xref: /onnv-gate/usr/src/uts/intel/io/pciex/pcieb_x86.c (revision 11596:e9010337bcd3)
110187SKrishna.Elango@Sun.COM /*
210187SKrishna.Elango@Sun.COM  * CDDL HEADER START
310187SKrishna.Elango@Sun.COM  *
410187SKrishna.Elango@Sun.COM  * The contents of this file are subject to the terms of the
510187SKrishna.Elango@Sun.COM  * Common Development and Distribution License (the "License").
610187SKrishna.Elango@Sun.COM  * You may not use this file except in compliance with the License.
710187SKrishna.Elango@Sun.COM  *
810187SKrishna.Elango@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910187SKrishna.Elango@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010187SKrishna.Elango@Sun.COM  * See the License for the specific language governing permissions
1110187SKrishna.Elango@Sun.COM  * and limitations under the License.
1210187SKrishna.Elango@Sun.COM  *
1310187SKrishna.Elango@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410187SKrishna.Elango@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510187SKrishna.Elango@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610187SKrishna.Elango@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710187SKrishna.Elango@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810187SKrishna.Elango@Sun.COM  *
1910187SKrishna.Elango@Sun.COM  * CDDL HEADER END
2010187SKrishna.Elango@Sun.COM  */
2110187SKrishna.Elango@Sun.COM /*
22*11596SJason.Beloro@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2310187SKrishna.Elango@Sun.COM  * Use is subject to license terms.
2410187SKrishna.Elango@Sun.COM  */
2510187SKrishna.Elango@Sun.COM 
2610187SKrishna.Elango@Sun.COM /* x86 specific code used by the pcieb driver */
2710187SKrishna.Elango@Sun.COM 
2810187SKrishna.Elango@Sun.COM #include <sys/types.h>
2910187SKrishna.Elango@Sun.COM #include <sys/ddi.h>
3010187SKrishna.Elango@Sun.COM #include <sys/kmem.h>
3110187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h>
3210187SKrishna.Elango@Sun.COM #include <sys/sunddi.h>
3310187SKrishna.Elango@Sun.COM #include <sys/sunndi.h>
3410187SKrishna.Elango@Sun.COM #include <sys/pcie.h>
3510187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h>
3610187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h>
3710187SKrishna.Elango@Sun.COM #include <sys/pcie_acpi.h>
3810187SKrishna.Elango@Sun.COM #include <sys/hotplug/hpctrl.h>
3910187SKrishna.Elango@Sun.COM #include <io/pciex/pcieb.h>
4010187SKrishna.Elango@Sun.COM #include <io/pciex/pcie_nb5000.h>
4110187SKrishna.Elango@Sun.COM 
4210187SKrishna.Elango@Sun.COM /* Flag to turn off intel error handling workarounds */
4310187SKrishna.Elango@Sun.COM int pcieb_intel_workaround_disable = 0;
4410187SKrishna.Elango@Sun.COM 
4510187SKrishna.Elango@Sun.COM void
pcieb_peekpoke_cb(dev_info_t * dip,ddi_fm_error_t * derr)4610187SKrishna.Elango@Sun.COM pcieb_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) {
47*11596SJason.Beloro@Sun.COM 	pf_eh_enter(PCIE_DIP2BUS(dip));
4810187SKrishna.Elango@Sun.COM 	(void) pf_scan_fabric(dip, derr, NULL);
49*11596SJason.Beloro@Sun.COM 	pf_eh_exit(PCIE_DIP2BUS(dip));
5010187SKrishna.Elango@Sun.COM }
5110187SKrishna.Elango@Sun.COM 
5211236SStephen.Hanson@Sun.COM void
pcieb_set_prot_scan(dev_info_t * dip,ddi_acc_impl_t * hdlp)5311236SStephen.Hanson@Sun.COM pcieb_set_prot_scan(dev_info_t *dip, ddi_acc_impl_t *hdlp)
5411236SStephen.Hanson@Sun.COM {
5511236SStephen.Hanson@Sun.COM 	pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state,
5611236SStephen.Hanson@Sun.COM 	    ddi_get_instance(dip));
5711236SStephen.Hanson@Sun.COM 
5811236SStephen.Hanson@Sun.COM 	hdlp->ahi_err_mutexp = &pcieb->pcieb_err_mutex;
5911236SStephen.Hanson@Sun.COM 	hdlp->ahi_peekpoke_mutexp = &pcieb->pcieb_peek_poke_mutex;
6011236SStephen.Hanson@Sun.COM 	hdlp->ahi_scan_dip = dip;
6111236SStephen.Hanson@Sun.COM 	hdlp->ahi_scan = pcieb_peekpoke_cb;
6211236SStephen.Hanson@Sun.COM }
6311236SStephen.Hanson@Sun.COM 
6410187SKrishna.Elango@Sun.COM int
pcieb_plat_peekpoke(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)6510187SKrishna.Elango@Sun.COM pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
6610187SKrishna.Elango@Sun.COM     void *arg, void *result)
6710187SKrishna.Elango@Sun.COM {
6810187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state,
6910187SKrishna.Elango@Sun.COM 	    ddi_get_instance(dip));
7010187SKrishna.Elango@Sun.COM 
7110187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_RP(PCIE_DIP2BUS(dip)))
7210187SKrishna.Elango@Sun.COM 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
7310187SKrishna.Elango@Sun.COM 
7410187SKrishna.Elango@Sun.COM 	return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
7510187SKrishna.Elango@Sun.COM 	    ddi_ctlops, &pcieb->pcieb_err_mutex,
7610187SKrishna.Elango@Sun.COM 	    &pcieb->pcieb_peek_poke_mutex,
7710187SKrishna.Elango@Sun.COM 	    pcieb_peekpoke_cb));
7810187SKrishna.Elango@Sun.COM }
7910187SKrishna.Elango@Sun.COM 
8010187SKrishna.Elango@Sun.COM /* x86 specific workarounds needed at the end of pcieb attach */
8110187SKrishna.Elango@Sun.COM void
pcieb_plat_attach_workaround(dev_info_t * dip)8210187SKrishna.Elango@Sun.COM pcieb_plat_attach_workaround(dev_info_t *dip)
8310187SKrishna.Elango@Sun.COM {
8410187SKrishna.Elango@Sun.COM 	/* Must apply workaround only after all initialization is done */
8510187SKrishna.Elango@Sun.COM 	pcieb_intel_error_workaround(dip);
8610187SKrishna.Elango@Sun.COM 	pcieb_intel_mps_workaround(dip);
8710187SKrishna.Elango@Sun.COM 
8810187SKrishna.Elango@Sun.COM }
8910187SKrishna.Elango@Sun.COM 
9010187SKrishna.Elango@Sun.COM /* Workarounds to enable error handling on certain Intel chipsets */
9110187SKrishna.Elango@Sun.COM void
pcieb_intel_error_workaround(dev_info_t * dip)9210187SKrishna.Elango@Sun.COM pcieb_intel_error_workaround(dev_info_t *dip)
9310187SKrishna.Elango@Sun.COM {
9410187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state,
9510187SKrishna.Elango@Sun.COM 	    ddi_get_instance(dip));
9610187SKrishna.Elango@Sun.COM 
9710187SKrishna.Elango@Sun.COM 	pcieb_intel_serr_workaround(dip, pcieb->pcieb_no_aer_msi);
9810187SKrishna.Elango@Sun.COM 	pcieb_intel_rber_workaround(dip);
9910187SKrishna.Elango@Sun.COM 	pcieb_intel_sw_workaround(dip);
10010187SKrishna.Elango@Sun.COM }
10110187SKrishna.Elango@Sun.COM 
10210187SKrishna.Elango@Sun.COM int
pcieb_plat_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)10310187SKrishna.Elango@Sun.COM pcieb_plat_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
10410187SKrishna.Elango@Sun.COM     ddi_intr_handle_impl_t *hdlp, void *result)
10510187SKrishna.Elango@Sun.COM {
10610187SKrishna.Elango@Sun.COM 	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
10710187SKrishna.Elango@Sun.COM }
10810187SKrishna.Elango@Sun.COM 
10910187SKrishna.Elango@Sun.COM /* shpc is not supported on x86 */
11010187SKrishna.Elango@Sun.COM /*ARGSUSED*/
11110187SKrishna.Elango@Sun.COM int
pcieb_plat_pcishpc_probe(dev_info_t * dip,ddi_acc_handle_t config_handle)11210187SKrishna.Elango@Sun.COM pcieb_plat_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
11310187SKrishna.Elango@Sun.COM {
11410187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
11510187SKrishna.Elango@Sun.COM }
11610187SKrishna.Elango@Sun.COM 
11710187SKrishna.Elango@Sun.COM /*
11810187SKrishna.Elango@Sun.COM  * Dummy functions to get around the fact that there's no shpc module on x86
11910187SKrishna.Elango@Sun.COM  * today
12010187SKrishna.Elango@Sun.COM  */
12110187SKrishna.Elango@Sun.COM /*ARGSUSED*/
12210187SKrishna.Elango@Sun.COM int
pcishpc_init(dev_info_t * dip)12310187SKrishna.Elango@Sun.COM pcishpc_init(dev_info_t *dip)
12410187SKrishna.Elango@Sun.COM {
12510187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
12610187SKrishna.Elango@Sun.COM }
12710187SKrishna.Elango@Sun.COM 
12810187SKrishna.Elango@Sun.COM /*ARGSUSED*/
12910187SKrishna.Elango@Sun.COM int
pcishpc_uninit(dev_info_t * dip)13010187SKrishna.Elango@Sun.COM pcishpc_uninit(dev_info_t *dip)
13110187SKrishna.Elango@Sun.COM {
13210187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
13310187SKrishna.Elango@Sun.COM }
13410187SKrishna.Elango@Sun.COM 
13510187SKrishna.Elango@Sun.COM /*ARGSUSED*/
13610187SKrishna.Elango@Sun.COM int
pcishpc_intr(dev_info_t * dip)13710187SKrishna.Elango@Sun.COM pcishpc_intr(dev_info_t *dip)
13810187SKrishna.Elango@Sun.COM {
13910187SKrishna.Elango@Sun.COM 	return (DDI_INTR_UNCLAIMED);
14010187SKrishna.Elango@Sun.COM }
14110187SKrishna.Elango@Sun.COM 
14210187SKrishna.Elango@Sun.COM /*ARGSUSED*/
14310187SKrishna.Elango@Sun.COM boolean_t
pcieb_plat_pwr_disable(dev_info_t * dip)14410187SKrishna.Elango@Sun.COM pcieb_plat_pwr_disable(dev_info_t *dip)
14510187SKrishna.Elango@Sun.COM {
14610187SKrishna.Elango@Sun.COM 	/* Always disable on x86 */
14710187SKrishna.Elango@Sun.COM 	return (B_TRUE);
14810187SKrishna.Elango@Sun.COM }
14910187SKrishna.Elango@Sun.COM 
15010187SKrishna.Elango@Sun.COM boolean_t
pcieb_plat_msi_supported(dev_info_t * dip)15110187SKrishna.Elango@Sun.COM pcieb_plat_msi_supported(dev_info_t *dip)
15210187SKrishna.Elango@Sun.COM {
15310187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
15410187SKrishna.Elango@Sun.COM 	uint16_t vendor_id, device_id;
15510187SKrishna.Elango@Sun.COM 	vendor_id = bus_p->bus_dev_ven_id & 0xFFFF;
15610187SKrishna.Elango@Sun.COM 	device_id = bus_p->bus_dev_ven_id >> 16;
15710187SKrishna.Elango@Sun.COM 
15810187SKrishna.Elango@Sun.COM 	/*
15910187SKrishna.Elango@Sun.COM 	 * Intel ESB2 switches have a errata which prevents using MSIs
16010187SKrishna.Elango@Sun.COM 	 * for hotplug.
16110187SKrishna.Elango@Sun.COM 	 */
16210187SKrishna.Elango@Sun.COM 	return (((vendor_id == INTEL_VENDOR_ID) &&
16310187SKrishna.Elango@Sun.COM 	    INTEL_ESB2_SW_PCIE_DEV_ID(device_id)) ? B_FALSE : B_TRUE);
16410187SKrishna.Elango@Sun.COM }
16510187SKrishna.Elango@Sun.COM 
16610187SKrishna.Elango@Sun.COM void
pcieb_plat_intr_attach(pcieb_devstate_t * pcieb)16710187SKrishna.Elango@Sun.COM pcieb_plat_intr_attach(pcieb_devstate_t *pcieb)
16810187SKrishna.Elango@Sun.COM {
16910187SKrishna.Elango@Sun.COM 	/*
17010187SKrishna.Elango@Sun.COM 	 *  _OSC initialization needs to be done before interrupts are
17110187SKrishna.Elango@Sun.COM 	 *  initialized.
17210187SKrishna.Elango@Sun.COM 	 */
17310187SKrishna.Elango@Sun.COM 	pcieb_init_osc(pcieb->pcieb_dip);
17410187SKrishna.Elango@Sun.COM }
17510187SKrishna.Elango@Sun.COM 
17610187SKrishna.Elango@Sun.COM void
pcieb_plat_initchild(dev_info_t * child)17710187SKrishna.Elango@Sun.COM pcieb_plat_initchild(dev_info_t *child)
17810187SKrishna.Elango@Sun.COM {
17910187SKrishna.Elango@Sun.COM 	struct ddi_parent_private_data *pdptr;
18010187SKrishna.Elango@Sun.COM 	if (ddi_getprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, "interrupts",
18110187SKrishna.Elango@Sun.COM 	    -1) != -1) {
18210187SKrishna.Elango@Sun.COM 		pdptr = kmem_zalloc((sizeof (struct ddi_parent_private_data) +
18310187SKrishna.Elango@Sun.COM 		    sizeof (struct intrspec)), KM_SLEEP);
18410187SKrishna.Elango@Sun.COM 		pdptr->par_intr = (struct intrspec *)(pdptr + 1);
18510187SKrishna.Elango@Sun.COM 		pdptr->par_nintr = 1;
18610187SKrishna.Elango@Sun.COM 		ddi_set_parent_data(child, pdptr);
18710187SKrishna.Elango@Sun.COM 	} else
18810187SKrishna.Elango@Sun.COM 		ddi_set_parent_data(child, NULL);
18910187SKrishna.Elango@Sun.COM }
19010187SKrishna.Elango@Sun.COM 
19110187SKrishna.Elango@Sun.COM void
pcieb_plat_uninitchild(dev_info_t * child)19210187SKrishna.Elango@Sun.COM pcieb_plat_uninitchild(dev_info_t *child)
19310187SKrishna.Elango@Sun.COM {
19410187SKrishna.Elango@Sun.COM 	struct ddi_parent_private_data	*pdptr;
19510187SKrishna.Elango@Sun.COM 
19610187SKrishna.Elango@Sun.COM 	if ((pdptr = ddi_get_parent_data(child)) != NULL)
19710187SKrishna.Elango@Sun.COM 		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
19810187SKrishna.Elango@Sun.COM 
19910187SKrishna.Elango@Sun.COM 	ddi_set_parent_data(child, NULL);
20010187SKrishna.Elango@Sun.COM }
20110187SKrishna.Elango@Sun.COM 
20210187SKrishna.Elango@Sun.COM /* _OSC related */
20310187SKrishna.Elango@Sun.COM void
pcieb_init_osc(dev_info_t * devi)20410187SKrishna.Elango@Sun.COM pcieb_init_osc(dev_info_t *devi) {
20510187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2UPBUS(devi);
20610187SKrishna.Elango@Sun.COM 	uint32_t	osc_flags = OSC_CONTROL_PCIE_ADV_ERR;
20710187SKrishna.Elango@Sun.COM 
20810187SKrishna.Elango@Sun.COM 	/*
20910187SKrishna.Elango@Sun.COM 	 * Call _OSC method for 2 reasons:
21010187SKrishna.Elango@Sun.COM 	 * 1. Hotplug: To determine if it is native or ACPI mode.
21110187SKrishna.Elango@Sun.COM 	 *
21210187SKrishna.Elango@Sun.COM 	 * 2. Error handling: Inform firmware that OS can support AER error
21310187SKrishna.Elango@Sun.COM 	 * handling. Currently we don't care for what the BIOS response was
21410187SKrishna.Elango@Sun.COM 	 * and instead setup interrupts for error handling as if it were
21510187SKrishna.Elango@Sun.COM 	 * supported.
21610187SKrishna.Elango@Sun.COM 	 *
21710187SKrishna.Elango@Sun.COM 	 * For hotpluggable slots the _OSC method has already been called as
21810187SKrishna.Elango@Sun.COM 	 * part of the hotplug initialization.
21910187SKrishna.Elango@Sun.COM 	 * For non-hotpluggable slots we need to call the _OSC method only for
22010187SKrishna.Elango@Sun.COM 	 * Root Ports (for AER support).
22110187SKrishna.Elango@Sun.COM 	 */
22210187SKrishna.Elango@Sun.COM 	if (!pcie_is_osc(devi) && PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p))
22310187SKrishna.Elango@Sun.COM 		(void) pcie_acpi_osc(devi, &osc_flags);
22410187SKrishna.Elango@Sun.COM }
22510187SKrishna.Elango@Sun.COM 
22610187SKrishna.Elango@Sun.COM /*
22710187SKrishna.Elango@Sun.COM  * Intel chip specific workarounds. Right now they're limited to the 5000, 5400
22810187SKrishna.Elango@Sun.COM  * and 7300 series chipsets.
22910187SKrishna.Elango@Sun.COM  */
23010187SKrishna.Elango@Sun.COM typedef struct x86_error_reg {
23110187SKrishna.Elango@Sun.COM 	uint32_t	offset;
23210187SKrishna.Elango@Sun.COM 	uint_t		size;
23310187SKrishna.Elango@Sun.COM 	uint32_t	mask;
23410187SKrishna.Elango@Sun.COM 	uint32_t	value1;	/* Value for MSI case */
23510187SKrishna.Elango@Sun.COM 	uint32_t	value2; /* Value for machinecheck case */
23610187SKrishna.Elango@Sun.COM } x86_error_reg_t;
23710187SKrishna.Elango@Sun.COM 
23810187SKrishna.Elango@Sun.COM typedef struct x86_error_tbl {
23910187SKrishna.Elango@Sun.COM 	uint16_t	vendor_id;
24010187SKrishna.Elango@Sun.COM 	uint16_t	device_id_low;
24110187SKrishna.Elango@Sun.COM 	uint16_t	device_id_high;
24210187SKrishna.Elango@Sun.COM 	uint8_t		rev_id_low;
24310187SKrishna.Elango@Sun.COM 	uint8_t		rev_id_high;
24410187SKrishna.Elango@Sun.COM 	x86_error_reg_t	*error_regs;
24510187SKrishna.Elango@Sun.COM 	int		error_regs_len;
24610187SKrishna.Elango@Sun.COM } x86_error_tbl_t;
24710187SKrishna.Elango@Sun.COM 
24810187SKrishna.Elango@Sun.COM /*
24910187SKrishna.Elango@Sun.COM  * Chipset and device specific settings that are required for error handling
25010187SKrishna.Elango@Sun.COM  * (reporting, fowarding, and response at the RC) beyond the standard
25110187SKrishna.Elango@Sun.COM  * registers in the PCIE and AER caps.
25210187SKrishna.Elango@Sun.COM  *
25310187SKrishna.Elango@Sun.COM  * The Northbridge Root Port settings also apply to the ESI port.  The ESI
25410187SKrishna.Elango@Sun.COM  * port is a special leaf device but functions like a root port connected
25510187SKrishna.Elango@Sun.COM  * to the Southbridge and receives all the onboard Southbridge errors
25610187SKrishna.Elango@Sun.COM  * including those from Southbridge Root Ports.  However, this does not
25710187SKrishna.Elango@Sun.COM  * include the Southbridge Switch Ports which act like normal switch ports
25810187SKrishna.Elango@Sun.COM  * and is connected to the Northbridge through a separate link.
25910187SKrishna.Elango@Sun.COM  *
26010187SKrishna.Elango@Sun.COM  * PCIE errors from the ESB2 Southbridge RPs are simply fowarded to the ESI
26110187SKrishna.Elango@Sun.COM  * port on the Northbridge.
26210187SKrishna.Elango@Sun.COM  *
26310187SKrishna.Elango@Sun.COM  * If MSIs don't work we want UEs (Fatal and Non-Fatal) to panic the system,
26410187SKrishna.Elango@Sun.COM  * except for URs.  We do this by having the Root Ports respond with a System
26510187SKrishna.Elango@Sun.COM  * Error and having that trigger a Machine Check (MCE).
26610187SKrishna.Elango@Sun.COM  */
26710187SKrishna.Elango@Sun.COM 
26810187SKrishna.Elango@Sun.COM /*
26910187SKrishna.Elango@Sun.COM  * 7300 Northbridge Root Ports
27010187SKrishna.Elango@Sun.COM  */
27110187SKrishna.Elango@Sun.COM static x86_error_reg_t intel_7300_rp_regs[] = {
27210187SKrishna.Elango@Sun.COM 	/* Command Register - Enable SERR */
27310187SKrishna.Elango@Sun.COM 	{0x4,   16, 0xFFFF,	0x0,	PCI_COMM_SERR_ENABLE},
27410187SKrishna.Elango@Sun.COM 
27510187SKrishna.Elango@Sun.COM 	/* Root Control Register - SERR on NFE/FE */
27610187SKrishna.Elango@Sun.COM 	{0x88,  16, 0x0,	0x0,	PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
27710187SKrishna.Elango@Sun.COM 					PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
27810187SKrishna.Elango@Sun.COM 
27910187SKrishna.Elango@Sun.COM 	/* AER UE Mask - Mask UR */
28010187SKrishna.Elango@Sun.COM 	{0x108, 32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
28110187SKrishna.Elango@Sun.COM 
28210187SKrishna.Elango@Sun.COM 	/* PEXCTRL[21] check for certain malformed TLP types and MSI enable */
28310187SKrishna.Elango@Sun.COM 	{0x48,	32, 0xFFFFFFFF, 0xC0200000, 0x200000},
28410187SKrishna.Elango@Sun.COM 	/* PEXCTRL3[7]. MSI RAS error enable */
28510187SKrishna.Elango@Sun.COM 	{0x4D,	32, 0xFFFFFFFF, 0x1, 0x0},
28610187SKrishna.Elango@Sun.COM 
28710187SKrishna.Elango@Sun.COM 	/* PEX_ERR_DOCMD[7:0] */
28810187SKrishna.Elango@Sun.COM 	{0x144,	8,  0x0,	0x0,	0xF0},
28910187SKrishna.Elango@Sun.COM 
29010187SKrishna.Elango@Sun.COM 	/* EMASK_UNCOR_PEX[21:0] UE mask */
29110187SKrishna.Elango@Sun.COM 	{0x148,	32, 0x0, PCIE_AER_UCE_UR, PCIE_AER_UCE_UR},
29210187SKrishna.Elango@Sun.COM 
29310187SKrishna.Elango@Sun.COM 	/* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
29410187SKrishna.Elango@Sun.COM 	{0x150,	8,  0x0,	0x0,	0x1},
29510187SKrishna.Elango@Sun.COM };
29610187SKrishna.Elango@Sun.COM #define	INTEL_7300_RP_REGS_LEN \
29710187SKrishna.Elango@Sun.COM 	(sizeof (intel_7300_rp_regs) / sizeof (x86_error_reg_t))
29810187SKrishna.Elango@Sun.COM 
29910187SKrishna.Elango@Sun.COM /*
30010187SKrishna.Elango@Sun.COM  * 5000 Northbridge Root Ports
30110187SKrishna.Elango@Sun.COM  */
30210187SKrishna.Elango@Sun.COM static x86_error_reg_t intel_5000_rp_regs[] = {
30310187SKrishna.Elango@Sun.COM 	/* Command Register - Enable SERR */
30410187SKrishna.Elango@Sun.COM 	{0x4,   16, 0xFFFF,	PCI_COMM_SERR_ENABLE,	PCI_COMM_SERR_ENABLE},
30510187SKrishna.Elango@Sun.COM 
30610187SKrishna.Elango@Sun.COM 	/* Root Control Register - SERR on NFE/FE/CE */
30710187SKrishna.Elango@Sun.COM 	{0x88,  16, 0x0,	PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
30810187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
30910187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
31010187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
31110187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
31210187SKrishna.Elango@Sun.COM 
31310187SKrishna.Elango@Sun.COM 	/* AER UE Mask - Mask UR */
31410187SKrishna.Elango@Sun.COM 	{0x108, 32, 0x0,	PCIE_AER_UCE_UR,	PCIE_AER_UCE_UR},
31510187SKrishna.Elango@Sun.COM 
31610187SKrishna.Elango@Sun.COM 	/* PEXCTRL[21] check for certain malformed TLP type */
31710187SKrishna.Elango@Sun.COM 	{0x48,	32, 0xFFFFFFFF, 0xC0200000, 0x200000},
31810187SKrishna.Elango@Sun.COM 	/* PEXCTRL3[7]. MSI RAS error enable. */
31910187SKrishna.Elango@Sun.COM 	{0x4D,	32, 0xFFFFFFFF,	0x1,	0x0},
32010187SKrishna.Elango@Sun.COM 
32110187SKrishna.Elango@Sun.COM 	/* PEX_ERR_DOCMD[7:0] */
32210187SKrishna.Elango@Sun.COM 	{0x144,	8,  0x0,	0x0,	0xF0},
32310187SKrishna.Elango@Sun.COM 
32410187SKrishna.Elango@Sun.COM 	/* EMASK_UNCOR_PEX[21:0] UE mask */
32510187SKrishna.Elango@Sun.COM 	{0x148,	32, 0x0, 	PCIE_AER_UCE_UR,	PCIE_AER_UCE_UR},
32610187SKrishna.Elango@Sun.COM 
32710187SKrishna.Elango@Sun.COM 	/* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
32810187SKrishna.Elango@Sun.COM 	{0x150,	8,  0x0, 	0x0,	0x1},
32910187SKrishna.Elango@Sun.COM };
33010187SKrishna.Elango@Sun.COM #define	INTEL_5000_RP_REGS_LEN \
33110187SKrishna.Elango@Sun.COM 	(sizeof (intel_5000_rp_regs) / sizeof (x86_error_reg_t))
33210187SKrishna.Elango@Sun.COM 
33310187SKrishna.Elango@Sun.COM /*
33410187SKrishna.Elango@Sun.COM  * 5400 Northbridge Root Ports.
33510187SKrishna.Elango@Sun.COM  */
33610187SKrishna.Elango@Sun.COM static x86_error_reg_t intel_5400_rp_regs[] = {
33710187SKrishna.Elango@Sun.COM 	/* Command Register - Enable SERR */
33810187SKrishna.Elango@Sun.COM 	{0x4,   16, 0xFFFF,	PCI_COMM_SERR_ENABLE, PCI_COMM_SERR_ENABLE},
33910187SKrishna.Elango@Sun.COM 
34010187SKrishna.Elango@Sun.COM 	/* Root Control Register - SERR on NFE/FE */
34110187SKrishna.Elango@Sun.COM 	{0x88,  16, 0x0, PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
34210187SKrishna.Elango@Sun.COM 			    PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
34310187SKrishna.Elango@Sun.COM 			    PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
34410187SKrishna.Elango@Sun.COM 			    PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
34510187SKrishna.Elango@Sun.COM 			    PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
34610187SKrishna.Elango@Sun.COM 
34710187SKrishna.Elango@Sun.COM 	/* AER UE Mask - Mask UR */
34810187SKrishna.Elango@Sun.COM 	{0x108, 32, 0x0,	PCIE_AER_UCE_UR,	PCIE_AER_UCE_UR},
34910187SKrishna.Elango@Sun.COM 
35010187SKrishna.Elango@Sun.COM 	/* PEXCTRL[21] check for certain malformed TLP types */
35110187SKrishna.Elango@Sun.COM 	{0x48,	32, 0xFFFFFFFF,	0xC0200000, 0x200000},
35210187SKrishna.Elango@Sun.COM 	/* PEXCTRL3. MSI RAS error enable. */
35310187SKrishna.Elango@Sun.COM 	{0x4E,	8, 0x0,	0x1,	0x0},
35410187SKrishna.Elango@Sun.COM 
35510187SKrishna.Elango@Sun.COM 	/* PEX_ERR_DOCMD[11:0] */
35610187SKrishna.Elango@Sun.COM 	{0x144,	16,  0x0, 	0x0,	0xFF0},
35710187SKrishna.Elango@Sun.COM 
35810187SKrishna.Elango@Sun.COM 	/* PEX_ERR_PIN_MASK[4:0] do not mask ERR[2:0] pins used by DOCMD */
35910187SKrishna.Elango@Sun.COM 	{0x146,	16,  0x0,	0x10,	0x10},
36010187SKrishna.Elango@Sun.COM 
36110187SKrishna.Elango@Sun.COM 	/* EMASK_UNCOR_PEX[21:0] UE mask */
36210187SKrishna.Elango@Sun.COM 	{0x148,	32, 0x0, 	PCIE_AER_UCE_UR,	PCIE_AER_UCE_UR},
36310187SKrishna.Elango@Sun.COM 
36410187SKrishna.Elango@Sun.COM 	/* EMASK_RP_PEX[2:0] FE, UE, CE message detect mask */
36510187SKrishna.Elango@Sun.COM 	{0x150,	8,  0x0, 	0x0,	0x1},
36610187SKrishna.Elango@Sun.COM };
36710187SKrishna.Elango@Sun.COM #define	INTEL_5400_RP_REGS_LEN \
36810187SKrishna.Elango@Sun.COM 	(sizeof (intel_5400_rp_regs) / sizeof (x86_error_reg_t))
36910187SKrishna.Elango@Sun.COM 
37010187SKrishna.Elango@Sun.COM 
37110187SKrishna.Elango@Sun.COM /*
37210187SKrishna.Elango@Sun.COM  * ESB2 Southbridge Root Ports
37310187SKrishna.Elango@Sun.COM  */
37410187SKrishna.Elango@Sun.COM static x86_error_reg_t intel_esb2_rp_regs[] = {
37510187SKrishna.Elango@Sun.COM 	/* Command Register - Enable SERR */
37610187SKrishna.Elango@Sun.COM 	{0x4,   16, 0xFFFF,	PCI_COMM_SERR_ENABLE,	PCI_COMM_SERR_ENABLE},
37710187SKrishna.Elango@Sun.COM 
37810187SKrishna.Elango@Sun.COM 	/* Root Control Register - SERR on NFE/FE */
37910187SKrishna.Elango@Sun.COM 	{0x5c,  16, 0x0,	PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
38010187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_FE_EN |
38110187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_CE_EN,
38210187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
38310187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_FE_EN},
38410187SKrishna.Elango@Sun.COM 
38510187SKrishna.Elango@Sun.COM 	/* UEM[20:0] UE mask (write-once) */
38610187SKrishna.Elango@Sun.COM 	{0x148, 32, 0x0,	PCIE_AER_UCE_UR,	PCIE_AER_UCE_UR},
38710187SKrishna.Elango@Sun.COM };
38810187SKrishna.Elango@Sun.COM #define	INTEL_ESB2_RP_REGS_LEN \
38910187SKrishna.Elango@Sun.COM 	(sizeof (intel_esb2_rp_regs) / sizeof (x86_error_reg_t))
39010187SKrishna.Elango@Sun.COM 
39110187SKrishna.Elango@Sun.COM 
39210187SKrishna.Elango@Sun.COM /*
39310187SKrishna.Elango@Sun.COM  * ESB2 Southbridge Switch Ports
39410187SKrishna.Elango@Sun.COM  */
39510187SKrishna.Elango@Sun.COM static x86_error_reg_t intel_esb2_sw_regs[] = {
39610187SKrishna.Elango@Sun.COM 	/* Command Register - Enable SERR */
39710187SKrishna.Elango@Sun.COM 	{0x4,   16, 0xFFFF,	PCI_COMM_SERR_ENABLE,	PCI_COMM_SERR_ENABLE},
39810187SKrishna.Elango@Sun.COM 
39910187SKrishna.Elango@Sun.COM 	/* AER UE Mask - Mask UR */
40010187SKrishna.Elango@Sun.COM 	{0x108, 32, 0x0,	PCIE_AER_UCE_UR,	PCIE_AER_UCE_UR},
40110187SKrishna.Elango@Sun.COM };
40210187SKrishna.Elango@Sun.COM #define	INTEL_ESB2_SW_REGS_LEN \
40310187SKrishna.Elango@Sun.COM 	(sizeof (intel_esb2_sw_regs) / sizeof (x86_error_reg_t))
40410187SKrishna.Elango@Sun.COM 
40510187SKrishna.Elango@Sun.COM 
40610187SKrishna.Elango@Sun.COM x86_error_tbl_t x86_error_init_tbl[] = {
40710187SKrishna.Elango@Sun.COM 	/* Intel 7300: 3600 = ESI, 3604-360A = NB root ports */
40810187SKrishna.Elango@Sun.COM 	{0x8086, 0x3600, 0x3600, 0x0, 0xFF,
40910187SKrishna.Elango@Sun.COM 		intel_7300_rp_regs, INTEL_7300_RP_REGS_LEN},
41010187SKrishna.Elango@Sun.COM 	{0x8086, 0x3604, 0x360A, 0x0, 0xFF,
41110187SKrishna.Elango@Sun.COM 		intel_7300_rp_regs, INTEL_7300_RP_REGS_LEN},
41210187SKrishna.Elango@Sun.COM 
41310187SKrishna.Elango@Sun.COM 	/* Intel 5000: 25C0, 25D0, 25D4, 25D8 = ESI */
41410187SKrishna.Elango@Sun.COM 	{0x8086, 0x25C0, 0x25C0, 0x0, 0xFF,
41510187SKrishna.Elango@Sun.COM 		intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
41610187SKrishna.Elango@Sun.COM 	{0x8086, 0x25D0, 0x25D0, 0x0, 0xFF,
41710187SKrishna.Elango@Sun.COM 		intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
41810187SKrishna.Elango@Sun.COM 	{0x8086, 0x25D4, 0x25D4, 0x0, 0xFF,
41910187SKrishna.Elango@Sun.COM 		intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
42010187SKrishna.Elango@Sun.COM 	{0x8086, 0x25D8, 0x25D8, 0x0, 0xFF,
42110187SKrishna.Elango@Sun.COM 		intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
42210187SKrishna.Elango@Sun.COM 
42310187SKrishna.Elango@Sun.COM 	/* Intel 5000: 25E2-25E7 and 25F7-25FA = NB root ports */
42410187SKrishna.Elango@Sun.COM 	{0x8086, 0x25E2, 0x25E7, 0x0, 0xFF,
42510187SKrishna.Elango@Sun.COM 		intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
42610187SKrishna.Elango@Sun.COM 	{0x8086, 0x25F7, 0x25FA, 0x0, 0xFF,
42710187SKrishna.Elango@Sun.COM 		intel_5000_rp_regs, INTEL_5000_RP_REGS_LEN},
42810187SKrishna.Elango@Sun.COM 
42910187SKrishna.Elango@Sun.COM 	/* Intel 5400: 4000-4001, 4003 = ESI and 4021-4029 = NB root ports */
43010187SKrishna.Elango@Sun.COM 	{0x8086, 0x4000, 0x4001, 0x0, 0xFF,
43110187SKrishna.Elango@Sun.COM 		intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
43210187SKrishna.Elango@Sun.COM 	{0x8086, 0x4003, 0x4003, 0x0, 0xFF,
43310187SKrishna.Elango@Sun.COM 		intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
43410187SKrishna.Elango@Sun.COM 	{0x8086, 0x4021, 0x4029, 0x0, 0xFF,
43510187SKrishna.Elango@Sun.COM 		intel_5400_rp_regs, INTEL_5400_RP_REGS_LEN},
43610187SKrishna.Elango@Sun.COM 
43710187SKrishna.Elango@Sun.COM 	/* Intel 631xESB/632xESB aka ESB2: 2690-2697 = SB root ports */
43810187SKrishna.Elango@Sun.COM 	{0x8086, 0x2690, 0x2697, 0x0, 0xFF,
43910187SKrishna.Elango@Sun.COM 		intel_esb2_rp_regs, INTEL_ESB2_RP_REGS_LEN},
44010187SKrishna.Elango@Sun.COM 
44110187SKrishna.Elango@Sun.COM 	/* Intel Switches on esb2: 3500-3503, 3510-351B */
44210187SKrishna.Elango@Sun.COM 	{0x8086, 0x3500, 0x3503, 0x0, 0xFF,
44310187SKrishna.Elango@Sun.COM 		intel_esb2_sw_regs, INTEL_ESB2_SW_REGS_LEN},
44410187SKrishna.Elango@Sun.COM 	{0x8086, 0x3510, 0x351B, 0x0, 0xFF,
44510187SKrishna.Elango@Sun.COM 		intel_esb2_sw_regs, INTEL_ESB2_SW_REGS_LEN},
44610187SKrishna.Elango@Sun.COM 
44710187SKrishna.Elango@Sun.COM 	/* XXX Intel PCIe-PCIx on esb2: 350C */
44810187SKrishna.Elango@Sun.COM };
44910187SKrishna.Elango@Sun.COM static int x86_error_init_tbl_len =
45010187SKrishna.Elango@Sun.COM 	sizeof (x86_error_init_tbl) / sizeof (x86_error_tbl_t);
45110187SKrishna.Elango@Sun.COM 
45210187SKrishna.Elango@Sun.COM /*
45310187SKrishna.Elango@Sun.COM  * The main goal of this workaround is to set chipset specific settings if
45410187SKrishna.Elango@Sun.COM  * MSIs happen to be enabled on this device. Otherwise make the system
45510187SKrishna.Elango@Sun.COM  * Machine Check/Panic if an UE is detected in the fabric.
45610187SKrishna.Elango@Sun.COM  */
45710187SKrishna.Elango@Sun.COM void
pcieb_intel_serr_workaround(dev_info_t * dip,boolean_t mcheck)45810187SKrishna.Elango@Sun.COM pcieb_intel_serr_workaround(dev_info_t *dip, boolean_t mcheck)
45910187SKrishna.Elango@Sun.COM {
46010187SKrishna.Elango@Sun.COM 	uint16_t		vid, did;
46110187SKrishna.Elango@Sun.COM 	uint8_t			rid;
46210187SKrishna.Elango@Sun.COM 	int			i, j;
46310187SKrishna.Elango@Sun.COM 	x86_error_tbl_t		*tbl;
46410187SKrishna.Elango@Sun.COM 	x86_error_reg_t		*reg;
46510187SKrishna.Elango@Sun.COM 	pcie_bus_t		*bus_p = PCIE_DIP2UPBUS(dip);
46610187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t	cfg_hdl = bus_p->bus_cfg_hdl;
46710187SKrishna.Elango@Sun.COM 	uint16_t		bdf = bus_p->bus_bdf;
46810187SKrishna.Elango@Sun.COM 
46910187SKrishna.Elango@Sun.COM 	if (pcieb_intel_workaround_disable)
47010187SKrishna.Elango@Sun.COM 		return;
47110187SKrishna.Elango@Sun.COM 
47210187SKrishna.Elango@Sun.COM 	vid = bus_p->bus_dev_ven_id & 0xFFFF;
47310187SKrishna.Elango@Sun.COM 	did = bus_p->bus_dev_ven_id >> 16;
47410187SKrishna.Elango@Sun.COM 	rid = bus_p->bus_rev_id;
47510187SKrishna.Elango@Sun.COM 
47610187SKrishna.Elango@Sun.COM 	PCIEB_DEBUG(DBG_ATTACH, dip, "VID:0x%x DID:0x%x RID:0x%x bdf=0x%x\n",
47710187SKrishna.Elango@Sun.COM 	    vid, did, rid, bdf);
47810187SKrishna.Elango@Sun.COM 
47910187SKrishna.Elango@Sun.COM 	tbl = x86_error_init_tbl;
48010187SKrishna.Elango@Sun.COM 	for (i = 0; i < x86_error_init_tbl_len; i++, tbl++) {
48110187SKrishna.Elango@Sun.COM 		if (!((vid == tbl->vendor_id) &&
48210187SKrishna.Elango@Sun.COM 		    (did >= tbl->device_id_low) &&
48310187SKrishna.Elango@Sun.COM 		    (did <= tbl->device_id_high) &&
48410187SKrishna.Elango@Sun.COM 		    (rid >= tbl->rev_id_low) &&
48510187SKrishna.Elango@Sun.COM 		    (rid <= tbl->rev_id_high)))
48610187SKrishna.Elango@Sun.COM 			continue;
48710187SKrishna.Elango@Sun.COM 
48810187SKrishna.Elango@Sun.COM 		if (mcheck && PCIE_IS_RP(bus_p))
48910187SKrishna.Elango@Sun.COM 			pcie_set_rber_fatal(dip, B_TRUE);
49010187SKrishna.Elango@Sun.COM 
49110187SKrishna.Elango@Sun.COM 		reg = tbl->error_regs;
49210187SKrishna.Elango@Sun.COM 		for (j = 0; j < tbl->error_regs_len; j++, reg++) {
49310187SKrishna.Elango@Sun.COM 			uint32_t data = 0xDEADBEEF;
49410187SKrishna.Elango@Sun.COM 			uint32_t value = 0xDEADBEEF;
49510187SKrishna.Elango@Sun.COM 			switch (reg->size) {
49610187SKrishna.Elango@Sun.COM 			case 32:
49710187SKrishna.Elango@Sun.COM 				data = (uint32_t)pci_config_get32(cfg_hdl,
49810187SKrishna.Elango@Sun.COM 				    reg->offset);
49910187SKrishna.Elango@Sun.COM 				value = (mcheck ?
50010187SKrishna.Elango@Sun.COM 				    ((data & reg->mask) | reg->value2) :
50110187SKrishna.Elango@Sun.COM 				    ((data & reg->mask) | reg->value1));
50210187SKrishna.Elango@Sun.COM 				pci_config_put32(cfg_hdl, reg->offset, value);
50310187SKrishna.Elango@Sun.COM 				value = (uint32_t)pci_config_get32(cfg_hdl,
50410187SKrishna.Elango@Sun.COM 				    reg->offset);
50510187SKrishna.Elango@Sun.COM 				break;
50610187SKrishna.Elango@Sun.COM 			case 16:
50710187SKrishna.Elango@Sun.COM 				data = (uint32_t)pci_config_get16(cfg_hdl,
50810187SKrishna.Elango@Sun.COM 				    reg->offset);
50910187SKrishna.Elango@Sun.COM 				value = (mcheck ?
51010187SKrishna.Elango@Sun.COM 				    ((data & reg->mask) | reg->value2) :
51110187SKrishna.Elango@Sun.COM 				    ((data & reg->mask) | reg->value1));
51210187SKrishna.Elango@Sun.COM 				pci_config_put16(cfg_hdl, reg->offset,
51310187SKrishna.Elango@Sun.COM 				    (uint16_t)value);
51410187SKrishna.Elango@Sun.COM 				value = (uint32_t)pci_config_get16(cfg_hdl,
51510187SKrishna.Elango@Sun.COM 				    reg->offset);
51610187SKrishna.Elango@Sun.COM 				break;
51710187SKrishna.Elango@Sun.COM 			case 8:
51810187SKrishna.Elango@Sun.COM 				data = (uint32_t)pci_config_get8(cfg_hdl,
51910187SKrishna.Elango@Sun.COM 				    reg->offset);
52010187SKrishna.Elango@Sun.COM 				value = (mcheck ?
52110187SKrishna.Elango@Sun.COM 				    ((data & reg->mask) | reg->value2) :
52210187SKrishna.Elango@Sun.COM 				    ((data & reg->mask) | reg->value1));
52310187SKrishna.Elango@Sun.COM 				pci_config_put8(cfg_hdl, reg->offset,
52410187SKrishna.Elango@Sun.COM 				    (uint8_t)value);
52510187SKrishna.Elango@Sun.COM 				value = (uint32_t)pci_config_get8(cfg_hdl,
52610187SKrishna.Elango@Sun.COM 				    reg->offset);
52710187SKrishna.Elango@Sun.COM 				break;
52810187SKrishna.Elango@Sun.COM 			}
52910187SKrishna.Elango@Sun.COM 
53010187SKrishna.Elango@Sun.COM 			PCIEB_DEBUG(DBG_ATTACH, dip, "bdf:%x mcheck:%d size:%d "
53110187SKrishna.Elango@Sun.COM 			    "off:0x%x mask:0x%x value:0x%x + orig:0x%x -> "
53210187SKrishna.Elango@Sun.COM 			    "0x%x\n", bdf, mcheck, reg->size, reg->offset,
53310187SKrishna.Elango@Sun.COM 			    reg->mask, (mcheck ?  reg->value2 : reg->value1),
53410187SKrishna.Elango@Sun.COM 			    data, value);
53510187SKrishna.Elango@Sun.COM 		}
53610187SKrishna.Elango@Sun.COM 	}
53710187SKrishna.Elango@Sun.COM }
53810187SKrishna.Elango@Sun.COM 
53910187SKrishna.Elango@Sun.COM /*
54010187SKrishna.Elango@Sun.COM  * For devices that support Role Base Errors, make several UE have a FATAL
54110187SKrishna.Elango@Sun.COM  * severity.  That way a Fatal Message will be sent instead of a Correctable
54210187SKrishna.Elango@Sun.COM  * Message.  Without full FMA support, CEs will be ignored.
54310187SKrishna.Elango@Sun.COM  */
54410187SKrishna.Elango@Sun.COM uint32_t pcieb_rber_sev = (PCIE_AER_UCE_TRAINING | PCIE_AER_UCE_DLP |
54510187SKrishna.Elango@Sun.COM     PCIE_AER_UCE_SD | PCIE_AER_UCE_PTLP | PCIE_AER_UCE_FCP | PCIE_AER_UCE_TO |
54610187SKrishna.Elango@Sun.COM     PCIE_AER_UCE_CA | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP | PCIE_AER_UCE_ECRC);
54710187SKrishna.Elango@Sun.COM 
54810187SKrishna.Elango@Sun.COM void
pcieb_intel_rber_workaround(dev_info_t * dip)54910187SKrishna.Elango@Sun.COM pcieb_intel_rber_workaround(dev_info_t *dip)
55010187SKrishna.Elango@Sun.COM {
55110187SKrishna.Elango@Sun.COM 	uint32_t rber;
55210187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
55310187SKrishna.Elango@Sun.COM 
55410187SKrishna.Elango@Sun.COM 	if (pcieb_intel_workaround_disable)
55510187SKrishna.Elango@Sun.COM 		return;
55610187SKrishna.Elango@Sun.COM 
55710187SKrishna.Elango@Sun.COM 	/*
55810187SKrishna.Elango@Sun.COM 	 * Check Root Port's machinecheck setting to determine if this
55910187SKrishna.Elango@Sun.COM 	 * workaround is needed or not.
56010187SKrishna.Elango@Sun.COM 	 */
56110187SKrishna.Elango@Sun.COM 	if (!pcie_get_rber_fatal(dip))
56210187SKrishna.Elango@Sun.COM 		return;
56310187SKrishna.Elango@Sun.COM 
56410187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE(bus_p) || !PCIE_HAS_AER(bus_p))
56510187SKrishna.Elango@Sun.COM 		return;
56610187SKrishna.Elango@Sun.COM 
56710187SKrishna.Elango@Sun.COM 	rber = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) &
56810187SKrishna.Elango@Sun.COM 	    PCIE_DEVCAP_ROLE_BASED_ERR_REP;
56910187SKrishna.Elango@Sun.COM 	if (!rber)
57010187SKrishna.Elango@Sun.COM 		return;
57110187SKrishna.Elango@Sun.COM 
57210187SKrishna.Elango@Sun.COM 	PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, pcieb_rber_sev);
57310187SKrishna.Elango@Sun.COM }
57410187SKrishna.Elango@Sun.COM 
57510187SKrishna.Elango@Sun.COM /*
57610187SKrishna.Elango@Sun.COM  * The Intel 5000 Chipset has an errata that requires read completion
57710187SKrishna.Elango@Sun.COM  * coalescing to be disabled if the Max Payload Size is set to 256 bytes.
57810187SKrishna.Elango@Sun.COM  */
57910187SKrishna.Elango@Sun.COM void
pcieb_intel_mps_workaround(dev_info_t * dip)58010187SKrishna.Elango@Sun.COM pcieb_intel_mps_workaround(dev_info_t *dip)
58110187SKrishna.Elango@Sun.COM {
58210187SKrishna.Elango@Sun.COM 	uint16_t		vid, did;
58310187SKrishna.Elango@Sun.COM 	uint32_t		pexctrl;
58410187SKrishna.Elango@Sun.COM 	pcie_bus_t		*bus_p = PCIE_DIP2UPBUS(dip);
58510187SKrishna.Elango@Sun.COM 
58610187SKrishna.Elango@Sun.COM 	vid = bus_p->bus_dev_ven_id & 0xFFFF;
58710187SKrishna.Elango@Sun.COM 	did = bus_p->bus_dev_ven_id >> 16;
58810187SKrishna.Elango@Sun.COM 
58910476SAlan.Adamson@Sun.COM 	if ((vid == INTEL_VENDOR_ID) && (INTEL_NB5000_PCIE_DEV_ID(did) ||
59010476SAlan.Adamson@Sun.COM 	    INTEL_NB5100_PCIE_DEV_ID(did))) {
59110476SAlan.Adamson@Sun.COM 
59210187SKrishna.Elango@Sun.COM 		pexctrl = pci_config_get32(bus_p->bus_cfg_hdl,
59310187SKrishna.Elango@Sun.COM 		    INTEL_NB5000_PEXCTRL_OFFSET);
59410187SKrishna.Elango@Sun.COM 		/*
59510187SKrishna.Elango@Sun.COM 		 * Turn off coalescing (bit 10)
59610187SKrishna.Elango@Sun.COM 		 */
59710187SKrishna.Elango@Sun.COM 		pexctrl &= ~INTEL_NB5000_PEXCTRL_COALESCE_EN;
59810187SKrishna.Elango@Sun.COM 
59910187SKrishna.Elango@Sun.COM 		pci_config_put32(bus_p->bus_cfg_hdl,
60010187SKrishna.Elango@Sun.COM 		    INTEL_NB5000_PEXCTRL_OFFSET, pexctrl);
60110187SKrishna.Elango@Sun.COM 	}
60210187SKrishna.Elango@Sun.COM }
60310187SKrishna.Elango@Sun.COM 
60410187SKrishna.Elango@Sun.COM /*
60510187SKrishna.Elango@Sun.COM  * Workaround for certain switches regardless of platform
60610187SKrishna.Elango@Sun.COM  */
60710187SKrishna.Elango@Sun.COM void
pcieb_intel_sw_workaround(dev_info_t * dip)60810187SKrishna.Elango@Sun.COM pcieb_intel_sw_workaround(dev_info_t *dip)
60910187SKrishna.Elango@Sun.COM {
61010187SKrishna.Elango@Sun.COM 	uint16_t		vid, regw;
61110187SKrishna.Elango@Sun.COM 	pcie_bus_t		*bus_p = PCIE_DIP2UPBUS(dip);
61210187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t	cfg_hdl = bus_p->bus_cfg_hdl;
61310187SKrishna.Elango@Sun.COM 
61410187SKrishna.Elango@Sun.COM 	if (pcieb_intel_workaround_disable)
61510187SKrishna.Elango@Sun.COM 		return;
61610187SKrishna.Elango@Sun.COM 
61710187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_SW(PCIE_DIP2BUS(dip)))
61810187SKrishna.Elango@Sun.COM 		return;
61910187SKrishna.Elango@Sun.COM 
62010187SKrishna.Elango@Sun.COM 	vid = bus_p->bus_dev_ven_id & 0xFFFF;
62110187SKrishna.Elango@Sun.COM 	/*
62210187SKrishna.Elango@Sun.COM 	 * Intel and PLX switches require SERR in CMD reg to foward error
62310187SKrishna.Elango@Sun.COM 	 * messages, though this is not PCIE spec-compliant behavior.
62410187SKrishna.Elango@Sun.COM 	 * To prevent the switches themselves from reporting errors on URs
62510187SKrishna.Elango@Sun.COM 	 * when the CMD reg has SERR enabled (which is expected according to
62610187SKrishna.Elango@Sun.COM 	 * the PCIE spec) we rely on masking URs in the AER cap.
62710187SKrishna.Elango@Sun.COM 	 */
62810187SKrishna.Elango@Sun.COM 	if (vid == 0x8086 || vid == 0x10B5) {
62910187SKrishna.Elango@Sun.COM 		regw = pci_config_get16(cfg_hdl, PCI_CONF_COMM);
63010187SKrishna.Elango@Sun.COM 		pci_config_put16(cfg_hdl, PCI_CONF_COMM,
63110187SKrishna.Elango@Sun.COM 		    regw | PCI_COMM_SERR_ENABLE);
63210187SKrishna.Elango@Sun.COM 	}
63310187SKrishna.Elango@Sun.COM }
63410187SKrishna.Elango@Sun.COM 
63510187SKrishna.Elango@Sun.COM int
pcieb_plat_ctlops(dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg)63610187SKrishna.Elango@Sun.COM pcieb_plat_ctlops(dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg)
63710187SKrishna.Elango@Sun.COM {
63810187SKrishna.Elango@Sun.COM 	struct detachspec *ds;
63910187SKrishna.Elango@Sun.COM 	struct attachspec *as;
64010187SKrishna.Elango@Sun.COM 
64110187SKrishna.Elango@Sun.COM 	switch (ctlop) {
64210187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_DETACH:
64310187SKrishna.Elango@Sun.COM 		ds = (struct detachspec *)arg;
64410187SKrishna.Elango@Sun.COM 		switch (ds->when) {
64510187SKrishna.Elango@Sun.COM 		case DDI_POST:
64610187SKrishna.Elango@Sun.COM 			if (ds->cmd == DDI_SUSPEND) {
64710187SKrishna.Elango@Sun.COM 				if (pci_post_suspend(rdip) != DDI_SUCCESS)
64810187SKrishna.Elango@Sun.COM 					return (DDI_FAILURE);
64910187SKrishna.Elango@Sun.COM 			}
65010187SKrishna.Elango@Sun.COM 			break;
65110187SKrishna.Elango@Sun.COM 		default:
65210187SKrishna.Elango@Sun.COM 			break;
65310187SKrishna.Elango@Sun.COM 		}
65410187SKrishna.Elango@Sun.COM 		break;
65510187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_ATTACH:
65610187SKrishna.Elango@Sun.COM 		as = (struct attachspec *)arg;
65710187SKrishna.Elango@Sun.COM 		switch (as->when) {
65810187SKrishna.Elango@Sun.COM 		case DDI_PRE:
65910187SKrishna.Elango@Sun.COM 			if (as->cmd == DDI_RESUME) {
66010187SKrishna.Elango@Sun.COM 				if (pci_pre_resume(rdip) != DDI_SUCCESS)
66110187SKrishna.Elango@Sun.COM 					return (DDI_FAILURE);
66210187SKrishna.Elango@Sun.COM 			}
66310187SKrishna.Elango@Sun.COM 			break;
66410187SKrishna.Elango@Sun.COM 		case DDI_POST:
66510187SKrishna.Elango@Sun.COM 			/*
66610187SKrishna.Elango@Sun.COM 			 * For leaf devices supporting RBER and AER, we
66710187SKrishna.Elango@Sun.COM 			 * need to apply this workaround on them after
66810187SKrishna.Elango@Sun.COM 			 * attach to be notified of UEs that would
66910187SKrishna.Elango@Sun.COM 			 * otherwise be ignored as CEs on Intel chipsets
67010187SKrishna.Elango@Sun.COM 			 * currently
67110187SKrishna.Elango@Sun.COM 			 */
67210187SKrishna.Elango@Sun.COM 			pcieb_intel_rber_workaround(rdip);
67310187SKrishna.Elango@Sun.COM 			break;
67410187SKrishna.Elango@Sun.COM 		default:
67510187SKrishna.Elango@Sun.COM 			break;
67610187SKrishna.Elango@Sun.COM 		}
67710187SKrishna.Elango@Sun.COM 		break;
67810187SKrishna.Elango@Sun.COM 	default:
67910187SKrishna.Elango@Sun.COM 		break;
68010187SKrishna.Elango@Sun.COM 	}
68110187SKrishna.Elango@Sun.COM 
68210187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
68310187SKrishna.Elango@Sun.COM }
684