xref: /onnv-gate/usr/src/uts/common/io/pciex/pcie.c (revision 11366:1ccde625d7fd)
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 /*
2210187SKrishna.Elango@Sun.COM  * Copyright 2009 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 #include <sys/sysmacros.h>
2710187SKrishna.Elango@Sun.COM #include <sys/types.h>
2810187SKrishna.Elango@Sun.COM #include <sys/kmem.h>
2910187SKrishna.Elango@Sun.COM #include <sys/modctl.h>
3010187SKrishna.Elango@Sun.COM #include <sys/ddi.h>
3110187SKrishna.Elango@Sun.COM #include <sys/sunddi.h>
3210187SKrishna.Elango@Sun.COM #include <sys/sunndi.h>
3310187SKrishna.Elango@Sun.COM #include <sys/fm/protocol.h>
3410187SKrishna.Elango@Sun.COM #include <sys/fm/util.h>
3510187SKrishna.Elango@Sun.COM #include <sys/promif.h>
3610187SKrishna.Elango@Sun.COM #include <sys/disp.h>
3710923SEvan.Yan@Sun.COM #include <sys/stat.h>
3810923SEvan.Yan@Sun.COM #include <sys/file.h>
3910187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h>
4010923SEvan.Yan@Sun.COM #include <sys/pci_impl.h>
4110187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h>
4210923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h>
4310923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcicfg.h>
4411245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h>
4510187SKrishna.Elango@Sun.COM 
4610923SEvan.Yan@Sun.COM /* Local functions prototypes */
4710187SKrishna.Elango@Sun.COM static void pcie_init_pfd(dev_info_t *);
4810187SKrishna.Elango@Sun.COM static void pcie_fini_pfd(dev_info_t *);
4910187SKrishna.Elango@Sun.COM 
5010187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
5110187SKrishna.Elango@Sun.COM static void pcie_check_io_mem_range(ddi_acc_handle_t, boolean_t *, boolean_t *);
5210187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
5310187SKrishna.Elango@Sun.COM 
5410187SKrishna.Elango@Sun.COM #ifdef DEBUG
5510187SKrishna.Elango@Sun.COM uint_t pcie_debug_flags = 0;
5610187SKrishna.Elango@Sun.COM static void pcie_print_bus(pcie_bus_t *bus_p);
5710923SEvan.Yan@Sun.COM void pcie_dbg(char *fmt, ...);
5810187SKrishna.Elango@Sun.COM #endif /* DEBUG */
5910187SKrishna.Elango@Sun.COM 
6010187SKrishna.Elango@Sun.COM /* Variable to control default PCI-Express config settings */
6110187SKrishna.Elango@Sun.COM ushort_t pcie_command_default =
6210187SKrishna.Elango@Sun.COM     PCI_COMM_SERR_ENABLE |
6310187SKrishna.Elango@Sun.COM     PCI_COMM_WAIT_CYC_ENAB |
6410187SKrishna.Elango@Sun.COM     PCI_COMM_PARITY_DETECT |
6510187SKrishna.Elango@Sun.COM     PCI_COMM_ME |
6610187SKrishna.Elango@Sun.COM     PCI_COMM_MAE |
6710187SKrishna.Elango@Sun.COM     PCI_COMM_IO;
6810187SKrishna.Elango@Sun.COM 
6910187SKrishna.Elango@Sun.COM /* xxx_fw are bits that are controlled by FW and should not be modified */
7010187SKrishna.Elango@Sun.COM ushort_t pcie_command_default_fw =
7110187SKrishna.Elango@Sun.COM     PCI_COMM_SPEC_CYC |
7210187SKrishna.Elango@Sun.COM     PCI_COMM_MEMWR_INVAL |
7310187SKrishna.Elango@Sun.COM     PCI_COMM_PALETTE_SNOOP |
7410187SKrishna.Elango@Sun.COM     PCI_COMM_WAIT_CYC_ENAB |
7510187SKrishna.Elango@Sun.COM     0xF800; /* Reserved Bits */
7610187SKrishna.Elango@Sun.COM 
7710187SKrishna.Elango@Sun.COM ushort_t pcie_bdg_command_default_fw =
7810187SKrishna.Elango@Sun.COM     PCI_BCNF_BCNTRL_ISA_ENABLE |
7910187SKrishna.Elango@Sun.COM     PCI_BCNF_BCNTRL_VGA_ENABLE |
8010187SKrishna.Elango@Sun.COM     0xF000; /* Reserved Bits */
8110187SKrishna.Elango@Sun.COM 
8210187SKrishna.Elango@Sun.COM /* PCI-Express Base error defaults */
8310187SKrishna.Elango@Sun.COM ushort_t pcie_base_err_default =
8410187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_CE_REPORTING_EN |
8510187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_NFE_REPORTING_EN |
8610187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_FE_REPORTING_EN |
8710187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_UR_REPORTING_EN;
8810187SKrishna.Elango@Sun.COM 
8910187SKrishna.Elango@Sun.COM /* PCI-Express Device Control Register */
9010187SKrishna.Elango@Sun.COM uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN |
9110187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_MAX_READ_REQ_512;
9210187SKrishna.Elango@Sun.COM 
9310187SKrishna.Elango@Sun.COM /* PCI-Express AER Root Control Register */
9410187SKrishna.Elango@Sun.COM #define	PCIE_ROOT_SYS_ERR	(PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \
9510187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \
9610187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_FE_EN)
9710187SKrishna.Elango@Sun.COM 
9810187SKrishna.Elango@Sun.COM ushort_t pcie_root_ctrl_default =
9910187SKrishna.Elango@Sun.COM     PCIE_ROOTCTL_SYS_ERR_ON_CE_EN |
10010187SKrishna.Elango@Sun.COM     PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
10110187SKrishna.Elango@Sun.COM     PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
10210187SKrishna.Elango@Sun.COM 
10310187SKrishna.Elango@Sun.COM /* PCI-Express Root Error Command Register */
10410187SKrishna.Elango@Sun.COM ushort_t pcie_root_error_cmd_default =
10510187SKrishna.Elango@Sun.COM     PCIE_AER_RE_CMD_CE_REP_EN |
10610187SKrishna.Elango@Sun.COM     PCIE_AER_RE_CMD_NFE_REP_EN |
10710187SKrishna.Elango@Sun.COM     PCIE_AER_RE_CMD_FE_REP_EN;
10810187SKrishna.Elango@Sun.COM 
10910187SKrishna.Elango@Sun.COM /* ECRC settings in the PCIe AER Control Register */
11010187SKrishna.Elango@Sun.COM uint32_t pcie_ecrc_value =
11110187SKrishna.Elango@Sun.COM     PCIE_AER_CTL_ECRC_GEN_ENA |
11210187SKrishna.Elango@Sun.COM     PCIE_AER_CTL_ECRC_CHECK_ENA;
11310187SKrishna.Elango@Sun.COM 
11410187SKrishna.Elango@Sun.COM /*
11510187SKrishna.Elango@Sun.COM  * If a particular platform wants to disable certain errors such as UR/MA,
11610187SKrishna.Elango@Sun.COM  * instead of using #defines have the platform's PCIe Root Complex driver set
11710187SKrishna.Elango@Sun.COM  * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions.  For
11810923SEvan.Yan@Sun.COM  * x86 the closest thing to a PCIe root complex driver is NPE.	For SPARC the
11910187SKrishna.Elango@Sun.COM  * closest PCIe root complex driver is PX.
12010187SKrishna.Elango@Sun.COM  *
12110187SKrishna.Elango@Sun.COM  * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86
12210187SKrishna.Elango@Sun.COM  * systems may want to disable SERR in general.  For root ports, enabling SERR
12310187SKrishna.Elango@Sun.COM  * causes NMIs which are not handled and results in a watchdog timeout error.
12410187SKrishna.Elango@Sun.COM  */
12510187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_mask = 0;		/* AER UE Mask */
12610187SKrishna.Elango@Sun.COM uint32_t pcie_aer_ce_mask = 0;		/* AER CE Mask */
12710187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_mask = 0;	/* AER Secondary UE Mask */
12810187SKrishna.Elango@Sun.COM uint32_t pcie_serr_disable_flag = 0;	/* Disable SERR */
12910187SKrishna.Elango@Sun.COM 
13010187SKrishna.Elango@Sun.COM /* Default severities needed for eversholt.  Error handling doesn't care */
13110187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \
13210187SKrishna.Elango@Sun.COM     PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \
13310187SKrishna.Elango@Sun.COM     PCIE_AER_UCE_TRAINING;
13410187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \
13510187SKrishna.Elango@Sun.COM     PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \
13610187SKrishna.Elango@Sun.COM     PCIE_AER_SUCE_USC_MSG_DATA_ERR;
13710187SKrishna.Elango@Sun.COM 
13810187SKrishna.Elango@Sun.COM int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5;
13910923SEvan.Yan@Sun.COM int pcie_disable_ari = 0;
14010187SKrishna.Elango@Sun.COM 
14110187SKrishna.Elango@Sun.COM static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip,
14210187SKrishna.Elango@Sun.COM 	int *max_supported);
14310187SKrishna.Elango@Sun.COM static int pcie_get_max_supported(dev_info_t *dip, void *arg);
14410187SKrishna.Elango@Sun.COM static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
14510187SKrishna.Elango@Sun.COM     caddr_t *addrp, ddi_acc_handle_t *handlep);
14610923SEvan.Yan@Sun.COM static void pcie_unmap_phys(ddi_acc_handle_t *handlep,	pci_regspec_t *ph);
14710187SKrishna.Elango@Sun.COM 
14811245SZhijun.Fu@Sun.COM dev_info_t *pcie_get_rc_dip(dev_info_t *dip);
14911245SZhijun.Fu@Sun.COM 
15010187SKrishna.Elango@Sun.COM /*
15110187SKrishna.Elango@Sun.COM  * modload support
15210187SKrishna.Elango@Sun.COM  */
15310187SKrishna.Elango@Sun.COM 
15410187SKrishna.Elango@Sun.COM static struct modlmisc modlmisc	= {
15510187SKrishna.Elango@Sun.COM 	&mod_miscops,	/* Type	of module */
15610923SEvan.Yan@Sun.COM 	"PCI Express Framework Module"
15710187SKrishna.Elango@Sun.COM };
15810187SKrishna.Elango@Sun.COM 
15910187SKrishna.Elango@Sun.COM static struct modlinkage modlinkage = {
16010187SKrishna.Elango@Sun.COM 	MODREV_1,
16110187SKrishna.Elango@Sun.COM 	(void	*)&modlmisc,
16210187SKrishna.Elango@Sun.COM 	NULL
16310187SKrishna.Elango@Sun.COM };
16410187SKrishna.Elango@Sun.COM 
16510187SKrishna.Elango@Sun.COM /*
16610187SKrishna.Elango@Sun.COM  * Global Variables needed for a non-atomic version of ddi_fm_ereport_post.
16710187SKrishna.Elango@Sun.COM  * Currently used to send the pci.fabric ereports whose payload depends on the
16810187SKrishna.Elango@Sun.COM  * type of PCI device it is being sent for.
16910187SKrishna.Elango@Sun.COM  */
17010187SKrishna.Elango@Sun.COM char		*pcie_nv_buf;
17110187SKrishna.Elango@Sun.COM nv_alloc_t	*pcie_nvap;
17210187SKrishna.Elango@Sun.COM nvlist_t	*pcie_nvl;
17310187SKrishna.Elango@Sun.COM 
17410187SKrishna.Elango@Sun.COM int
17510187SKrishna.Elango@Sun.COM _init(void)
17610187SKrishna.Elango@Sun.COM {
17710187SKrishna.Elango@Sun.COM 	int rval;
17810187SKrishna.Elango@Sun.COM 
17910187SKrishna.Elango@Sun.COM 	pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP);
18010187SKrishna.Elango@Sun.COM 	pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ);
18110187SKrishna.Elango@Sun.COM 	pcie_nvl = fm_nvlist_create(pcie_nvap);
18210187SKrishna.Elango@Sun.COM 
18310187SKrishna.Elango@Sun.COM 	rval = mod_install(&modlinkage);
18410187SKrishna.Elango@Sun.COM 	return (rval);
18510187SKrishna.Elango@Sun.COM }
18610187SKrishna.Elango@Sun.COM 
18710187SKrishna.Elango@Sun.COM int
18810187SKrishna.Elango@Sun.COM _fini()
18910187SKrishna.Elango@Sun.COM {
19010187SKrishna.Elango@Sun.COM 	int		rval;
19110187SKrishna.Elango@Sun.COM 
19210187SKrishna.Elango@Sun.COM 	fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
19310187SKrishna.Elango@Sun.COM 	fm_nva_xdestroy(pcie_nvap);
19410187SKrishna.Elango@Sun.COM 	kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
19510187SKrishna.Elango@Sun.COM 
19610187SKrishna.Elango@Sun.COM 	rval = mod_remove(&modlinkage);
19710187SKrishna.Elango@Sun.COM 	return (rval);
19810187SKrishna.Elango@Sun.COM }
19910187SKrishna.Elango@Sun.COM 
20010187SKrishna.Elango@Sun.COM int
20110187SKrishna.Elango@Sun.COM _info(struct modinfo *modinfop)
20210187SKrishna.Elango@Sun.COM {
20310187SKrishna.Elango@Sun.COM 	return (mod_info(&modlinkage, modinfop));
20410187SKrishna.Elango@Sun.COM }
20510187SKrishna.Elango@Sun.COM 
20610923SEvan.Yan@Sun.COM /* ARGSUSED */
20710923SEvan.Yan@Sun.COM int
20810923SEvan.Yan@Sun.COM pcie_init(dev_info_t *dip, caddr_t arg)
20910923SEvan.Yan@Sun.COM {
21010923SEvan.Yan@Sun.COM 	int	ret = DDI_SUCCESS;
21110923SEvan.Yan@Sun.COM 
21210923SEvan.Yan@Sun.COM 	/*
21310923SEvan.Yan@Sun.COM 	 * Create a "devctl" minor node to support DEVCTL_DEVICE_*
21410923SEvan.Yan@Sun.COM 	 * and DEVCTL_BUS_* ioctls to this bus.
21510923SEvan.Yan@Sun.COM 	 */
21610923SEvan.Yan@Sun.COM 	if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR,
21710923SEvan.Yan@Sun.COM 	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR),
21810923SEvan.Yan@Sun.COM 	    DDI_NT_NEXUS, 0)) != DDI_SUCCESS) {
21910923SEvan.Yan@Sun.COM 		PCIE_DBG("Failed to create devctl minor node for %s%d\n",
22010923SEvan.Yan@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip));
22110923SEvan.Yan@Sun.COM 
22210923SEvan.Yan@Sun.COM 		return (ret);
22310923SEvan.Yan@Sun.COM 	}
22410923SEvan.Yan@Sun.COM 
22510923SEvan.Yan@Sun.COM 	if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) {
22610923SEvan.Yan@Sun.COM 		/*
227*11366SColin.Zou@Sun.COM 		 * On some x86 platforms, we observed unexpected hotplug
228*11366SColin.Zou@Sun.COM 		 * initialization failures in recent years. The known cause
229*11366SColin.Zou@Sun.COM 		 * is a hardware issue: while the problem PCI bridges have
230*11366SColin.Zou@Sun.COM 		 * the Hotplug Capable registers set, the machine actually
231*11366SColin.Zou@Sun.COM 		 * does not implement the expected ACPI object.
232*11366SColin.Zou@Sun.COM 		 *
233*11366SColin.Zou@Sun.COM 		 * We don't want to stop PCI driver attach and system boot
234*11366SColin.Zou@Sun.COM 		 * just because of this hotplug initialization failure.
235*11366SColin.Zou@Sun.COM 		 * Continue with a debug message printed.
23610923SEvan.Yan@Sun.COM 		 */
237*11366SColin.Zou@Sun.COM 		PCIE_DBG("%s%d: Failed setting hotplug framework\n",
23810923SEvan.Yan@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip));
23910923SEvan.Yan@Sun.COM 
24010923SEvan.Yan@Sun.COM #if defined(__sparc)
24110923SEvan.Yan@Sun.COM 		ddi_remove_minor_node(dip, "devctl");
24210923SEvan.Yan@Sun.COM 
24310923SEvan.Yan@Sun.COM 		return (ret);
24410923SEvan.Yan@Sun.COM #endif /* defined(__sparc) */
24510923SEvan.Yan@Sun.COM 	}
24610923SEvan.Yan@Sun.COM 
24710923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
24810923SEvan.Yan@Sun.COM }
24910923SEvan.Yan@Sun.COM 
25010923SEvan.Yan@Sun.COM /* ARGSUSED */
25110923SEvan.Yan@Sun.COM int
25210923SEvan.Yan@Sun.COM pcie_uninit(dev_info_t *dip)
25310923SEvan.Yan@Sun.COM {
25410923SEvan.Yan@Sun.COM 	int	ret = DDI_SUCCESS;
25510923SEvan.Yan@Sun.COM 
25610923SEvan.Yan@Sun.COM 	if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED)
25710923SEvan.Yan@Sun.COM 		(void) pcie_ari_disable(dip);
25810923SEvan.Yan@Sun.COM 
25910923SEvan.Yan@Sun.COM 	if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) {
26010923SEvan.Yan@Sun.COM 		PCIE_DBG("Failed to uninitialize hotplug for %s%d\n",
26110923SEvan.Yan@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip));
26210923SEvan.Yan@Sun.COM 
26310923SEvan.Yan@Sun.COM 		return (ret);
26410923SEvan.Yan@Sun.COM 	}
26510923SEvan.Yan@Sun.COM 
26610923SEvan.Yan@Sun.COM 	ddi_remove_minor_node(dip, "devctl");
26710923SEvan.Yan@Sun.COM 
26810923SEvan.Yan@Sun.COM 	return (ret);
26910923SEvan.Yan@Sun.COM }
27010923SEvan.Yan@Sun.COM 
27110923SEvan.Yan@Sun.COM /* ARGSUSED */
27210923SEvan.Yan@Sun.COM int
27310923SEvan.Yan@Sun.COM pcie_intr(dev_info_t *dip)
27410923SEvan.Yan@Sun.COM {
27510923SEvan.Yan@Sun.COM 	return (pcie_hp_intr(dip));
27610923SEvan.Yan@Sun.COM }
27710923SEvan.Yan@Sun.COM 
27810923SEvan.Yan@Sun.COM /* ARGSUSED */
27910923SEvan.Yan@Sun.COM int
28010923SEvan.Yan@Sun.COM pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp)
28110923SEvan.Yan@Sun.COM {
28210923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
28310923SEvan.Yan@Sun.COM 
28410923SEvan.Yan@Sun.COM 	/*
28510923SEvan.Yan@Sun.COM 	 * Make sure the open is for the right file type.
28610923SEvan.Yan@Sun.COM 	 */
28710923SEvan.Yan@Sun.COM 	if (otyp != OTYP_CHR)
28810923SEvan.Yan@Sun.COM 		return (EINVAL);
28910923SEvan.Yan@Sun.COM 
29010923SEvan.Yan@Sun.COM 	/*
29110923SEvan.Yan@Sun.COM 	 * Handle the open by tracking the device state.
29210923SEvan.Yan@Sun.COM 	 */
29310923SEvan.Yan@Sun.COM 	if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) ||
29410923SEvan.Yan@Sun.COM 	    ((flags & FEXCL) &&
29510923SEvan.Yan@Sun.COM 	    (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) {
29610923SEvan.Yan@Sun.COM 		return (EBUSY);
29710923SEvan.Yan@Sun.COM 	}
29810923SEvan.Yan@Sun.COM 
29910923SEvan.Yan@Sun.COM 	if (flags & FEXCL)
30010923SEvan.Yan@Sun.COM 		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
30110923SEvan.Yan@Sun.COM 	else
30210923SEvan.Yan@Sun.COM 		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN;
30310923SEvan.Yan@Sun.COM 
30410923SEvan.Yan@Sun.COM 	return (0);
30510923SEvan.Yan@Sun.COM }
30610923SEvan.Yan@Sun.COM 
30710923SEvan.Yan@Sun.COM /* ARGSUSED */
30810923SEvan.Yan@Sun.COM int
30910923SEvan.Yan@Sun.COM pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp)
31010923SEvan.Yan@Sun.COM {
31110923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
31210923SEvan.Yan@Sun.COM 
31310923SEvan.Yan@Sun.COM 	if (otyp != OTYP_CHR)
31410923SEvan.Yan@Sun.COM 		return (EINVAL);
31510923SEvan.Yan@Sun.COM 
31610923SEvan.Yan@Sun.COM 	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
31710923SEvan.Yan@Sun.COM 
31810923SEvan.Yan@Sun.COM 	return (0);
31910923SEvan.Yan@Sun.COM }
32010923SEvan.Yan@Sun.COM 
32110923SEvan.Yan@Sun.COM /* ARGSUSED */
32210923SEvan.Yan@Sun.COM int
32310923SEvan.Yan@Sun.COM pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode,
32410923SEvan.Yan@Sun.COM     cred_t *credp, int *rvalp)
32510923SEvan.Yan@Sun.COM {
32610923SEvan.Yan@Sun.COM 	struct devctl_iocdata	*dcp;
32710923SEvan.Yan@Sun.COM 	uint_t			bus_state;
32810923SEvan.Yan@Sun.COM 	int			rv = DDI_SUCCESS;
32910923SEvan.Yan@Sun.COM 
33010923SEvan.Yan@Sun.COM 	/*
33110923SEvan.Yan@Sun.COM 	 * We can use the generic implementation for devctl ioctl
33210923SEvan.Yan@Sun.COM 	 */
33310923SEvan.Yan@Sun.COM 	switch (cmd) {
33410923SEvan.Yan@Sun.COM 	case DEVCTL_DEVICE_GETSTATE:
33510923SEvan.Yan@Sun.COM 	case DEVCTL_DEVICE_ONLINE:
33610923SEvan.Yan@Sun.COM 	case DEVCTL_DEVICE_OFFLINE:
33710923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_GETSTATE:
33810923SEvan.Yan@Sun.COM 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
33910923SEvan.Yan@Sun.COM 	default:
34010923SEvan.Yan@Sun.COM 		break;
34110923SEvan.Yan@Sun.COM 	}
34210923SEvan.Yan@Sun.COM 
34310923SEvan.Yan@Sun.COM 	/*
34410923SEvan.Yan@Sun.COM 	 * read devctl ioctl data
34510923SEvan.Yan@Sun.COM 	 */
34610923SEvan.Yan@Sun.COM 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
34710923SEvan.Yan@Sun.COM 		return (EFAULT);
34810923SEvan.Yan@Sun.COM 
34910923SEvan.Yan@Sun.COM 	switch (cmd) {
35010923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_QUIESCE:
35110923SEvan.Yan@Sun.COM 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
35210923SEvan.Yan@Sun.COM 			if (bus_state == BUS_QUIESCED)
35310923SEvan.Yan@Sun.COM 				break;
35410923SEvan.Yan@Sun.COM 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
35510923SEvan.Yan@Sun.COM 		break;
35610923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_UNQUIESCE:
35710923SEvan.Yan@Sun.COM 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
35810923SEvan.Yan@Sun.COM 			if (bus_state == BUS_ACTIVE)
35910923SEvan.Yan@Sun.COM 				break;
36010923SEvan.Yan@Sun.COM 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
36110923SEvan.Yan@Sun.COM 		break;
36210923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_RESET:
36310923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_RESETALL:
36410923SEvan.Yan@Sun.COM 	case DEVCTL_DEVICE_RESET:
36510923SEvan.Yan@Sun.COM 		rv = ENOTSUP;
36610923SEvan.Yan@Sun.COM 		break;
36710923SEvan.Yan@Sun.COM 	default:
36810923SEvan.Yan@Sun.COM 		rv = ENOTTY;
36910923SEvan.Yan@Sun.COM 	}
37010923SEvan.Yan@Sun.COM 
37110923SEvan.Yan@Sun.COM 	ndi_dc_freehdl(dcp);
37210923SEvan.Yan@Sun.COM 	return (rv);
37310923SEvan.Yan@Sun.COM }
37410923SEvan.Yan@Sun.COM 
37510923SEvan.Yan@Sun.COM /* ARGSUSED */
37610923SEvan.Yan@Sun.COM int
37710923SEvan.Yan@Sun.COM pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
37810923SEvan.Yan@Sun.COM     int flags, char *name, caddr_t valuep, int *lengthp)
37910923SEvan.Yan@Sun.COM {
38010923SEvan.Yan@Sun.COM 	if (dev == DDI_DEV_T_ANY)
38110923SEvan.Yan@Sun.COM 		goto skip;
38210923SEvan.Yan@Sun.COM 
38310923SEvan.Yan@Sun.COM 	if (PCIE_IS_HOTPLUG_CAPABLE(dip) &&
38410923SEvan.Yan@Sun.COM 	    strcmp(name, "pci-occupant") == 0) {
38510923SEvan.Yan@Sun.COM 		int	pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
38610923SEvan.Yan@Sun.COM 
38710923SEvan.Yan@Sun.COM 		pcie_hp_create_occupant_props(dip, dev, pci_dev);
38810923SEvan.Yan@Sun.COM 	}
38910923SEvan.Yan@Sun.COM 
39010923SEvan.Yan@Sun.COM skip:
39110923SEvan.Yan@Sun.COM 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
39210923SEvan.Yan@Sun.COM }
39310923SEvan.Yan@Sun.COM 
39411245SZhijun.Fu@Sun.COM int
39511245SZhijun.Fu@Sun.COM pcie_init_cfghdl(dev_info_t *cdip)
39611245SZhijun.Fu@Sun.COM {
39711245SZhijun.Fu@Sun.COM 	pcie_bus_t		*bus_p;
39811245SZhijun.Fu@Sun.COM 	ddi_acc_handle_t	eh = NULL;
39911245SZhijun.Fu@Sun.COM 
40011245SZhijun.Fu@Sun.COM 	bus_p = PCIE_DIP2BUS(cdip);
40111245SZhijun.Fu@Sun.COM 	if (bus_p == NULL)
40211245SZhijun.Fu@Sun.COM 		return (DDI_FAILURE);
40311245SZhijun.Fu@Sun.COM 
40411245SZhijun.Fu@Sun.COM 	/* Create an config access special to error handling */
40511245SZhijun.Fu@Sun.COM 	if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
40611245SZhijun.Fu@Sun.COM 		cmn_err(CE_WARN, "Cannot setup config access"
40711245SZhijun.Fu@Sun.COM 		    " for BDF 0x%x\n", bus_p->bus_bdf);
40811245SZhijun.Fu@Sun.COM 		return (DDI_FAILURE);
40911245SZhijun.Fu@Sun.COM 	}
41011245SZhijun.Fu@Sun.COM 
41111245SZhijun.Fu@Sun.COM 	bus_p->bus_cfg_hdl = eh;
41211245SZhijun.Fu@Sun.COM 	return (DDI_SUCCESS);
41311245SZhijun.Fu@Sun.COM }
41411245SZhijun.Fu@Sun.COM 
41511245SZhijun.Fu@Sun.COM void
41611245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(dev_info_t *cdip)
41711245SZhijun.Fu@Sun.COM {
41811245SZhijun.Fu@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(cdip);
41911245SZhijun.Fu@Sun.COM 
42011245SZhijun.Fu@Sun.COM 	pci_config_teardown(&bus_p->bus_cfg_hdl);
42111245SZhijun.Fu@Sun.COM }
42211245SZhijun.Fu@Sun.COM 
42310187SKrishna.Elango@Sun.COM /*
42410187SKrishna.Elango@Sun.COM  * PCI-Express child device initialization.
42510187SKrishna.Elango@Sun.COM  * This function enables generic pci-express interrupts and error
42610187SKrishna.Elango@Sun.COM  * handling.
42710187SKrishna.Elango@Sun.COM  *
42810187SKrishna.Elango@Sun.COM  * @param pdip		root dip (root nexus's dip)
42910187SKrishna.Elango@Sun.COM  * @param cdip		child's dip (device's dip)
43010187SKrishna.Elango@Sun.COM  * @return		DDI_SUCCESS or DDI_FAILURE
43110187SKrishna.Elango@Sun.COM  */
43210187SKrishna.Elango@Sun.COM /* ARGSUSED */
43310187SKrishna.Elango@Sun.COM int
43410187SKrishna.Elango@Sun.COM pcie_initchild(dev_info_t *cdip)
43510187SKrishna.Elango@Sun.COM {
43610187SKrishna.Elango@Sun.COM 	uint16_t		tmp16, reg16;
43710187SKrishna.Elango@Sun.COM 	pcie_bus_t		*bus_p;
43810187SKrishna.Elango@Sun.COM 
43910187SKrishna.Elango@Sun.COM 	bus_p = PCIE_DIP2BUS(cdip);
44010187SKrishna.Elango@Sun.COM 	if (bus_p == NULL) {
44110187SKrishna.Elango@Sun.COM 		PCIE_DBG("%s: BUS not found.\n",
44210187SKrishna.Elango@Sun.COM 		    ddi_driver_name(cdip));
44310187SKrishna.Elango@Sun.COM 
44410187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
44510187SKrishna.Elango@Sun.COM 	}
44610187SKrishna.Elango@Sun.COM 
44711245SZhijun.Fu@Sun.COM 	if (pcie_init_cfghdl(cdip) != DDI_SUCCESS)
44811245SZhijun.Fu@Sun.COM 		return (DDI_FAILURE);
44911245SZhijun.Fu@Sun.COM 
45010187SKrishna.Elango@Sun.COM 	/* Clear the device's status register */
45110187SKrishna.Elango@Sun.COM 	reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT);
45210187SKrishna.Elango@Sun.COM 	PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16);
45310187SKrishna.Elango@Sun.COM 
45410187SKrishna.Elango@Sun.COM 	/* Setup the device's command register */
45510187SKrishna.Elango@Sun.COM 	reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM);
45610187SKrishna.Elango@Sun.COM 	tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default;
45710187SKrishna.Elango@Sun.COM 
45810187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
45910187SKrishna.Elango@Sun.COM 	boolean_t empty_io_range = B_FALSE;
46010187SKrishna.Elango@Sun.COM 	boolean_t empty_mem_range = B_FALSE;
46110187SKrishna.Elango@Sun.COM 	/*
46210187SKrishna.Elango@Sun.COM 	 * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem
46310187SKrishna.Elango@Sun.COM 	 * access as it can cause a hang if enabled.
46410187SKrishna.Elango@Sun.COM 	 */
46510187SKrishna.Elango@Sun.COM 	pcie_check_io_mem_range(bus_p->bus_cfg_hdl, &empty_io_range,
46610187SKrishna.Elango@Sun.COM 	    &empty_mem_range);
46710187SKrishna.Elango@Sun.COM 	if ((empty_io_range == B_TRUE) &&
46810187SKrishna.Elango@Sun.COM 	    (pcie_command_default & PCI_COMM_IO)) {
46910187SKrishna.Elango@Sun.COM 		tmp16 &= ~PCI_COMM_IO;
47010187SKrishna.Elango@Sun.COM 		PCIE_DBG("No I/O range found for %s, bdf 0x%x\n",
47110187SKrishna.Elango@Sun.COM 		    ddi_driver_name(cdip), bus_p->bus_bdf);
47210187SKrishna.Elango@Sun.COM 	}
47310187SKrishna.Elango@Sun.COM 	if ((empty_mem_range == B_TRUE) &&
47410187SKrishna.Elango@Sun.COM 	    (pcie_command_default & PCI_COMM_MAE)) {
47510187SKrishna.Elango@Sun.COM 		tmp16 &= ~PCI_COMM_MAE;
47610187SKrishna.Elango@Sun.COM 		PCIE_DBG("No Mem range found for %s, bdf 0x%x\n",
47710187SKrishna.Elango@Sun.COM 		    ddi_driver_name(cdip), bus_p->bus_bdf);
47810187SKrishna.Elango@Sun.COM 	}
47910187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
48010187SKrishna.Elango@Sun.COM 
48110187SKrishna.Elango@Sun.COM 	if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p))
48210187SKrishna.Elango@Sun.COM 		tmp16 &= ~PCI_COMM_SERR_ENABLE;
48310187SKrishna.Elango@Sun.COM 
48410187SKrishna.Elango@Sun.COM 	PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16);
48510187SKrishna.Elango@Sun.COM 	PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16);
48610187SKrishna.Elango@Sun.COM 
48710187SKrishna.Elango@Sun.COM 	/*
48810187SKrishna.Elango@Sun.COM 	 * If the device has a bus control register then program it
48910187SKrishna.Elango@Sun.COM 	 * based on the settings in the command register.
49010187SKrishna.Elango@Sun.COM 	 */
49110187SKrishna.Elango@Sun.COM 	if (PCIE_IS_BDG(bus_p)) {
49210187SKrishna.Elango@Sun.COM 		/* Clear the device's secondary status register */
49310187SKrishna.Elango@Sun.COM 		reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
49410187SKrishna.Elango@Sun.COM 		PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16);
49510187SKrishna.Elango@Sun.COM 
49610187SKrishna.Elango@Sun.COM 		/* Setup the device's secondary command register */
49710187SKrishna.Elango@Sun.COM 		reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
49810187SKrishna.Elango@Sun.COM 		tmp16 = (reg16 & pcie_bdg_command_default_fw);
49910187SKrishna.Elango@Sun.COM 
50010187SKrishna.Elango@Sun.COM 		tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE;
50110187SKrishna.Elango@Sun.COM 		/*
50210187SKrishna.Elango@Sun.COM 		 * Workaround for this Nvidia bridge. Don't enable the SERR
50310187SKrishna.Elango@Sun.COM 		 * enable bit in the bridge control register as it could lead to
50410187SKrishna.Elango@Sun.COM 		 * bogus NMIs.
50510187SKrishna.Elango@Sun.COM 		 */
50610187SKrishna.Elango@Sun.COM 		if (bus_p->bus_dev_ven_id == 0x037010DE)
50710187SKrishna.Elango@Sun.COM 			tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
50810187SKrishna.Elango@Sun.COM 
50910187SKrishna.Elango@Sun.COM 		if (pcie_command_default & PCI_COMM_PARITY_DETECT)
51010187SKrishna.Elango@Sun.COM 			tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
51110187SKrishna.Elango@Sun.COM 
51210187SKrishna.Elango@Sun.COM 		/*
51310187SKrishna.Elango@Sun.COM 		 * Enable Master Abort Mode only if URs have not been masked.
51410187SKrishna.Elango@Sun.COM 		 * For PCI and PCIe-PCI bridges, enabling this bit causes a
51510187SKrishna.Elango@Sun.COM 		 * Master Aborts/UR to be forwarded as a UR/TA or SERR.  If this
51610187SKrishna.Elango@Sun.COM 		 * bit is masked, posted requests are dropped and non-posted
51710187SKrishna.Elango@Sun.COM 		 * requests are returned with -1.
51810187SKrishna.Elango@Sun.COM 		 */
51910187SKrishna.Elango@Sun.COM 		if (pcie_aer_uce_mask & PCIE_AER_UCE_UR)
52010187SKrishna.Elango@Sun.COM 			tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE;
52110187SKrishna.Elango@Sun.COM 		else
52210187SKrishna.Elango@Sun.COM 			tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
52310187SKrishna.Elango@Sun.COM 		PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16);
52410187SKrishna.Elango@Sun.COM 		PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL,
52510187SKrishna.Elango@Sun.COM 		    reg16);
52610187SKrishna.Elango@Sun.COM 	}
52710187SKrishna.Elango@Sun.COM 
52810187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p)) {
52910187SKrishna.Elango@Sun.COM 		/* Setup PCIe device control register */
53010187SKrishna.Elango@Sun.COM 		reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
53110187SKrishna.Elango@Sun.COM 		tmp16 = pcie_devctl_default;
53210187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
53310187SKrishna.Elango@Sun.COM 		PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
53410187SKrishna.Elango@Sun.COM 
53510187SKrishna.Elango@Sun.COM 		/* Enable PCIe errors */
53610187SKrishna.Elango@Sun.COM 		pcie_enable_errors(cdip);
53710187SKrishna.Elango@Sun.COM 	}
53810187SKrishna.Elango@Sun.COM 
53910923SEvan.Yan@Sun.COM 	bus_p->bus_ari = B_FALSE;
54010923SEvan.Yan@Sun.COM 	if ((pcie_ari_is_enabled(ddi_get_parent(cdip))
54110923SEvan.Yan@Sun.COM 	    == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip)
54210923SEvan.Yan@Sun.COM 	    == PCIE_ARI_DEVICE)) {
54310923SEvan.Yan@Sun.COM 		bus_p->bus_ari = B_TRUE;
54410923SEvan.Yan@Sun.COM 	}
54510923SEvan.Yan@Sun.COM 
54611245SZhijun.Fu@Sun.COM 	if (pcie_initchild_mps(cdip) == DDI_FAILURE) {
54711245SZhijun.Fu@Sun.COM 		pcie_fini_cfghdl(cdip);
54810187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
54911245SZhijun.Fu@Sun.COM 	}
55010187SKrishna.Elango@Sun.COM 
55110187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
55210187SKrishna.Elango@Sun.COM }
55310187SKrishna.Elango@Sun.COM 
55410187SKrishna.Elango@Sun.COM #define	PCIE_ZALLOC(data) kmem_zalloc(sizeof (data), KM_SLEEP)
55510187SKrishna.Elango@Sun.COM static void
55610187SKrishna.Elango@Sun.COM pcie_init_pfd(dev_info_t *dip)
55710187SKrishna.Elango@Sun.COM {
55810187SKrishna.Elango@Sun.COM 	pf_data_t	*pfd_p = PCIE_ZALLOC(pf_data_t);
55910187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
56010187SKrishna.Elango@Sun.COM 
56110187SKrishna.Elango@Sun.COM 	PCIE_DIP2PFD(dip) = pfd_p;
56210187SKrishna.Elango@Sun.COM 
56310187SKrishna.Elango@Sun.COM 	pfd_p->pe_bus_p = bus_p;
56410187SKrishna.Elango@Sun.COM 	pfd_p->pe_severity_flags = 0;
56510187SKrishna.Elango@Sun.COM 	pfd_p->pe_lock = B_FALSE;
56610187SKrishna.Elango@Sun.COM 	pfd_p->pe_valid = B_FALSE;
56710187SKrishna.Elango@Sun.COM 
56810187SKrishna.Elango@Sun.COM 	/* Allocate the root fault struct for both RC and RP */
56910187SKrishna.Elango@Sun.COM 	if (PCIE_IS_ROOT(bus_p)) {
57010187SKrishna.Elango@Sun.COM 		PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
57110187SKrishna.Elango@Sun.COM 		PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
57210187SKrishna.Elango@Sun.COM 	}
57310187SKrishna.Elango@Sun.COM 
57410187SKrishna.Elango@Sun.COM 	PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
57510187SKrishna.Elango@Sun.COM 
57610187SKrishna.Elango@Sun.COM 	if (PCIE_IS_BDG(bus_p))
57710187SKrishna.Elango@Sun.COM 		PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
57810187SKrishna.Elango@Sun.COM 
57910187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p)) {
58010187SKrishna.Elango@Sun.COM 		PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
58110187SKrishna.Elango@Sun.COM 
58210187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p))
58310187SKrishna.Elango@Sun.COM 			PCIE_RP_REG(pfd_p) =
58410187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
58510187SKrishna.Elango@Sun.COM 
58610187SKrishna.Elango@Sun.COM 		PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
58710187SKrishna.Elango@Sun.COM 		PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
58810187SKrishna.Elango@Sun.COM 
58910187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p)) {
59010187SKrishna.Elango@Sun.COM 			PCIE_ADV_RP_REG(pfd_p) =
59110187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
59210187SKrishna.Elango@Sun.COM 			PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id =
59310187SKrishna.Elango@Sun.COM 			    PCIE_INVALID_BDF;
59410187SKrishna.Elango@Sun.COM 			PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id =
59510187SKrishna.Elango@Sun.COM 			    PCIE_INVALID_BDF;
59610187SKrishna.Elango@Sun.COM 		} else if (PCIE_IS_PCIE_BDG(bus_p)) {
59710187SKrishna.Elango@Sun.COM 			PCIE_ADV_BDG_REG(pfd_p) =
59810187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t);
59910187SKrishna.Elango@Sun.COM 			PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf =
60010187SKrishna.Elango@Sun.COM 			    PCIE_INVALID_BDF;
60110187SKrishna.Elango@Sun.COM 		}
60210187SKrishna.Elango@Sun.COM 
60310187SKrishna.Elango@Sun.COM 		if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
60410187SKrishna.Elango@Sun.COM 			PCIX_BDG_ERR_REG(pfd_p) =
60510187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
60610187SKrishna.Elango@Sun.COM 
60710187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
60810187SKrishna.Elango@Sun.COM 				PCIX_BDG_ECC_REG(pfd_p, 0) =
60910187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
61010187SKrishna.Elango@Sun.COM 				PCIX_BDG_ECC_REG(pfd_p, 1) =
61110187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
61210187SKrishna.Elango@Sun.COM 			}
61310187SKrishna.Elango@Sun.COM 		}
61410187SKrishna.Elango@Sun.COM 	} else if (PCIE_IS_PCIX(bus_p)) {
61510187SKrishna.Elango@Sun.COM 		if (PCIE_IS_BDG(bus_p)) {
61610187SKrishna.Elango@Sun.COM 			PCIX_BDG_ERR_REG(pfd_p) =
61710187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
61810187SKrishna.Elango@Sun.COM 
61910187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
62010187SKrishna.Elango@Sun.COM 				PCIX_BDG_ECC_REG(pfd_p, 0) =
62110187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
62210187SKrishna.Elango@Sun.COM 				PCIX_BDG_ECC_REG(pfd_p, 1) =
62310187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
62410187SKrishna.Elango@Sun.COM 			}
62510187SKrishna.Elango@Sun.COM 		} else {
62610187SKrishna.Elango@Sun.COM 			PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t);
62710187SKrishna.Elango@Sun.COM 
62810187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p))
62910187SKrishna.Elango@Sun.COM 				PCIX_ECC_REG(pfd_p) =
63010187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
63110187SKrishna.Elango@Sun.COM 		}
63210187SKrishna.Elango@Sun.COM 	}
63310187SKrishna.Elango@Sun.COM }
63410187SKrishna.Elango@Sun.COM 
63510187SKrishna.Elango@Sun.COM static void
63610187SKrishna.Elango@Sun.COM pcie_fini_pfd(dev_info_t *dip)
63710187SKrishna.Elango@Sun.COM {
63810187SKrishna.Elango@Sun.COM 	pf_data_t	*pfd_p = PCIE_DIP2PFD(dip);
63910187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
64010187SKrishna.Elango@Sun.COM 
64110187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p)) {
64210187SKrishna.Elango@Sun.COM 		if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
64310187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
64410187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
64510187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
64610187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
64710187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
64810187SKrishna.Elango@Sun.COM 			}
64910187SKrishna.Elango@Sun.COM 
65010187SKrishna.Elango@Sun.COM 			kmem_free(PCIX_BDG_ERR_REG(pfd_p),
65110187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcix_bdg_err_regs_t));
65210187SKrishna.Elango@Sun.COM 		}
65310187SKrishna.Elango@Sun.COM 
65410187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p))
65510187SKrishna.Elango@Sun.COM 			kmem_free(PCIE_ADV_RP_REG(pfd_p),
65610187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcie_adv_rp_err_regs_t));
65710187SKrishna.Elango@Sun.COM 		else if (PCIE_IS_PCIE_BDG(bus_p))
65810187SKrishna.Elango@Sun.COM 			kmem_free(PCIE_ADV_BDG_REG(pfd_p),
65910187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcie_adv_bdg_err_regs_t));
66010187SKrishna.Elango@Sun.COM 
66110187SKrishna.Elango@Sun.COM 		kmem_free(PCIE_ADV_REG(pfd_p),
66210187SKrishna.Elango@Sun.COM 		    sizeof (pf_pcie_adv_err_regs_t));
66310187SKrishna.Elango@Sun.COM 
66410187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p))
66510187SKrishna.Elango@Sun.COM 			kmem_free(PCIE_RP_REG(pfd_p),
66610187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcie_rp_err_regs_t));
66710187SKrishna.Elango@Sun.COM 
66810187SKrishna.Elango@Sun.COM 		kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
66910187SKrishna.Elango@Sun.COM 	} else if (PCIE_IS_PCIX(bus_p)) {
67010187SKrishna.Elango@Sun.COM 		if (PCIE_IS_BDG(bus_p)) {
67110187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
67210187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
67310187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
67410187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
67510187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
67610187SKrishna.Elango@Sun.COM 			}
67710187SKrishna.Elango@Sun.COM 
67810187SKrishna.Elango@Sun.COM 			kmem_free(PCIX_BDG_ERR_REG(pfd_p),
67910187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcix_bdg_err_regs_t));
68010187SKrishna.Elango@Sun.COM 		} else {
68110187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p))
68210187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_ECC_REG(pfd_p),
68310187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
68410187SKrishna.Elango@Sun.COM 
68510187SKrishna.Elango@Sun.COM 			kmem_free(PCIX_ERR_REG(pfd_p),
68610187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcix_err_regs_t));
68710187SKrishna.Elango@Sun.COM 		}
68810187SKrishna.Elango@Sun.COM 	}
68910187SKrishna.Elango@Sun.COM 
69010187SKrishna.Elango@Sun.COM 	if (PCIE_IS_BDG(bus_p))
69110187SKrishna.Elango@Sun.COM 		kmem_free(PCI_BDG_ERR_REG(pfd_p),
69210187SKrishna.Elango@Sun.COM 		    sizeof (pf_pci_bdg_err_regs_t));
69310187SKrishna.Elango@Sun.COM 
69410187SKrishna.Elango@Sun.COM 	kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
69510187SKrishna.Elango@Sun.COM 
69610187SKrishna.Elango@Sun.COM 	if (PCIE_IS_ROOT(bus_p))
69710187SKrishna.Elango@Sun.COM 		kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
69810187SKrishna.Elango@Sun.COM 
69910187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t));
70010187SKrishna.Elango@Sun.COM 
70110187SKrishna.Elango@Sun.COM 	PCIE_DIP2PFD(dip) = NULL;
70210187SKrishna.Elango@Sun.COM }
70310187SKrishna.Elango@Sun.COM 
70410187SKrishna.Elango@Sun.COM 
70510187SKrishna.Elango@Sun.COM /*
70610187SKrishna.Elango@Sun.COM  * Special functions to allocate pf_data_t's for PCIe root complexes.
70710187SKrishna.Elango@Sun.COM  * Note: Root Complex not Root Port
70810187SKrishna.Elango@Sun.COM  */
70910187SKrishna.Elango@Sun.COM void
71010187SKrishna.Elango@Sun.COM pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p)
71110187SKrishna.Elango@Sun.COM {
71210187SKrishna.Elango@Sun.COM 	pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip);
71310187SKrishna.Elango@Sun.COM 	pfd_p->pe_severity_flags = 0;
71410187SKrishna.Elango@Sun.COM 	pfd_p->pe_lock = B_FALSE;
71510187SKrishna.Elango@Sun.COM 	pfd_p->pe_valid = B_FALSE;
71610187SKrishna.Elango@Sun.COM 
71710187SKrishna.Elango@Sun.COM 	PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
71810187SKrishna.Elango@Sun.COM 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
71910187SKrishna.Elango@Sun.COM 	PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
72010187SKrishna.Elango@Sun.COM 	PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
72110187SKrishna.Elango@Sun.COM 	PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
72210187SKrishna.Elango@Sun.COM 	PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
72310187SKrishna.Elango@Sun.COM 	PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
72410187SKrishna.Elango@Sun.COM 	PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
72510187SKrishna.Elango@Sun.COM 
72610187SKrishna.Elango@Sun.COM 	PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity;
72710187SKrishna.Elango@Sun.COM }
72810187SKrishna.Elango@Sun.COM 
72910187SKrishna.Elango@Sun.COM void
73010187SKrishna.Elango@Sun.COM pcie_rc_fini_pfd(pf_data_t *pfd_p)
73110187SKrishna.Elango@Sun.COM {
73210187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t));
73310187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t));
73410187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t));
73510187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
73610187SKrishna.Elango@Sun.COM 	kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t));
73710187SKrishna.Elango@Sun.COM 	kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
73810187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
73910187SKrishna.Elango@Sun.COM }
74010187SKrishna.Elango@Sun.COM 
74111245SZhijun.Fu@Sun.COM /*
74211245SZhijun.Fu@Sun.COM  * init pcie_bus_t for root complex
74311245SZhijun.Fu@Sun.COM  *
74411245SZhijun.Fu@Sun.COM  * Only a few of the fields in bus_t is valid for root complex.
74511245SZhijun.Fu@Sun.COM  * The fields that are bracketed are initialized in this routine:
74611245SZhijun.Fu@Sun.COM  *
74711245SZhijun.Fu@Sun.COM  * dev_info_t *		<bus_dip>
74811245SZhijun.Fu@Sun.COM  * dev_info_t *		bus_rp_dip
74911245SZhijun.Fu@Sun.COM  * ddi_acc_handle_t	bus_cfg_hdl
75011245SZhijun.Fu@Sun.COM  * uint_t		<bus_fm_flags>
75111245SZhijun.Fu@Sun.COM  * pcie_req_id_t	bus_bdf
75211245SZhijun.Fu@Sun.COM  * pcie_req_id_t	bus_rp_bdf
75311245SZhijun.Fu@Sun.COM  * uint32_t		bus_dev_ven_id
75411245SZhijun.Fu@Sun.COM  * uint8_t		bus_rev_id
75511245SZhijun.Fu@Sun.COM  * uint8_t		<bus_hdr_type>
75611245SZhijun.Fu@Sun.COM  * uint16_t		<bus_dev_type>
75711245SZhijun.Fu@Sun.COM  * uint8_t		bus_bdg_secbus
75811245SZhijun.Fu@Sun.COM  * uint16_t		bus_pcie_off
75911245SZhijun.Fu@Sun.COM  * uint16_t		<bus_aer_off>
76011245SZhijun.Fu@Sun.COM  * uint16_t		bus_pcix_off
76111245SZhijun.Fu@Sun.COM  * uint16_t		bus_ecc_ver
76211245SZhijun.Fu@Sun.COM  * pci_bus_range_t	bus_bus_range
76311245SZhijun.Fu@Sun.COM  * ppb_ranges_t	*	bus_addr_ranges
76411245SZhijun.Fu@Sun.COM  * int			bus_addr_entries
76511245SZhijun.Fu@Sun.COM  * pci_regspec_t *	bus_assigned_addr
76611245SZhijun.Fu@Sun.COM  * int			bus_assigned_entries
76711245SZhijun.Fu@Sun.COM  * pf_data_t *		bus_pfd
76811245SZhijun.Fu@Sun.COM  * int			bus_mps
76911245SZhijun.Fu@Sun.COM  * uint64_t		bus_cfgacc_base
77011245SZhijun.Fu@Sun.COM  * void	*		bus_plat_private
77111245SZhijun.Fu@Sun.COM  */
77210187SKrishna.Elango@Sun.COM void
77310187SKrishna.Elango@Sun.COM pcie_rc_init_bus(dev_info_t *dip)
77410187SKrishna.Elango@Sun.COM {
77510187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p;
77610187SKrishna.Elango@Sun.COM 
77710187SKrishna.Elango@Sun.COM 	bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
77810187SKrishna.Elango@Sun.COM 	bus_p->bus_dip = dip;
77910187SKrishna.Elango@Sun.COM 	bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO;
78010187SKrishna.Elango@Sun.COM 	bus_p->bus_hdr_type = PCI_HEADER_ONE;
78110187SKrishna.Elango@Sun.COM 
78210187SKrishna.Elango@Sun.COM 	/* Fake that there are AER logs */
78310187SKrishna.Elango@Sun.COM 	bus_p->bus_aer_off = (uint16_t)-1;
78410187SKrishna.Elango@Sun.COM 
78510187SKrishna.Elango@Sun.COM 	/* Needed only for handle lookup */
78610187SKrishna.Elango@Sun.COM 	bus_p->bus_fm_flags |= PF_FM_READY;
78710187SKrishna.Elango@Sun.COM 
78810187SKrishna.Elango@Sun.COM 	ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p);
78910187SKrishna.Elango@Sun.COM }
79010187SKrishna.Elango@Sun.COM 
79110187SKrishna.Elango@Sun.COM void
79210187SKrishna.Elango@Sun.COM pcie_rc_fini_bus(dev_info_t *dip)
79310187SKrishna.Elango@Sun.COM {
79411245SZhijun.Fu@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip);
79510187SKrishna.Elango@Sun.COM 	ndi_set_bus_private(dip, B_FALSE, NULL, NULL);
79610187SKrishna.Elango@Sun.COM 	kmem_free(bus_p, sizeof (pcie_bus_t));
79710187SKrishna.Elango@Sun.COM }
79810187SKrishna.Elango@Sun.COM 
79910187SKrishna.Elango@Sun.COM /*
80011245SZhijun.Fu@Sun.COM  * partially init pcie_bus_t for device (dip,bdf) for accessing pci
80111245SZhijun.Fu@Sun.COM  * config space
80211245SZhijun.Fu@Sun.COM  *
80311245SZhijun.Fu@Sun.COM  * This routine is invoked during boot, either after creating a devinfo node
80411245SZhijun.Fu@Sun.COM  * (x86 case) or during px driver attach (sparc case); it is also invoked
80511245SZhijun.Fu@Sun.COM  * in hotplug context after a devinfo node is created.
80611245SZhijun.Fu@Sun.COM  *
80711245SZhijun.Fu@Sun.COM  * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL
80811245SZhijun.Fu@Sun.COM  * is set:
80910187SKrishna.Elango@Sun.COM  *
81011245SZhijun.Fu@Sun.COM  * dev_info_t *		<bus_dip>
81111245SZhijun.Fu@Sun.COM  * dev_info_t *		<bus_rp_dip>
81211245SZhijun.Fu@Sun.COM  * ddi_acc_handle_t	bus_cfg_hdl
81311245SZhijun.Fu@Sun.COM  * uint_t		bus_fm_flags
81411245SZhijun.Fu@Sun.COM  * pcie_req_id_t	<bus_bdf>
81511245SZhijun.Fu@Sun.COM  * pcie_req_id_t	<bus_rp_bdf>
81611245SZhijun.Fu@Sun.COM  * uint32_t		<bus_dev_ven_id>
81711245SZhijun.Fu@Sun.COM  * uint8_t		<bus_rev_id>
81811245SZhijun.Fu@Sun.COM  * uint8_t		<bus_hdr_type>
81911245SZhijun.Fu@Sun.COM  * uint16_t		<bus_dev_type>
82011245SZhijun.Fu@Sun.COM  * uint8_t		<bus_bdg_secbus
82111245SZhijun.Fu@Sun.COM  * uint16_t		<bus_pcie_off>
82211245SZhijun.Fu@Sun.COM  * uint16_t		<bus_aer_off>
82311245SZhijun.Fu@Sun.COM  * uint16_t		<bus_pcix_off>
82411245SZhijun.Fu@Sun.COM  * uint16_t		<bus_ecc_ver>
82511245SZhijun.Fu@Sun.COM  * pci_bus_range_t	bus_bus_range
82611245SZhijun.Fu@Sun.COM  * ppb_ranges_t	*	bus_addr_ranges
82711245SZhijun.Fu@Sun.COM  * int			bus_addr_entries
82811245SZhijun.Fu@Sun.COM  * pci_regspec_t *	bus_assigned_addr
82911245SZhijun.Fu@Sun.COM  * int			bus_assigned_entries
83011245SZhijun.Fu@Sun.COM  * pf_data_t *		bus_pfd
83111245SZhijun.Fu@Sun.COM  * int			bus_mps
83211245SZhijun.Fu@Sun.COM  * uint64_t		bus_cfgacc_base
83311245SZhijun.Fu@Sun.COM  * void	*		bus_plat_private
83411245SZhijun.Fu@Sun.COM  *
83511245SZhijun.Fu@Sun.COM  * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL
83611245SZhijun.Fu@Sun.COM  * is set:
83711245SZhijun.Fu@Sun.COM  *
83811245SZhijun.Fu@Sun.COM  * dev_info_t *		bus_dip
83911245SZhijun.Fu@Sun.COM  * dev_info_t *		bus_rp_dip
84011245SZhijun.Fu@Sun.COM  * ddi_acc_handle_t	bus_cfg_hdl
84111245SZhijun.Fu@Sun.COM  * uint_t		bus_fm_flags
84211245SZhijun.Fu@Sun.COM  * pcie_req_id_t	bus_bdf
84311245SZhijun.Fu@Sun.COM  * pcie_req_id_t	bus_rp_bdf
84411245SZhijun.Fu@Sun.COM  * uint32_t		bus_dev_ven_id
84511245SZhijun.Fu@Sun.COM  * uint8_t		bus_rev_id
84611245SZhijun.Fu@Sun.COM  * uint8_t		bus_hdr_type
84711245SZhijun.Fu@Sun.COM  * uint16_t		bus_dev_type
84811245SZhijun.Fu@Sun.COM  * uint8_t		<bus_bdg_secbus>
84911245SZhijun.Fu@Sun.COM  * uint16_t		bus_pcie_off
85011245SZhijun.Fu@Sun.COM  * uint16_t		bus_aer_off
85111245SZhijun.Fu@Sun.COM  * uint16_t		bus_pcix_off
85211245SZhijun.Fu@Sun.COM  * uint16_t		bus_ecc_ver
85311245SZhijun.Fu@Sun.COM  * pci_bus_range_t	<bus_bus_range>
85411245SZhijun.Fu@Sun.COM  * ppb_ranges_t	*	<bus_addr_ranges>
85511245SZhijun.Fu@Sun.COM  * int			<bus_addr_entries>
85611245SZhijun.Fu@Sun.COM  * pci_regspec_t *	<bus_assigned_addr>
85711245SZhijun.Fu@Sun.COM  * int			<bus_assigned_entries>
85811245SZhijun.Fu@Sun.COM  * pf_data_t *		<bus_pfd>
85911245SZhijun.Fu@Sun.COM  * int			bus_mps
86011245SZhijun.Fu@Sun.COM  * uint64_t		bus_cfgacc_base
86111245SZhijun.Fu@Sun.COM  * void	*		<bus_plat_private>
86210187SKrishna.Elango@Sun.COM  */
86311245SZhijun.Fu@Sun.COM 
86410187SKrishna.Elango@Sun.COM pcie_bus_t *
86511245SZhijun.Fu@Sun.COM pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags)
86610187SKrishna.Elango@Sun.COM {
86711245SZhijun.Fu@Sun.COM 	uint16_t	status, base, baseptr, num_cap;
86811245SZhijun.Fu@Sun.COM 	uint32_t	capid;
86911245SZhijun.Fu@Sun.COM 	int		range_size;
87011245SZhijun.Fu@Sun.COM 	pcie_bus_t	*bus_p;
87111245SZhijun.Fu@Sun.COM 	dev_info_t	*rcdip;
87211245SZhijun.Fu@Sun.COM 	dev_info_t	*pdip;
87311245SZhijun.Fu@Sun.COM 	const char	*errstr = NULL;
87410187SKrishna.Elango@Sun.COM 
87511245SZhijun.Fu@Sun.COM 	if (!(flags & PCIE_BUS_INITIAL))
87611245SZhijun.Fu@Sun.COM 		goto initial_done;
87710187SKrishna.Elango@Sun.COM 
87810187SKrishna.Elango@Sun.COM 	bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
87910187SKrishna.Elango@Sun.COM 
88011245SZhijun.Fu@Sun.COM 	bus_p->bus_dip = dip;
88111245SZhijun.Fu@Sun.COM 	bus_p->bus_bdf = bdf;
88210187SKrishna.Elango@Sun.COM 
88311245SZhijun.Fu@Sun.COM 	rcdip = pcie_get_rc_dip(dip);
88411245SZhijun.Fu@Sun.COM 	ASSERT(rcdip != NULL);
88510187SKrishna.Elango@Sun.COM 
88611245SZhijun.Fu@Sun.COM 	/* Save the Vendor ID, Device ID and revision ID */
88711245SZhijun.Fu@Sun.COM 	bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID);
88811245SZhijun.Fu@Sun.COM 	bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID);
88910187SKrishna.Elango@Sun.COM 	/* Save the Header Type */
89011245SZhijun.Fu@Sun.COM 	bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER);
89110187SKrishna.Elango@Sun.COM 	bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
89210187SKrishna.Elango@Sun.COM 
89311245SZhijun.Fu@Sun.COM 	/*
89411245SZhijun.Fu@Sun.COM 	 * Figure out the device type and all the relavant capability offsets
89511245SZhijun.Fu@Sun.COM 	 */
89611245SZhijun.Fu@Sun.COM 	/* set default value */
89711245SZhijun.Fu@Sun.COM 	bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
89810187SKrishna.Elango@Sun.COM 
89911245SZhijun.Fu@Sun.COM 	status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT);
90011245SZhijun.Fu@Sun.COM 	if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP))
90111245SZhijun.Fu@Sun.COM 		goto caps_done; /* capability not supported */
90211245SZhijun.Fu@Sun.COM 
90311245SZhijun.Fu@Sun.COM 	/* Relevant conventional capabilities first */
90411245SZhijun.Fu@Sun.COM 
90511245SZhijun.Fu@Sun.COM 	/* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */
90611245SZhijun.Fu@Sun.COM 	num_cap = 2;
90710923SEvan.Yan@Sun.COM 
90811245SZhijun.Fu@Sun.COM 	switch (bus_p->bus_hdr_type) {
90911245SZhijun.Fu@Sun.COM 	case PCI_HEADER_ZERO:
91011245SZhijun.Fu@Sun.COM 		baseptr = PCI_CONF_CAP_PTR;
91111245SZhijun.Fu@Sun.COM 		break;
91211245SZhijun.Fu@Sun.COM 	case PCI_HEADER_PPB:
91311245SZhijun.Fu@Sun.COM 		baseptr = PCI_BCNF_CAP_PTR;
91411245SZhijun.Fu@Sun.COM 		break;
91511245SZhijun.Fu@Sun.COM 	case PCI_HEADER_CARDBUS:
91611245SZhijun.Fu@Sun.COM 		baseptr = PCI_CBUS_CAP_PTR;
91711245SZhijun.Fu@Sun.COM 		break;
91811245SZhijun.Fu@Sun.COM 	default:
91911245SZhijun.Fu@Sun.COM 		cmn_err(CE_WARN, "%s: unexpected pci header type:%x",
92011245SZhijun.Fu@Sun.COM 		    __func__, bus_p->bus_hdr_type);
92111245SZhijun.Fu@Sun.COM 		goto caps_done;
92210187SKrishna.Elango@Sun.COM 	}
92310187SKrishna.Elango@Sun.COM 
92411245SZhijun.Fu@Sun.COM 	base = baseptr;
92511245SZhijun.Fu@Sun.COM 	for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap;
92611245SZhijun.Fu@Sun.COM 	    base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) {
92711245SZhijun.Fu@Sun.COM 		capid = pci_cfgacc_get8(rcdip, bdf, base);
92811245SZhijun.Fu@Sun.COM 		switch (capid) {
92911245SZhijun.Fu@Sun.COM 		case PCI_CAP_ID_PCI_E:
93011245SZhijun.Fu@Sun.COM 			bus_p->bus_pcie_off = base;
93111245SZhijun.Fu@Sun.COM 			bus_p->bus_dev_type = pci_cfgacc_get16(rcdip, bdf,
93211245SZhijun.Fu@Sun.COM 			    base + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
93311245SZhijun.Fu@Sun.COM 
93411245SZhijun.Fu@Sun.COM 			/* Check and save PCIe hotplug capability information */
93511245SZhijun.Fu@Sun.COM 			if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
93611245SZhijun.Fu@Sun.COM 			    (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP)
93711245SZhijun.Fu@Sun.COM 			    & PCIE_PCIECAP_SLOT_IMPL) &&
93811245SZhijun.Fu@Sun.COM 			    (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP)
93911245SZhijun.Fu@Sun.COM 			    & PCIE_SLOTCAP_HP_CAPABLE))
94011245SZhijun.Fu@Sun.COM 				bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
94110923SEvan.Yan@Sun.COM 
94211245SZhijun.Fu@Sun.COM 			num_cap--;
94311245SZhijun.Fu@Sun.COM 			break;
94411245SZhijun.Fu@Sun.COM 		case PCI_CAP_ID_PCIX:
94511245SZhijun.Fu@Sun.COM 			bus_p->bus_pcix_off = base;
94611245SZhijun.Fu@Sun.COM 			if (PCIE_IS_BDG(bus_p))
94711245SZhijun.Fu@Sun.COM 				bus_p->bus_ecc_ver =
94811245SZhijun.Fu@Sun.COM 				    pci_cfgacc_get16(rcdip, bdf, base +
94911245SZhijun.Fu@Sun.COM 				    PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
95011245SZhijun.Fu@Sun.COM 			else
95111245SZhijun.Fu@Sun.COM 				bus_p->bus_ecc_ver =
95211245SZhijun.Fu@Sun.COM 				    pci_cfgacc_get16(rcdip, bdf, base +
95311245SZhijun.Fu@Sun.COM 				    PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
95411245SZhijun.Fu@Sun.COM 			num_cap--;
95511245SZhijun.Fu@Sun.COM 			break;
95611245SZhijun.Fu@Sun.COM 		default:
95711245SZhijun.Fu@Sun.COM 			break;
95810187SKrishna.Elango@Sun.COM 		}
95910187SKrishna.Elango@Sun.COM 	}
96010187SKrishna.Elango@Sun.COM 
96111245SZhijun.Fu@Sun.COM 	/* Check and save PCI hotplug (SHPC) capability information */
96211245SZhijun.Fu@Sun.COM 	if (PCIE_IS_BDG(bus_p)) {
96311245SZhijun.Fu@Sun.COM 		base = baseptr;
96411245SZhijun.Fu@Sun.COM 		for (base = pci_cfgacc_get8(rcdip, bdf, base);
96511245SZhijun.Fu@Sun.COM 		    base; base = pci_cfgacc_get8(rcdip, bdf,
96611245SZhijun.Fu@Sun.COM 		    base + PCI_CAP_NEXT_PTR)) {
96711245SZhijun.Fu@Sun.COM 			capid = pci_cfgacc_get8(rcdip, bdf, base);
96811245SZhijun.Fu@Sun.COM 			if (capid == PCI_CAP_ID_PCI_HOTPLUG) {
96911245SZhijun.Fu@Sun.COM 				bus_p->bus_pci_hp_off = base;
97011245SZhijun.Fu@Sun.COM 				bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
97111245SZhijun.Fu@Sun.COM 				break;
97211245SZhijun.Fu@Sun.COM 			}
97311245SZhijun.Fu@Sun.COM 		}
97411245SZhijun.Fu@Sun.COM 	}
97511245SZhijun.Fu@Sun.COM 
97611245SZhijun.Fu@Sun.COM 	/* Then, relevant extended capabilities */
97710187SKrishna.Elango@Sun.COM 
97811245SZhijun.Fu@Sun.COM 	if (!PCIE_IS_PCIE(bus_p))
97911245SZhijun.Fu@Sun.COM 		goto caps_done;
98011245SZhijun.Fu@Sun.COM 
98111245SZhijun.Fu@Sun.COM 	/* Extended caps: PCIE_EXT_CAP_ID_AER */
98211245SZhijun.Fu@Sun.COM 	for (base = PCIE_EXT_CAP; base; base = (capid >>
98311245SZhijun.Fu@Sun.COM 	    PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) {
98411245SZhijun.Fu@Sun.COM 		capid = pci_cfgacc_get32(rcdip, bdf, base);
98511245SZhijun.Fu@Sun.COM 		if (capid == PCI_CAP_EINVAL32)
98611245SZhijun.Fu@Sun.COM 			break;
98711245SZhijun.Fu@Sun.COM 		if (((capid >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK)
98811245SZhijun.Fu@Sun.COM 		    == PCIE_EXT_CAP_ID_AER) {
98911245SZhijun.Fu@Sun.COM 			bus_p->bus_aer_off = base;
99011245SZhijun.Fu@Sun.COM 			break;
99111245SZhijun.Fu@Sun.COM 		}
99211245SZhijun.Fu@Sun.COM 	}
99311245SZhijun.Fu@Sun.COM 
99411245SZhijun.Fu@Sun.COM caps_done:
99510187SKrishna.Elango@Sun.COM 	/* save RP dip and RP bdf */
99610187SKrishna.Elango@Sun.COM 	if (PCIE_IS_RP(bus_p)) {
99711245SZhijun.Fu@Sun.COM 		bus_p->bus_rp_dip = dip;
99810187SKrishna.Elango@Sun.COM 		bus_p->bus_rp_bdf = bus_p->bus_bdf;
99910187SKrishna.Elango@Sun.COM 	} else {
100011245SZhijun.Fu@Sun.COM 		for (pdip = ddi_get_parent(dip); pdip;
100110187SKrishna.Elango@Sun.COM 		    pdip = ddi_get_parent(pdip)) {
100210187SKrishna.Elango@Sun.COM 			pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
100310187SKrishna.Elango@Sun.COM 
100410187SKrishna.Elango@Sun.COM 			/*
100511245SZhijun.Fu@Sun.COM 			 * If RP dip and RP bdf in parent's bus_t have
100611245SZhijun.Fu@Sun.COM 			 * been initialized, simply use these instead of
100711245SZhijun.Fu@Sun.COM 			 * continuing up to the RC.
100811245SZhijun.Fu@Sun.COM 			 */
100911245SZhijun.Fu@Sun.COM 			if (parent_bus_p->bus_rp_dip != NULL) {
101011245SZhijun.Fu@Sun.COM 				bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip;
101111245SZhijun.Fu@Sun.COM 				bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf;
101211245SZhijun.Fu@Sun.COM 				break;
101311245SZhijun.Fu@Sun.COM 			}
101411245SZhijun.Fu@Sun.COM 
101511245SZhijun.Fu@Sun.COM 			/*
101610187SKrishna.Elango@Sun.COM 			 * When debugging be aware that some NVIDIA x86
101710187SKrishna.Elango@Sun.COM 			 * architectures have 2 nodes for each RP, One at Bus
101810187SKrishna.Elango@Sun.COM 			 * 0x0 and one at Bus 0x80.  The requester is from Bus
101910187SKrishna.Elango@Sun.COM 			 * 0x80
102010187SKrishna.Elango@Sun.COM 			 */
102110187SKrishna.Elango@Sun.COM 			if (PCIE_IS_ROOT(parent_bus_p)) {
102210187SKrishna.Elango@Sun.COM 				bus_p->bus_rp_dip = pdip;
102310187SKrishna.Elango@Sun.COM 				bus_p->bus_rp_bdf = parent_bus_p->bus_bdf;
102410187SKrishna.Elango@Sun.COM 				break;
102510187SKrishna.Elango@Sun.COM 			}
102610187SKrishna.Elango@Sun.COM 		}
102710187SKrishna.Elango@Sun.COM 	}
102810187SKrishna.Elango@Sun.COM 
102911245SZhijun.Fu@Sun.COM 	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
103011245SZhijun.Fu@Sun.COM 	bus_p->bus_fm_flags = 0;
103111245SZhijun.Fu@Sun.COM 	bus_p->bus_mps = 0;
103210187SKrishna.Elango@Sun.COM 
103311245SZhijun.Fu@Sun.COM 	ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
103411245SZhijun.Fu@Sun.COM 
103511245SZhijun.Fu@Sun.COM 	if (PCIE_IS_HOTPLUG_CAPABLE(dip))
103611245SZhijun.Fu@Sun.COM 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
103710923SEvan.Yan@Sun.COM 		    "hotplug-capable");
103810923SEvan.Yan@Sun.COM 
103911245SZhijun.Fu@Sun.COM initial_done:
104011245SZhijun.Fu@Sun.COM 	if (!(flags & PCIE_BUS_FINAL))
104111245SZhijun.Fu@Sun.COM 		goto final_done;
104211245SZhijun.Fu@Sun.COM 
104311245SZhijun.Fu@Sun.COM 	/* already initialized? */
104411245SZhijun.Fu@Sun.COM 	bus_p = PCIE_DIP2BUS(dip);
104511245SZhijun.Fu@Sun.COM 
104611245SZhijun.Fu@Sun.COM 	/* Save the Range information if device is a switch/bridge */
104711245SZhijun.Fu@Sun.COM 	if (PCIE_IS_BDG(bus_p)) {
104811245SZhijun.Fu@Sun.COM 		/* get "bus_range" property */
104911245SZhijun.Fu@Sun.COM 		range_size = sizeof (pci_bus_range_t);
105011245SZhijun.Fu@Sun.COM 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
105111245SZhijun.Fu@Sun.COM 		    "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
105211245SZhijun.Fu@Sun.COM 		    != DDI_PROP_SUCCESS) {
105311245SZhijun.Fu@Sun.COM 			errstr = "Cannot find \"bus-range\" property";
105411245SZhijun.Fu@Sun.COM 			cmn_err(CE_WARN,
105511245SZhijun.Fu@Sun.COM 			    "PCIE init err info failed BDF 0x%x:%s\n",
105611245SZhijun.Fu@Sun.COM 			    bus_p->bus_bdf, errstr);
105711245SZhijun.Fu@Sun.COM 		}
105811245SZhijun.Fu@Sun.COM 
105911245SZhijun.Fu@Sun.COM 		/* get secondary bus number */
106011245SZhijun.Fu@Sun.COM 		rcdip = pcie_get_rc_dip(dip);
106111245SZhijun.Fu@Sun.COM 		ASSERT(rcdip != NULL);
106210187SKrishna.Elango@Sun.COM 
106311245SZhijun.Fu@Sun.COM 		bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip,
106411245SZhijun.Fu@Sun.COM 		    bus_p->bus_bdf, PCI_BCNF_SECBUS);
106511245SZhijun.Fu@Sun.COM 
106611245SZhijun.Fu@Sun.COM 		/* Get "ranges" property */
106711245SZhijun.Fu@Sun.COM 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
106811245SZhijun.Fu@Sun.COM 		    "ranges", (caddr_t)&bus_p->bus_addr_ranges,
106911245SZhijun.Fu@Sun.COM 		    &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
107011245SZhijun.Fu@Sun.COM 			bus_p->bus_addr_entries = 0;
107111245SZhijun.Fu@Sun.COM 		bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
107211245SZhijun.Fu@Sun.COM 	}
107310187SKrishna.Elango@Sun.COM 
107411245SZhijun.Fu@Sun.COM 	/* save "assigned-addresses" property array, ignore failues */
107511245SZhijun.Fu@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
107611245SZhijun.Fu@Sun.COM 	    "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
107711245SZhijun.Fu@Sun.COM 	    &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
107811245SZhijun.Fu@Sun.COM 		bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
107911245SZhijun.Fu@Sun.COM 	else
108011245SZhijun.Fu@Sun.COM 		bus_p->bus_assigned_entries = 0;
108111245SZhijun.Fu@Sun.COM 
108211245SZhijun.Fu@Sun.COM 	pcie_init_pfd(dip);
108311245SZhijun.Fu@Sun.COM 
108411245SZhijun.Fu@Sun.COM 	pcie_init_plat(dip);
108511245SZhijun.Fu@Sun.COM 
108611245SZhijun.Fu@Sun.COM final_done:
108710187SKrishna.Elango@Sun.COM 
108810187SKrishna.Elango@Sun.COM 	PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
108911245SZhijun.Fu@Sun.COM 	    ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf,
109010187SKrishna.Elango@Sun.COM 	    bus_p->bus_bdg_secbus);
109110187SKrishna.Elango@Sun.COM #ifdef DEBUG
109210187SKrishna.Elango@Sun.COM 	pcie_print_bus(bus_p);
109310187SKrishna.Elango@Sun.COM #endif
109410187SKrishna.Elango@Sun.COM 
109510187SKrishna.Elango@Sun.COM 	return (bus_p);
109611245SZhijun.Fu@Sun.COM }
109711245SZhijun.Fu@Sun.COM 
109811245SZhijun.Fu@Sun.COM /*
109911245SZhijun.Fu@Sun.COM  * Invoked before destroying devinfo node, mostly during hotplug
110011245SZhijun.Fu@Sun.COM  * operation to free pcie_bus_t data structure
110111245SZhijun.Fu@Sun.COM  */
110211245SZhijun.Fu@Sun.COM /* ARGSUSED */
110311245SZhijun.Fu@Sun.COM void
110411245SZhijun.Fu@Sun.COM pcie_fini_bus(dev_info_t *dip, uint8_t flags)
110511245SZhijun.Fu@Sun.COM {
110611245SZhijun.Fu@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
110711245SZhijun.Fu@Sun.COM 	ASSERT(bus_p);
110811245SZhijun.Fu@Sun.COM 
110911245SZhijun.Fu@Sun.COM 	if (flags & PCIE_BUS_INITIAL) {
111011245SZhijun.Fu@Sun.COM 		pcie_fini_plat(dip);
111111245SZhijun.Fu@Sun.COM 		pcie_fini_pfd(dip);
111211245SZhijun.Fu@Sun.COM 
111311245SZhijun.Fu@Sun.COM 		kmem_free(bus_p->bus_assigned_addr,
111411245SZhijun.Fu@Sun.COM 		    (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
111511245SZhijun.Fu@Sun.COM 		kmem_free(bus_p->bus_addr_ranges,
111611245SZhijun.Fu@Sun.COM 		    (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
111711245SZhijun.Fu@Sun.COM 		/* zero out the fields that have been destroyed */
111811245SZhijun.Fu@Sun.COM 		bus_p->bus_assigned_addr = NULL;
111911245SZhijun.Fu@Sun.COM 		bus_p->bus_addr_ranges = NULL;
112011245SZhijun.Fu@Sun.COM 		bus_p->bus_assigned_entries = 0;
112111245SZhijun.Fu@Sun.COM 		bus_p->bus_addr_entries = 0;
112211245SZhijun.Fu@Sun.COM 	}
112311245SZhijun.Fu@Sun.COM 
112411245SZhijun.Fu@Sun.COM 	if (flags & PCIE_BUS_FINAL) {
112511245SZhijun.Fu@Sun.COM 		if (PCIE_IS_HOTPLUG_CAPABLE(dip)) {
112611245SZhijun.Fu@Sun.COM 			(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
112711245SZhijun.Fu@Sun.COM 			    "hotplug-capable");
112811245SZhijun.Fu@Sun.COM 		}
112911245SZhijun.Fu@Sun.COM 
113011245SZhijun.Fu@Sun.COM 		ndi_set_bus_private(dip, B_TRUE, NULL, NULL);
113111245SZhijun.Fu@Sun.COM 		kmem_free(bus_p, sizeof (pcie_bus_t));
113211245SZhijun.Fu@Sun.COM 	}
113310187SKrishna.Elango@Sun.COM }
113410187SKrishna.Elango@Sun.COM 
113510187SKrishna.Elango@Sun.COM int
113610187SKrishna.Elango@Sun.COM pcie_postattach_child(dev_info_t *cdip)
113710187SKrishna.Elango@Sun.COM {
113810187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
113910187SKrishna.Elango@Sun.COM 
114010187SKrishna.Elango@Sun.COM 	if (!bus_p)
114110187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
114210187SKrishna.Elango@Sun.COM 
114310187SKrishna.Elango@Sun.COM 	return (pcie_enable_ce(cdip));
114410187SKrishna.Elango@Sun.COM }
114510187SKrishna.Elango@Sun.COM 
114610187SKrishna.Elango@Sun.COM /*
114710187SKrishna.Elango@Sun.COM  * PCI-Express child device de-initialization.
114810187SKrishna.Elango@Sun.COM  * This function disables generic pci-express interrupts and error
114910187SKrishna.Elango@Sun.COM  * handling.
115010187SKrishna.Elango@Sun.COM  */
115110187SKrishna.Elango@Sun.COM void
115210187SKrishna.Elango@Sun.COM pcie_uninitchild(dev_info_t *cdip)
115310187SKrishna.Elango@Sun.COM {
115410187SKrishna.Elango@Sun.COM 	pcie_disable_errors(cdip);
115511245SZhijun.Fu@Sun.COM 	pcie_fini_cfghdl(cdip);
115611245SZhijun.Fu@Sun.COM }
115711245SZhijun.Fu@Sun.COM 
115811245SZhijun.Fu@Sun.COM /*
115911245SZhijun.Fu@Sun.COM  * find the root complex dip
116011245SZhijun.Fu@Sun.COM  */
116111245SZhijun.Fu@Sun.COM dev_info_t *
116211245SZhijun.Fu@Sun.COM pcie_get_rc_dip(dev_info_t *dip)
116311245SZhijun.Fu@Sun.COM {
116411245SZhijun.Fu@Sun.COM 	dev_info_t *rcdip;
116511245SZhijun.Fu@Sun.COM 	pcie_bus_t *rc_bus_p;
116611245SZhijun.Fu@Sun.COM 
116711245SZhijun.Fu@Sun.COM 	for (rcdip = ddi_get_parent(dip); rcdip;
116811245SZhijun.Fu@Sun.COM 	    rcdip = ddi_get_parent(rcdip)) {
116911245SZhijun.Fu@Sun.COM 		rc_bus_p = PCIE_DIP2BUS(rcdip);
117011245SZhijun.Fu@Sun.COM 		if (rc_bus_p && PCIE_IS_RC(rc_bus_p))
117111245SZhijun.Fu@Sun.COM 			break;
117211245SZhijun.Fu@Sun.COM 	}
117311245SZhijun.Fu@Sun.COM 
117411245SZhijun.Fu@Sun.COM 	return (rcdip);
117511245SZhijun.Fu@Sun.COM }
117611245SZhijun.Fu@Sun.COM 
117711245SZhijun.Fu@Sun.COM static boolean_t
117811245SZhijun.Fu@Sun.COM pcie_is_pci_device(dev_info_t *dip)
117911245SZhijun.Fu@Sun.COM {
118011245SZhijun.Fu@Sun.COM 	dev_info_t	*pdip;
118111245SZhijun.Fu@Sun.COM 	char		*device_type;
118211245SZhijun.Fu@Sun.COM 
118311245SZhijun.Fu@Sun.COM 	pdip = ddi_get_parent(dip);
118411245SZhijun.Fu@Sun.COM 	ASSERT(pdip);
118511245SZhijun.Fu@Sun.COM 
118611245SZhijun.Fu@Sun.COM 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
118711245SZhijun.Fu@Sun.COM 	    "device_type", &device_type) != DDI_PROP_SUCCESS)
118811245SZhijun.Fu@Sun.COM 		return (B_FALSE);
118911245SZhijun.Fu@Sun.COM 
119011245SZhijun.Fu@Sun.COM 	if (strcmp(device_type, "pciex") != 0 &&
119111245SZhijun.Fu@Sun.COM 	    strcmp(device_type, "pci") != 0) {
119211245SZhijun.Fu@Sun.COM 		ddi_prop_free(device_type);
119311245SZhijun.Fu@Sun.COM 		return (B_FALSE);
119411245SZhijun.Fu@Sun.COM 	}
119511245SZhijun.Fu@Sun.COM 
119611245SZhijun.Fu@Sun.COM 	ddi_prop_free(device_type);
119711245SZhijun.Fu@Sun.COM 	return (B_TRUE);
119811245SZhijun.Fu@Sun.COM }
119911245SZhijun.Fu@Sun.COM 
120011245SZhijun.Fu@Sun.COM typedef struct {
120111245SZhijun.Fu@Sun.COM 	boolean_t	init;
120211245SZhijun.Fu@Sun.COM 	uint8_t		flags;
120311245SZhijun.Fu@Sun.COM } pcie_bus_arg_t;
120411245SZhijun.Fu@Sun.COM 
120511245SZhijun.Fu@Sun.COM /*ARGSUSED*/
120611245SZhijun.Fu@Sun.COM static int
120711245SZhijun.Fu@Sun.COM pcie_fab_do_init_fini(dev_info_t *dip, void *arg)
120811245SZhijun.Fu@Sun.COM {
120911245SZhijun.Fu@Sun.COM 	pcie_req_id_t	bdf;
121011245SZhijun.Fu@Sun.COM 	pcie_bus_arg_t	*bus_arg = (pcie_bus_arg_t *)arg;
121111245SZhijun.Fu@Sun.COM 
121211245SZhijun.Fu@Sun.COM 	if (!pcie_is_pci_device(dip))
121311245SZhijun.Fu@Sun.COM 		goto out;
121411245SZhijun.Fu@Sun.COM 
121511245SZhijun.Fu@Sun.COM 	if (bus_arg->init) {
121611245SZhijun.Fu@Sun.COM 		if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS)
121711245SZhijun.Fu@Sun.COM 			goto out;
121811245SZhijun.Fu@Sun.COM 
121911245SZhijun.Fu@Sun.COM 		(void) pcie_init_bus(dip, bdf, bus_arg->flags);
122011245SZhijun.Fu@Sun.COM 	} else {
122111245SZhijun.Fu@Sun.COM 		(void) pcie_fini_bus(dip, bus_arg->flags);
122211245SZhijun.Fu@Sun.COM 	}
122311245SZhijun.Fu@Sun.COM 
122411245SZhijun.Fu@Sun.COM 	return (DDI_WALK_CONTINUE);
122511245SZhijun.Fu@Sun.COM 
122611245SZhijun.Fu@Sun.COM out:
122711245SZhijun.Fu@Sun.COM 	return (DDI_WALK_PRUNECHILD);
122810187SKrishna.Elango@Sun.COM }
122910187SKrishna.Elango@Sun.COM 
123010187SKrishna.Elango@Sun.COM void
123111245SZhijun.Fu@Sun.COM pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags)
123210187SKrishna.Elango@Sun.COM {
123311245SZhijun.Fu@Sun.COM 	int		circular_count;
123411245SZhijun.Fu@Sun.COM 	dev_info_t	*dip = ddi_get_child(rcdip);
123511245SZhijun.Fu@Sun.COM 	pcie_bus_arg_t	arg;
123610187SKrishna.Elango@Sun.COM 
123711245SZhijun.Fu@Sun.COM 	arg.init = B_TRUE;
123811245SZhijun.Fu@Sun.COM 	arg.flags = flags;
123910187SKrishna.Elango@Sun.COM 
124011245SZhijun.Fu@Sun.COM 	ndi_devi_enter(rcdip, &circular_count);
124111245SZhijun.Fu@Sun.COM 	ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
124211245SZhijun.Fu@Sun.COM 	ndi_devi_exit(rcdip, circular_count);
124311245SZhijun.Fu@Sun.COM }
124410923SEvan.Yan@Sun.COM 
124511245SZhijun.Fu@Sun.COM void
124611245SZhijun.Fu@Sun.COM pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags)
124711245SZhijun.Fu@Sun.COM {
124811245SZhijun.Fu@Sun.COM 	int		circular_count;
124911245SZhijun.Fu@Sun.COM 	dev_info_t	*dip = ddi_get_child(rcdip);
125011245SZhijun.Fu@Sun.COM 	pcie_bus_arg_t	arg;
125110923SEvan.Yan@Sun.COM 
125211245SZhijun.Fu@Sun.COM 	arg.init = B_FALSE;
125311245SZhijun.Fu@Sun.COM 	arg.flags = flags;
125410187SKrishna.Elango@Sun.COM 
125511245SZhijun.Fu@Sun.COM 	ndi_devi_enter(rcdip, &circular_count);
125611245SZhijun.Fu@Sun.COM 	ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
125711245SZhijun.Fu@Sun.COM 	ndi_devi_exit(rcdip, circular_count);
125810187SKrishna.Elango@Sun.COM }
125910187SKrishna.Elango@Sun.COM 
126010187SKrishna.Elango@Sun.COM void
126110187SKrishna.Elango@Sun.COM pcie_enable_errors(dev_info_t *dip)
126210187SKrishna.Elango@Sun.COM {
126310187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
126410187SKrishna.Elango@Sun.COM 	uint16_t	reg16, tmp16;
126510187SKrishna.Elango@Sun.COM 	uint32_t	reg32, tmp32;
126610187SKrishna.Elango@Sun.COM 
126710187SKrishna.Elango@Sun.COM 	ASSERT(bus_p);
126810187SKrishna.Elango@Sun.COM 
126910187SKrishna.Elango@Sun.COM 	/*
127010187SKrishna.Elango@Sun.COM 	 * Clear any pending errors
127110187SKrishna.Elango@Sun.COM 	 */
127210187SKrishna.Elango@Sun.COM 	pcie_clear_errors(dip);
127310187SKrishna.Elango@Sun.COM 
127410187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE(bus_p))
127510187SKrishna.Elango@Sun.COM 		return;
127610187SKrishna.Elango@Sun.COM 
127710187SKrishna.Elango@Sun.COM 	/*
127810187SKrishna.Elango@Sun.COM 	 * Enable Baseline Error Handling but leave CE reporting off (poweron
127910187SKrishna.Elango@Sun.COM 	 * default).
128010187SKrishna.Elango@Sun.COM 	 */
128110187SKrishna.Elango@Sun.COM 	if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) !=
128210187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16) {
128310187SKrishna.Elango@Sun.COM 		tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
128410187SKrishna.Elango@Sun.COM 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
128510187SKrishna.Elango@Sun.COM 		    (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
128610187SKrishna.Elango@Sun.COM 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
128710187SKrishna.Elango@Sun.COM 		    (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN));
128810187SKrishna.Elango@Sun.COM 
128910187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
129010187SKrishna.Elango@Sun.COM 		PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
129110187SKrishna.Elango@Sun.COM 	}
129210187SKrishna.Elango@Sun.COM 
129310187SKrishna.Elango@Sun.COM 	/* Enable Root Port Baseline Error Receiving */
129410187SKrishna.Elango@Sun.COM 	if (PCIE_IS_ROOT(bus_p) &&
129510187SKrishna.Elango@Sun.COM 	    (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) !=
129610187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16) {
129710187SKrishna.Elango@Sun.COM 
129810187SKrishna.Elango@Sun.COM 		tmp16 = pcie_serr_disable_flag ?
129910187SKrishna.Elango@Sun.COM 		    (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) :
130010187SKrishna.Elango@Sun.COM 		    pcie_root_ctrl_default;
130110187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16);
130210187SKrishna.Elango@Sun.COM 		PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL,
130310187SKrishna.Elango@Sun.COM 		    reg16);
130410187SKrishna.Elango@Sun.COM 	}
130510187SKrishna.Elango@Sun.COM 
130610187SKrishna.Elango@Sun.COM 	/*
130710187SKrishna.Elango@Sun.COM 	 * Enable PCI-Express Advanced Error Handling if Exists
130810187SKrishna.Elango@Sun.COM 	 */
130910187SKrishna.Elango@Sun.COM 	if (!PCIE_HAS_AER(bus_p))
131010187SKrishna.Elango@Sun.COM 		return;
131110187SKrishna.Elango@Sun.COM 
131210187SKrishna.Elango@Sun.COM 	/* Set Uncorrectable Severity */
131310187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) !=
131410187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
131510187SKrishna.Elango@Sun.COM 		tmp32 = pcie_aer_uce_severity;
131610187SKrishna.Elango@Sun.COM 
131710187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32);
131810187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV,
131910187SKrishna.Elango@Sun.COM 		    reg32);
132010187SKrishna.Elango@Sun.COM 	}
132110187SKrishna.Elango@Sun.COM 
132210187SKrishna.Elango@Sun.COM 	/* Enable Uncorrectable errors */
132310187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) !=
132410187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
132510187SKrishna.Elango@Sun.COM 		tmp32 = pcie_aer_uce_mask;
132610187SKrishna.Elango@Sun.COM 
132710187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32);
132810187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK,
132910187SKrishna.Elango@Sun.COM 		    reg32);
133010187SKrishna.Elango@Sun.COM 	}
133110187SKrishna.Elango@Sun.COM 
133210187SKrishna.Elango@Sun.COM 	/* Enable ECRC generation and checking */
133310187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
133410187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
133510187SKrishna.Elango@Sun.COM 		tmp32 = reg32 | pcie_ecrc_value;
133610187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32);
133710187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32);
133810187SKrishna.Elango@Sun.COM 	}
133910187SKrishna.Elango@Sun.COM 
134010187SKrishna.Elango@Sun.COM 	/* Enable Secondary Uncorrectable errors if this is a bridge */
134110187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE_BDG(bus_p))
134210187SKrishna.Elango@Sun.COM 		goto root;
134310187SKrishna.Elango@Sun.COM 
134410187SKrishna.Elango@Sun.COM 	/* Set Uncorrectable Severity */
134510187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) !=
134610187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
134710187SKrishna.Elango@Sun.COM 		tmp32 = pcie_aer_suce_severity;
134810187SKrishna.Elango@Sun.COM 
134910187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32);
135010187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV,
135110187SKrishna.Elango@Sun.COM 		    reg32);
135210187SKrishna.Elango@Sun.COM 	}
135310187SKrishna.Elango@Sun.COM 
135410187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) !=
135510187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
135610187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask);
135710187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32,
135810187SKrishna.Elango@Sun.COM 		    PCIE_AER_SUCE_MASK, reg32);
135910187SKrishna.Elango@Sun.COM 	}
136010187SKrishna.Elango@Sun.COM 
136110187SKrishna.Elango@Sun.COM root:
136210187SKrishna.Elango@Sun.COM 	/*
136310187SKrishna.Elango@Sun.COM 	 * Enable Root Control this is a Root device
136410187SKrishna.Elango@Sun.COM 	 */
136510187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_ROOT(bus_p))
136610187SKrishna.Elango@Sun.COM 		return;
136710187SKrishna.Elango@Sun.COM 
136810187SKrishna.Elango@Sun.COM 	if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
136910187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16) {
137010187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD,
137110187SKrishna.Elango@Sun.COM 		    pcie_root_error_cmd_default);
137210187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16,
137310187SKrishna.Elango@Sun.COM 		    PCIE_AER_RE_CMD, reg16);
137410187SKrishna.Elango@Sun.COM 	}
137510187SKrishna.Elango@Sun.COM }
137610187SKrishna.Elango@Sun.COM 
137710187SKrishna.Elango@Sun.COM /*
137810187SKrishna.Elango@Sun.COM  * This function is used for enabling CE reporting and setting the AER CE mask.
137910187SKrishna.Elango@Sun.COM  * When called from outside the pcie module it should always be preceded by
138010187SKrishna.Elango@Sun.COM  * a call to pcie_enable_errors.
138110187SKrishna.Elango@Sun.COM  */
138210187SKrishna.Elango@Sun.COM int
138310187SKrishna.Elango@Sun.COM pcie_enable_ce(dev_info_t *dip)
138410187SKrishna.Elango@Sun.COM {
138510187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
138610187SKrishna.Elango@Sun.COM 	uint16_t	device_sts, device_ctl;
138710187SKrishna.Elango@Sun.COM 	uint32_t	tmp_pcie_aer_ce_mask;
138810187SKrishna.Elango@Sun.COM 
138910187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE(bus_p))
139010187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
139110187SKrishna.Elango@Sun.COM 
139210187SKrishna.Elango@Sun.COM 	/*
139310187SKrishna.Elango@Sun.COM 	 * The "pcie_ce_mask" property is used to control both the CE reporting
139410187SKrishna.Elango@Sun.COM 	 * enable field in the device control register and the AER CE mask. We
139510187SKrishna.Elango@Sun.COM 	 * leave CE reporting disabled if pcie_ce_mask is set to -1.
139610187SKrishna.Elango@Sun.COM 	 */
139710187SKrishna.Elango@Sun.COM 
139810187SKrishna.Elango@Sun.COM 	tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
139910187SKrishna.Elango@Sun.COM 	    DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask);
140010187SKrishna.Elango@Sun.COM 
140110187SKrishna.Elango@Sun.COM 	if (tmp_pcie_aer_ce_mask == (uint32_t)-1) {
140210187SKrishna.Elango@Sun.COM 		/*
140310187SKrishna.Elango@Sun.COM 		 * Nothing to do since CE reporting has already been disabled.
140410187SKrishna.Elango@Sun.COM 		 */
140510187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
140610187SKrishna.Elango@Sun.COM 	}
140710187SKrishna.Elango@Sun.COM 
140810187SKrishna.Elango@Sun.COM 	if (PCIE_HAS_AER(bus_p)) {
140910187SKrishna.Elango@Sun.COM 		/* Enable AER CE */
141010187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask);
141110187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK,
141210187SKrishna.Elango@Sun.COM 		    0);
141310187SKrishna.Elango@Sun.COM 
141410187SKrishna.Elango@Sun.COM 		/* Clear any pending AER CE errors */
141510187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1);
141610187SKrishna.Elango@Sun.COM 	}
141710187SKrishna.Elango@Sun.COM 
141810187SKrishna.Elango@Sun.COM 	/* clear any pending CE errors */
141910187SKrishna.Elango@Sun.COM 	if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) !=
142010187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16)
142110187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS,
142210187SKrishna.Elango@Sun.COM 		    device_sts & (~PCIE_DEVSTS_CE_DETECTED));
142310187SKrishna.Elango@Sun.COM 
142410187SKrishna.Elango@Sun.COM 	/* Enable CE reporting */
142510187SKrishna.Elango@Sun.COM 	device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
142610187SKrishna.Elango@Sun.COM 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL,
142710187SKrishna.Elango@Sun.COM 	    (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default);
142810187SKrishna.Elango@Sun.COM 	PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl);
142910187SKrishna.Elango@Sun.COM 
143010187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
143110187SKrishna.Elango@Sun.COM }
143210187SKrishna.Elango@Sun.COM 
143310187SKrishna.Elango@Sun.COM /* ARGSUSED */
143410187SKrishna.Elango@Sun.COM void
143510187SKrishna.Elango@Sun.COM pcie_disable_errors(dev_info_t *dip)
143610187SKrishna.Elango@Sun.COM {
143710187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
143810187SKrishna.Elango@Sun.COM 	uint16_t	device_ctl;
143910187SKrishna.Elango@Sun.COM 	uint32_t	aer_reg;
144010187SKrishna.Elango@Sun.COM 
144110187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE(bus_p))
144210187SKrishna.Elango@Sun.COM 		return;
144310187SKrishna.Elango@Sun.COM 
144410187SKrishna.Elango@Sun.COM 	/*
144510187SKrishna.Elango@Sun.COM 	 * Disable PCI-Express Baseline Error Handling
144610187SKrishna.Elango@Sun.COM 	 */
144710187SKrishna.Elango@Sun.COM 	device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
144810187SKrishna.Elango@Sun.COM 	device_ctl &= ~PCIE_DEVCTL_ERR_MASK;
144910187SKrishna.Elango@Sun.COM 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl);
145010187SKrishna.Elango@Sun.COM 
145110187SKrishna.Elango@Sun.COM 	/*
145210187SKrishna.Elango@Sun.COM 	 * Disable PCI-Express Advanced Error Handling if Exists
145310187SKrishna.Elango@Sun.COM 	 */
145410187SKrishna.Elango@Sun.COM 	if (!PCIE_HAS_AER(bus_p))
145510187SKrishna.Elango@Sun.COM 		goto root;
145610187SKrishna.Elango@Sun.COM 
145710187SKrishna.Elango@Sun.COM 	/* Disable Uncorrectable errors */
145810187SKrishna.Elango@Sun.COM 	PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS);
145910187SKrishna.Elango@Sun.COM 
146010187SKrishna.Elango@Sun.COM 	/* Disable Correctable errors */
146110187SKrishna.Elango@Sun.COM 	PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS);
146210187SKrishna.Elango@Sun.COM 
146310187SKrishna.Elango@Sun.COM 	/* Disable ECRC generation and checking */
146410187SKrishna.Elango@Sun.COM 	if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
146510187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
146610187SKrishna.Elango@Sun.COM 		aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA |
146710187SKrishna.Elango@Sun.COM 		    PCIE_AER_CTL_ECRC_CHECK_ENA);
146810187SKrishna.Elango@Sun.COM 
146910187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg);
147010187SKrishna.Elango@Sun.COM 	}
147110187SKrishna.Elango@Sun.COM 	/*
147210187SKrishna.Elango@Sun.COM 	 * Disable Secondary Uncorrectable errors if this is a bridge
147310187SKrishna.Elango@Sun.COM 	 */
147410187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE_BDG(bus_p))
147510187SKrishna.Elango@Sun.COM 		goto root;
147610187SKrishna.Elango@Sun.COM 
147710187SKrishna.Elango@Sun.COM 	PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS);
147810187SKrishna.Elango@Sun.COM 
147910187SKrishna.Elango@Sun.COM root:
148010187SKrishna.Elango@Sun.COM 	/*
148110187SKrishna.Elango@Sun.COM 	 * disable Root Control this is a Root device
148210187SKrishna.Elango@Sun.COM 	 */
148310187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_ROOT(bus_p))
148410187SKrishna.Elango@Sun.COM 		return;
148510187SKrishna.Elango@Sun.COM 
148610187SKrishna.Elango@Sun.COM 	if (!pcie_serr_disable_flag) {
148710187SKrishna.Elango@Sun.COM 		device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL);
148810187SKrishna.Elango@Sun.COM 		device_ctl &= ~PCIE_ROOT_SYS_ERR;
148910187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl);
149010187SKrishna.Elango@Sun.COM 	}
149110187SKrishna.Elango@Sun.COM 
149210187SKrishna.Elango@Sun.COM 	if (!PCIE_HAS_AER(bus_p))
149310187SKrishna.Elango@Sun.COM 		return;
149410187SKrishna.Elango@Sun.COM 
149510187SKrishna.Elango@Sun.COM 	if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
149610187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16) {
149710187SKrishna.Elango@Sun.COM 		device_ctl &= ~pcie_root_error_cmd_default;
149810187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl);
149910187SKrishna.Elango@Sun.COM 	}
150010187SKrishna.Elango@Sun.COM }
150110187SKrishna.Elango@Sun.COM 
150210187SKrishna.Elango@Sun.COM /*
150310187SKrishna.Elango@Sun.COM  * Extract bdf from "reg" property.
150410187SKrishna.Elango@Sun.COM  */
150510187SKrishna.Elango@Sun.COM int
150610187SKrishna.Elango@Sun.COM pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf)
150710187SKrishna.Elango@Sun.COM {
150810187SKrishna.Elango@Sun.COM 	pci_regspec_t	*regspec;
150910187SKrishna.Elango@Sun.COM 	int		reglen;
151010187SKrishna.Elango@Sun.COM 
151110187SKrishna.Elango@Sun.COM 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
151210187SKrishna.Elango@Sun.COM 	    "reg", (int **)&regspec, (uint_t *)&reglen) != DDI_SUCCESS)
151310187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
151410187SKrishna.Elango@Sun.COM 
151510187SKrishna.Elango@Sun.COM 	if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) {
151610187SKrishna.Elango@Sun.COM 		ddi_prop_free(regspec);
151710187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
151810187SKrishna.Elango@Sun.COM 	}
151910187SKrishna.Elango@Sun.COM 
152010187SKrishna.Elango@Sun.COM 	/* Get phys_hi from first element.  All have same bdf. */
152110187SKrishna.Elango@Sun.COM 	*bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8;
152210187SKrishna.Elango@Sun.COM 
152310187SKrishna.Elango@Sun.COM 	ddi_prop_free(regspec);
152410187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
152510187SKrishna.Elango@Sun.COM }
152610187SKrishna.Elango@Sun.COM 
152710187SKrishna.Elango@Sun.COM dev_info_t *
152810187SKrishna.Elango@Sun.COM pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip)
152910187SKrishna.Elango@Sun.COM {
153010187SKrishna.Elango@Sun.COM 	dev_info_t *cdip = rdip;
153110187SKrishna.Elango@Sun.COM 
153210187SKrishna.Elango@Sun.COM 	for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip))
153310187SKrishna.Elango@Sun.COM 		;
153410187SKrishna.Elango@Sun.COM 
153510187SKrishna.Elango@Sun.COM 	return (cdip);
153610187SKrishna.Elango@Sun.COM }
153710187SKrishna.Elango@Sun.COM 
153810187SKrishna.Elango@Sun.COM uint32_t
153910187SKrishna.Elango@Sun.COM pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
154010187SKrishna.Elango@Sun.COM {
154110187SKrishna.Elango@Sun.COM 	dev_info_t *cdip;
154210187SKrishna.Elango@Sun.COM 
154310187SKrishna.Elango@Sun.COM 	/*
154410187SKrishna.Elango@Sun.COM 	 * As part of the probing, the PCI fcode interpreter may setup a DMA
154510187SKrishna.Elango@Sun.COM 	 * request if a given card has a fcode on it using dip and rdip of the
154610923SEvan.Yan@Sun.COM 	 * hotplug connector i.e, dip and rdip of px/pcieb driver. In this
154710187SKrishna.Elango@Sun.COM 	 * case, return a invalid value for the bdf since we cannot get to the
154810187SKrishna.Elango@Sun.COM 	 * bdf value of the actual device which will be initiating this DMA.
154910187SKrishna.Elango@Sun.COM 	 */
155010187SKrishna.Elango@Sun.COM 	if (rdip == dip)
155110187SKrishna.Elango@Sun.COM 		return (PCIE_INVALID_BDF);
155210187SKrishna.Elango@Sun.COM 
155310187SKrishna.Elango@Sun.COM 	cdip = pcie_get_my_childs_dip(dip, rdip);
155410187SKrishna.Elango@Sun.COM 
155510187SKrishna.Elango@Sun.COM 	/*
155610187SKrishna.Elango@Sun.COM 	 * For a given rdip, return the bdf value of dip's (px or pcieb)
155710187SKrishna.Elango@Sun.COM 	 * immediate child or secondary bus-id if dip is a PCIe2PCI bridge.
155810187SKrishna.Elango@Sun.COM 	 *
155910187SKrishna.Elango@Sun.COM 	 * XXX - For now, return a invalid bdf value for all PCI and PCI-X
156010187SKrishna.Elango@Sun.COM 	 * devices since this needs more work.
156110187SKrishna.Elango@Sun.COM 	 */
156210187SKrishna.Elango@Sun.COM 	return (PCI_GET_PCIE2PCI_SECBUS(cdip) ?
156310187SKrishna.Elango@Sun.COM 	    PCIE_INVALID_BDF : PCI_GET_BDF(cdip));
156410187SKrishna.Elango@Sun.COM }
156510187SKrishna.Elango@Sun.COM 
156610187SKrishna.Elango@Sun.COM uint32_t
156710187SKrishna.Elango@Sun.COM pcie_get_aer_uce_mask() {
156810187SKrishna.Elango@Sun.COM 	return (pcie_aer_uce_mask);
156910187SKrishna.Elango@Sun.COM }
157010187SKrishna.Elango@Sun.COM uint32_t
157110187SKrishna.Elango@Sun.COM pcie_get_aer_ce_mask() {
157210187SKrishna.Elango@Sun.COM 	return (pcie_aer_ce_mask);
157310187SKrishna.Elango@Sun.COM }
157410187SKrishna.Elango@Sun.COM uint32_t
157510187SKrishna.Elango@Sun.COM pcie_get_aer_suce_mask() {
157610187SKrishna.Elango@Sun.COM 	return (pcie_aer_suce_mask);
157710187SKrishna.Elango@Sun.COM }
157810187SKrishna.Elango@Sun.COM uint32_t
157910187SKrishna.Elango@Sun.COM pcie_get_serr_mask() {
158010187SKrishna.Elango@Sun.COM 	return (pcie_serr_disable_flag);
158110187SKrishna.Elango@Sun.COM }
158210187SKrishna.Elango@Sun.COM 
158310187SKrishna.Elango@Sun.COM void
158410187SKrishna.Elango@Sun.COM pcie_set_aer_uce_mask(uint32_t mask) {
158510187SKrishna.Elango@Sun.COM 	pcie_aer_uce_mask = mask;
158610187SKrishna.Elango@Sun.COM 	if (mask & PCIE_AER_UCE_UR)
158710187SKrishna.Elango@Sun.COM 		pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN;
158810187SKrishna.Elango@Sun.COM 	else
158910187SKrishna.Elango@Sun.COM 		pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN;
159010187SKrishna.Elango@Sun.COM 
159110187SKrishna.Elango@Sun.COM 	if (mask & PCIE_AER_UCE_ECRC)
159210187SKrishna.Elango@Sun.COM 		pcie_ecrc_value = 0;
159310187SKrishna.Elango@Sun.COM }
159410187SKrishna.Elango@Sun.COM 
159510187SKrishna.Elango@Sun.COM void
159610187SKrishna.Elango@Sun.COM pcie_set_aer_ce_mask(uint32_t mask) {
159710187SKrishna.Elango@Sun.COM 	pcie_aer_ce_mask = mask;
159810187SKrishna.Elango@Sun.COM }
159910187SKrishna.Elango@Sun.COM void
160010187SKrishna.Elango@Sun.COM pcie_set_aer_suce_mask(uint32_t mask) {
160110187SKrishna.Elango@Sun.COM 	pcie_aer_suce_mask = mask;
160210187SKrishna.Elango@Sun.COM }
160310187SKrishna.Elango@Sun.COM void
160410187SKrishna.Elango@Sun.COM pcie_set_serr_mask(uint32_t mask) {
160510187SKrishna.Elango@Sun.COM 	pcie_serr_disable_flag = mask;
160610187SKrishna.Elango@Sun.COM }
160710187SKrishna.Elango@Sun.COM 
160810187SKrishna.Elango@Sun.COM /*
160910187SKrishna.Elango@Sun.COM  * Is the rdip a child of dip.	Used for checking certain CTLOPS from bubbling
161010187SKrishna.Elango@Sun.COM  * up erronously.  Ex.	ISA ctlops to a PCI-PCI Bridge.
161110187SKrishna.Elango@Sun.COM  */
161210187SKrishna.Elango@Sun.COM boolean_t
161310187SKrishna.Elango@Sun.COM pcie_is_child(dev_info_t *dip, dev_info_t *rdip)
161410187SKrishna.Elango@Sun.COM {
161510187SKrishna.Elango@Sun.COM 	dev_info_t	*cdip = ddi_get_child(dip);
161610187SKrishna.Elango@Sun.COM 	for (; cdip; cdip = ddi_get_next_sibling(cdip))
161710187SKrishna.Elango@Sun.COM 		if (cdip == rdip)
161810187SKrishna.Elango@Sun.COM 			break;
161910187SKrishna.Elango@Sun.COM 	return (cdip != NULL);
162010187SKrishna.Elango@Sun.COM }
162110187SKrishna.Elango@Sun.COM 
162210187SKrishna.Elango@Sun.COM boolean_t
162310187SKrishna.Elango@Sun.COM pcie_is_link_disabled(dev_info_t *dip)
162410187SKrishna.Elango@Sun.COM {
162510187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
162610187SKrishna.Elango@Sun.COM 
162710187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p)) {
162810187SKrishna.Elango@Sun.COM 		if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) &
162910187SKrishna.Elango@Sun.COM 		    PCIE_LINKCTL_LINK_DISABLE)
163010187SKrishna.Elango@Sun.COM 			return (B_TRUE);
163110187SKrishna.Elango@Sun.COM 	}
163210187SKrishna.Elango@Sun.COM 	return (B_FALSE);
163310187SKrishna.Elango@Sun.COM }
163410187SKrishna.Elango@Sun.COM 
163510187SKrishna.Elango@Sun.COM /*
163610187SKrishna.Elango@Sun.COM  * Initialize the MPS for a root port.
163710187SKrishna.Elango@Sun.COM  *
163810187SKrishna.Elango@Sun.COM  * dip - dip of root port device.
163910187SKrishna.Elango@Sun.COM  */
164010187SKrishna.Elango@Sun.COM void
164110187SKrishna.Elango@Sun.COM pcie_init_root_port_mps(dev_info_t *dip)
164210187SKrishna.Elango@Sun.COM {
164310187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
164410187SKrishna.Elango@Sun.COM 	int rp_cap, max_supported = pcie_max_mps;
164510187SKrishna.Elango@Sun.COM 
164610187SKrishna.Elango@Sun.COM 	(void) pcie_get_fabric_mps(ddi_get_parent(dip),
164710187SKrishna.Elango@Sun.COM 	    ddi_get_child(dip), &max_supported);
164810187SKrishna.Elango@Sun.COM 
164910187SKrishna.Elango@Sun.COM 	rp_cap = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL,
165010187SKrishna.Elango@Sun.COM 	    bus_p->bus_pcie_off, PCIE_DEVCAP) &
165110187SKrishna.Elango@Sun.COM 	    PCIE_DEVCAP_MAX_PAYLOAD_MASK;
165210187SKrishna.Elango@Sun.COM 
165310187SKrishna.Elango@Sun.COM 	if (rp_cap < max_supported)
165410187SKrishna.Elango@Sun.COM 		max_supported = rp_cap;
165510187SKrishna.Elango@Sun.COM 
165610187SKrishna.Elango@Sun.COM 	bus_p->bus_mps = max_supported;
165710187SKrishna.Elango@Sun.COM 	(void) pcie_initchild_mps(dip);
165810187SKrishna.Elango@Sun.COM }
165910187SKrishna.Elango@Sun.COM 
166010187SKrishna.Elango@Sun.COM /*
166110187SKrishna.Elango@Sun.COM  * Initialize the Maximum Payload Size of a device.
166210187SKrishna.Elango@Sun.COM  *
166310187SKrishna.Elango@Sun.COM  * cdip - dip of device.
166410187SKrishna.Elango@Sun.COM  *
166510187SKrishna.Elango@Sun.COM  * returns - DDI_SUCCESS or DDI_FAILURE
166610187SKrishna.Elango@Sun.COM  */
166710187SKrishna.Elango@Sun.COM int
166810187SKrishna.Elango@Sun.COM pcie_initchild_mps(dev_info_t *cdip)
166910187SKrishna.Elango@Sun.COM {
167010187SKrishna.Elango@Sun.COM 	int		max_payload_size;
167110187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p;
167210187SKrishna.Elango@Sun.COM 	dev_info_t	*pdip = ddi_get_parent(cdip);
167310923SEvan.Yan@Sun.COM 	uint8_t		dev_type;
167410187SKrishna.Elango@Sun.COM 
167510187SKrishna.Elango@Sun.COM 	bus_p = PCIE_DIP2BUS(cdip);
167610187SKrishna.Elango@Sun.COM 	if (bus_p == NULL) {
167710187SKrishna.Elango@Sun.COM 		PCIE_DBG("%s: BUS not found.\n",
167810187SKrishna.Elango@Sun.COM 		    ddi_driver_name(cdip));
167910187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
168010187SKrishna.Elango@Sun.COM 	}
168110187SKrishna.Elango@Sun.COM 
168210923SEvan.Yan@Sun.COM 	dev_type = bus_p->bus_dev_type;
168310923SEvan.Yan@Sun.COM 
168410923SEvan.Yan@Sun.COM 	/*
168510923SEvan.Yan@Sun.COM 	 * For ARI Devices, only function zero's MPS needs to be set.
168610923SEvan.Yan@Sun.COM 	 */
168710923SEvan.Yan@Sun.COM 	if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
168810923SEvan.Yan@Sun.COM 	    (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) {
168910923SEvan.Yan@Sun.COM 		pcie_req_id_t child_bdf;
169010923SEvan.Yan@Sun.COM 
169110923SEvan.Yan@Sun.COM 		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
169210923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
169310923SEvan.Yan@Sun.COM 		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0)
169410923SEvan.Yan@Sun.COM 			return (DDI_SUCCESS);
169510923SEvan.Yan@Sun.COM 	}
169610923SEvan.Yan@Sun.COM 
169710187SKrishna.Elango@Sun.COM 	if (PCIE_IS_RP(bus_p)) {
169810187SKrishna.Elango@Sun.COM 		/*
169910187SKrishna.Elango@Sun.COM 		 * If this device is a root port, then the mps scan
170010187SKrishna.Elango@Sun.COM 		 * saved the mps in the root ports bus_p.
170110187SKrishna.Elango@Sun.COM 		 */
170210187SKrishna.Elango@Sun.COM 		max_payload_size = bus_p->bus_mps;
170310187SKrishna.Elango@Sun.COM 	} else {
170410187SKrishna.Elango@Sun.COM 		/*
170510187SKrishna.Elango@Sun.COM 		 * If the device is not a root port, then the mps of
170610187SKrishna.Elango@Sun.COM 		 * its parent should be used.
170710187SKrishna.Elango@Sun.COM 		 */
170810187SKrishna.Elango@Sun.COM 		pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
170910187SKrishna.Elango@Sun.COM 		max_payload_size = parent_bus_p->bus_mps;
171010187SKrishna.Elango@Sun.COM 	}
171110187SKrishna.Elango@Sun.COM 
171210187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p) && (max_payload_size >= 0)) {
171310187SKrishna.Elango@Sun.COM 		pcie_bus_t *rootp_bus_p = PCIE_DIP2BUS(bus_p->bus_rp_dip);
171410187SKrishna.Elango@Sun.COM 		uint16_t mask, dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL),
171510187SKrishna.Elango@Sun.COM 		    mps = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) &
171610187SKrishna.Elango@Sun.COM 		    PCIE_DEVCAP_MAX_PAYLOAD_MASK;
171710187SKrishna.Elango@Sun.COM 
171810187SKrishna.Elango@Sun.COM 		mps = MIN(mps, (uint16_t)max_payload_size);
171910187SKrishna.Elango@Sun.COM 
172010187SKrishna.Elango@Sun.COM 		/*
172110187SKrishna.Elango@Sun.COM 		 * If the MPS to be set is less than the root ports
172210187SKrishna.Elango@Sun.COM 		 * MPS, then MRRS will have to be set the same as MPS.
172310187SKrishna.Elango@Sun.COM 		 */
172410187SKrishna.Elango@Sun.COM 		mask = ((mps < rootp_bus_p->bus_mps) ?
172510187SKrishna.Elango@Sun.COM 		    PCIE_DEVCTL_MAX_READ_REQ_MASK : 0) |
172610187SKrishna.Elango@Sun.COM 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK;
172710187SKrishna.Elango@Sun.COM 
172810187SKrishna.Elango@Sun.COM 		dev_ctrl &= ~mask;
172910187SKrishna.Elango@Sun.COM 		mask = ((mps < rootp_bus_p->bus_mps)
173010187SKrishna.Elango@Sun.COM 		    ? mps << PCIE_DEVCTL_MAX_READ_REQ_SHIFT : 0)
173110187SKrishna.Elango@Sun.COM 		    | (mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT);
173210187SKrishna.Elango@Sun.COM 
173310187SKrishna.Elango@Sun.COM 		dev_ctrl |= mask;
173410187SKrishna.Elango@Sun.COM 
173510187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl);
173610187SKrishna.Elango@Sun.COM 
173710187SKrishna.Elango@Sun.COM 		bus_p->bus_mps = mps;
173810187SKrishna.Elango@Sun.COM 	}
173910923SEvan.Yan@Sun.COM 
174010187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
174110187SKrishna.Elango@Sun.COM }
174210187SKrishna.Elango@Sun.COM 
174310187SKrishna.Elango@Sun.COM /*
174410187SKrishna.Elango@Sun.COM  * Scans a device tree/branch for a maximum payload size capabilities.
174510187SKrishna.Elango@Sun.COM  *
174610187SKrishna.Elango@Sun.COM  * rc_dip - dip of Root Complex.
174710187SKrishna.Elango@Sun.COM  * dip - dip of device where scan will begin.
174810187SKrishna.Elango@Sun.COM  * max_supported (IN) - maximum allowable MPS.
174910187SKrishna.Elango@Sun.COM  * max_supported (OUT) - maximum payload size capability of fabric.
175010187SKrishna.Elango@Sun.COM  */
175110187SKrishna.Elango@Sun.COM void
175210187SKrishna.Elango@Sun.COM pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
175310187SKrishna.Elango@Sun.COM {
175410187SKrishna.Elango@Sun.COM 	if (dip == NULL)
175510187SKrishna.Elango@Sun.COM 		return;
175610187SKrishna.Elango@Sun.COM 
175710187SKrishna.Elango@Sun.COM 	/*
175810187SKrishna.Elango@Sun.COM 	 * Perform a fabric scan to obtain Maximum Payload Capabilities
175910187SKrishna.Elango@Sun.COM 	 */
176010187SKrishna.Elango@Sun.COM 	(void) pcie_scan_mps(rc_dip, dip, max_supported);
176110187SKrishna.Elango@Sun.COM 
176210187SKrishna.Elango@Sun.COM 	PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported);
176310187SKrishna.Elango@Sun.COM }
176410187SKrishna.Elango@Sun.COM 
176510187SKrishna.Elango@Sun.COM /*
176610187SKrishna.Elango@Sun.COM  * Scans fabric and determines Maximum Payload Size based on
176710187SKrishna.Elango@Sun.COM  * highest common denominator alogorithm
176810187SKrishna.Elango@Sun.COM  */
176910187SKrishna.Elango@Sun.COM static void
177010187SKrishna.Elango@Sun.COM pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
177110187SKrishna.Elango@Sun.COM {
177210187SKrishna.Elango@Sun.COM 	int circular_count;
177310187SKrishna.Elango@Sun.COM 	pcie_max_supported_t max_pay_load_supported;
177410187SKrishna.Elango@Sun.COM 
177510187SKrishna.Elango@Sun.COM 	max_pay_load_supported.dip = rc_dip;
177610187SKrishna.Elango@Sun.COM 	max_pay_load_supported.highest_common_mps = *max_supported;
177710187SKrishna.Elango@Sun.COM 
177810187SKrishna.Elango@Sun.COM 	ndi_devi_enter(ddi_get_parent(dip), &circular_count);
177910187SKrishna.Elango@Sun.COM 	ddi_walk_devs(dip, pcie_get_max_supported,
178010187SKrishna.Elango@Sun.COM 	    (void *)&max_pay_load_supported);
178110187SKrishna.Elango@Sun.COM 	ndi_devi_exit(ddi_get_parent(dip), circular_count);
178210923SEvan.Yan@Sun.COM 
178310187SKrishna.Elango@Sun.COM 	*max_supported = max_pay_load_supported.highest_common_mps;
178410187SKrishna.Elango@Sun.COM }
178510187SKrishna.Elango@Sun.COM 
178610187SKrishna.Elango@Sun.COM /*
178710187SKrishna.Elango@Sun.COM  * Called as part of the Maximum Payload Size scan.
178810187SKrishna.Elango@Sun.COM  */
178910187SKrishna.Elango@Sun.COM static int
179010187SKrishna.Elango@Sun.COM pcie_get_max_supported(dev_info_t *dip, void *arg)
179110187SKrishna.Elango@Sun.COM {
179210187SKrishna.Elango@Sun.COM 	uint32_t max_supported;
179310187SKrishna.Elango@Sun.COM 	uint16_t cap_ptr;
179410187SKrishna.Elango@Sun.COM 	pcie_max_supported_t *current = (pcie_max_supported_t *)arg;
179510187SKrishna.Elango@Sun.COM 	pci_regspec_t *reg;
179610187SKrishna.Elango@Sun.COM 	int rlen;
179710187SKrishna.Elango@Sun.COM 	caddr_t virt;
179810187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t config_handle;
179910187SKrishna.Elango@Sun.COM 
180010187SKrishna.Elango@Sun.COM 	if (ddi_get_child(current->dip) == NULL) {
180110187SKrishna.Elango@Sun.COM 		goto fail1;
180210187SKrishna.Elango@Sun.COM 	}
180310187SKrishna.Elango@Sun.COM 
180410187SKrishna.Elango@Sun.COM 	if (pcie_dev(dip) == DDI_FAILURE) {
180510187SKrishna.Elango@Sun.COM 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  "
180610187SKrishna.Elango@Sun.COM 		    "Not a PCIe dev\n", ddi_driver_name(dip));
180710187SKrishna.Elango@Sun.COM 		goto fail1;
180810187SKrishna.Elango@Sun.COM 	}
180910187SKrishna.Elango@Sun.COM 
181010187SKrishna.Elango@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
181110187SKrishna.Elango@Sun.COM 	    (caddr_t)&reg, &rlen) != DDI_PROP_SUCCESS) {
181210187SKrishna.Elango@Sun.COM 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  "
181310187SKrishna.Elango@Sun.COM 		    "Can not read reg\n", ddi_driver_name(dip));
181410187SKrishna.Elango@Sun.COM 		goto fail1;
181510187SKrishna.Elango@Sun.COM 	}
181610187SKrishna.Elango@Sun.COM 
181710187SKrishna.Elango@Sun.COM 	if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt,
181810187SKrishna.Elango@Sun.COM 	    &config_handle) != DDI_SUCCESS) {
181910187SKrishna.Elango@Sun.COM 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  pcie_map_phys "
182010187SKrishna.Elango@Sun.COM 		    "failed\n", ddi_driver_name(dip));
182110187SKrishna.Elango@Sun.COM 		goto fail2;
182210187SKrishna.Elango@Sun.COM 	}
182310187SKrishna.Elango@Sun.COM 
182410187SKrishna.Elango@Sun.COM 	if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
182510187SKrishna.Elango@Sun.COM 	    DDI_FAILURE) {
182610187SKrishna.Elango@Sun.COM 		goto fail3;
182710187SKrishna.Elango@Sun.COM 	}
182810187SKrishna.Elango@Sun.COM 
182910187SKrishna.Elango@Sun.COM 	max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
183010187SKrishna.Elango@Sun.COM 	    PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK;
183110187SKrishna.Elango@Sun.COM 
183210187SKrishna.Elango@Sun.COM 	PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip),
183310187SKrishna.Elango@Sun.COM 	    max_supported);
183410187SKrishna.Elango@Sun.COM 
183510187SKrishna.Elango@Sun.COM 	if (max_supported < current->highest_common_mps)
183610187SKrishna.Elango@Sun.COM 		current->highest_common_mps = max_supported;
183710187SKrishna.Elango@Sun.COM 
183810187SKrishna.Elango@Sun.COM fail3:
183910187SKrishna.Elango@Sun.COM 	pcie_unmap_phys(&config_handle, reg);
184010187SKrishna.Elango@Sun.COM fail2:
184110187SKrishna.Elango@Sun.COM 	kmem_free(reg, rlen);
184210187SKrishna.Elango@Sun.COM fail1:
184310187SKrishna.Elango@Sun.COM 	return (DDI_WALK_CONTINUE);
184410187SKrishna.Elango@Sun.COM }
184510187SKrishna.Elango@Sun.COM 
184610187SKrishna.Elango@Sun.COM /*
184710187SKrishna.Elango@Sun.COM  * Determines if there are any root ports attached to a root complex.
184810187SKrishna.Elango@Sun.COM  *
184910187SKrishna.Elango@Sun.COM  * dip - dip of root complex
185010187SKrishna.Elango@Sun.COM  *
185110187SKrishna.Elango@Sun.COM  * Returns - DDI_SUCCESS if there is at least one root port otherwise
185210923SEvan.Yan@Sun.COM  *	     DDI_FAILURE.
185310187SKrishna.Elango@Sun.COM  */
185410187SKrishna.Elango@Sun.COM int
185510187SKrishna.Elango@Sun.COM pcie_root_port(dev_info_t *dip)
185610187SKrishna.Elango@Sun.COM {
185710187SKrishna.Elango@Sun.COM 	int port_type;
185810187SKrishna.Elango@Sun.COM 	uint16_t cap_ptr;
185910187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t config_handle;
186010187SKrishna.Elango@Sun.COM 	dev_info_t *cdip = ddi_get_child(dip);
186110187SKrishna.Elango@Sun.COM 
186210187SKrishna.Elango@Sun.COM 	/*
186310187SKrishna.Elango@Sun.COM 	 * Determine if any of the children of the passed in dip
186410187SKrishna.Elango@Sun.COM 	 * are root ports.
186510187SKrishna.Elango@Sun.COM 	 */
186610187SKrishna.Elango@Sun.COM 	for (; cdip; cdip = ddi_get_next_sibling(cdip)) {
186710187SKrishna.Elango@Sun.COM 
186810187SKrishna.Elango@Sun.COM 		if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS)
186910187SKrishna.Elango@Sun.COM 			continue;
187010187SKrishna.Elango@Sun.COM 
187110187SKrishna.Elango@Sun.COM 		if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E,
187210187SKrishna.Elango@Sun.COM 		    &cap_ptr)) == DDI_FAILURE) {
187310187SKrishna.Elango@Sun.COM 			pci_config_teardown(&config_handle);
187410187SKrishna.Elango@Sun.COM 			continue;
187510187SKrishna.Elango@Sun.COM 		}
187610187SKrishna.Elango@Sun.COM 
187710187SKrishna.Elango@Sun.COM 		port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
187810187SKrishna.Elango@Sun.COM 		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
187910187SKrishna.Elango@Sun.COM 
188010187SKrishna.Elango@Sun.COM 		pci_config_teardown(&config_handle);
188110187SKrishna.Elango@Sun.COM 
188210187SKrishna.Elango@Sun.COM 		if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT)
188310187SKrishna.Elango@Sun.COM 			return (DDI_SUCCESS);
188410187SKrishna.Elango@Sun.COM 	}
188510187SKrishna.Elango@Sun.COM 
188610187SKrishna.Elango@Sun.COM 	/* No root ports were found */
188710187SKrishna.Elango@Sun.COM 
188810187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
188910187SKrishna.Elango@Sun.COM }
189010187SKrishna.Elango@Sun.COM 
189110187SKrishna.Elango@Sun.COM /*
189210187SKrishna.Elango@Sun.COM  * Function that determines if a device a PCIe device.
189310187SKrishna.Elango@Sun.COM  *
189410187SKrishna.Elango@Sun.COM  * dip - dip of device.
189510187SKrishna.Elango@Sun.COM  *
189610187SKrishna.Elango@Sun.COM  * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE.
189710187SKrishna.Elango@Sun.COM  */
189810187SKrishna.Elango@Sun.COM int
189910187SKrishna.Elango@Sun.COM pcie_dev(dev_info_t *dip)
190010187SKrishna.Elango@Sun.COM {
190110187SKrishna.Elango@Sun.COM 	/* get parent device's device_type property */
190210187SKrishna.Elango@Sun.COM 	char *device_type;
190310187SKrishna.Elango@Sun.COM 	int rc = DDI_FAILURE;
190410187SKrishna.Elango@Sun.COM 	dev_info_t *pdip = ddi_get_parent(dip);
190510187SKrishna.Elango@Sun.COM 
190610187SKrishna.Elango@Sun.COM 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
190710187SKrishna.Elango@Sun.COM 	    DDI_PROP_DONTPASS, "device_type", &device_type)
190810187SKrishna.Elango@Sun.COM 	    != DDI_PROP_SUCCESS) {
190910187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
191010187SKrishna.Elango@Sun.COM 	}
191110187SKrishna.Elango@Sun.COM 
191210187SKrishna.Elango@Sun.COM 	if (strcmp(device_type, "pciex") == 0)
191310187SKrishna.Elango@Sun.COM 		rc = DDI_SUCCESS;
191410187SKrishna.Elango@Sun.COM 	else
191510187SKrishna.Elango@Sun.COM 		rc = DDI_FAILURE;
191610187SKrishna.Elango@Sun.COM 
191710187SKrishna.Elango@Sun.COM 	ddi_prop_free(device_type);
191810187SKrishna.Elango@Sun.COM 	return (rc);
191910187SKrishna.Elango@Sun.COM }
192010187SKrishna.Elango@Sun.COM 
192110187SKrishna.Elango@Sun.COM /*
192210187SKrishna.Elango@Sun.COM  * Function to map in a device's memory space.
192310187SKrishna.Elango@Sun.COM  */
192410187SKrishna.Elango@Sun.COM static int
192510187SKrishna.Elango@Sun.COM pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
192610187SKrishna.Elango@Sun.COM     caddr_t *addrp, ddi_acc_handle_t *handlep)
192710187SKrishna.Elango@Sun.COM {
192810187SKrishna.Elango@Sun.COM 	ddi_map_req_t mr;
192910187SKrishna.Elango@Sun.COM 	ddi_acc_hdl_t *hp;
193010187SKrishna.Elango@Sun.COM 	int result;
193110187SKrishna.Elango@Sun.COM 	ddi_device_acc_attr_t attr;
193210187SKrishna.Elango@Sun.COM 
193310187SKrishna.Elango@Sun.COM 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
193410187SKrishna.Elango@Sun.COM 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
193510187SKrishna.Elango@Sun.COM 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
193610187SKrishna.Elango@Sun.COM 	attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
193710187SKrishna.Elango@Sun.COM 
193810187SKrishna.Elango@Sun.COM 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
193910187SKrishna.Elango@Sun.COM 	hp = impl_acc_hdl_get(*handlep);
194010187SKrishna.Elango@Sun.COM 	hp->ah_vers = VERS_ACCHDL;
194110187SKrishna.Elango@Sun.COM 	hp->ah_dip = dip;
194210187SKrishna.Elango@Sun.COM 	hp->ah_rnumber = 0;
194310187SKrishna.Elango@Sun.COM 	hp->ah_offset = 0;
194410187SKrishna.Elango@Sun.COM 	hp->ah_len = 0;
194510187SKrishna.Elango@Sun.COM 	hp->ah_acc = attr;
194610187SKrishna.Elango@Sun.COM 
194710187SKrishna.Elango@Sun.COM 	mr.map_op = DDI_MO_MAP_LOCKED;
194810187SKrishna.Elango@Sun.COM 	mr.map_type = DDI_MT_REGSPEC;
194910187SKrishna.Elango@Sun.COM 	mr.map_obj.rp = (struct regspec *)phys_spec;
195010187SKrishna.Elango@Sun.COM 	mr.map_prot = PROT_READ | PROT_WRITE;
195110187SKrishna.Elango@Sun.COM 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
195210187SKrishna.Elango@Sun.COM 	mr.map_handlep = hp;
195310187SKrishna.Elango@Sun.COM 	mr.map_vers = DDI_MAP_VERSION;
195410187SKrishna.Elango@Sun.COM 
195510187SKrishna.Elango@Sun.COM 	result = ddi_map(dip, &mr, 0, 0, addrp);
195610187SKrishna.Elango@Sun.COM 
195710187SKrishna.Elango@Sun.COM 	if (result != DDI_SUCCESS) {
195810187SKrishna.Elango@Sun.COM 		impl_acc_hdl_free(*handlep);
195910187SKrishna.Elango@Sun.COM 		*handlep = (ddi_acc_handle_t)NULL;
196010187SKrishna.Elango@Sun.COM 	} else {
196110187SKrishna.Elango@Sun.COM 		hp->ah_addr = *addrp;
196210187SKrishna.Elango@Sun.COM 	}
196310187SKrishna.Elango@Sun.COM 
196410187SKrishna.Elango@Sun.COM 	return (result);
196510187SKrishna.Elango@Sun.COM }
196610187SKrishna.Elango@Sun.COM 
196710187SKrishna.Elango@Sun.COM /*
196810187SKrishna.Elango@Sun.COM  * Map out memory that was mapped in with pcie_map_phys();
196910187SKrishna.Elango@Sun.COM  */
197010187SKrishna.Elango@Sun.COM static void
197110187SKrishna.Elango@Sun.COM pcie_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph)
197210187SKrishna.Elango@Sun.COM {
197310187SKrishna.Elango@Sun.COM 	ddi_map_req_t mr;
197410187SKrishna.Elango@Sun.COM 	ddi_acc_hdl_t *hp;
197510187SKrishna.Elango@Sun.COM 
197610187SKrishna.Elango@Sun.COM 	hp = impl_acc_hdl_get(*handlep);
197710187SKrishna.Elango@Sun.COM 	ASSERT(hp);
197810187SKrishna.Elango@Sun.COM 
197910187SKrishna.Elango@Sun.COM 	mr.map_op = DDI_MO_UNMAP;
198010187SKrishna.Elango@Sun.COM 	mr.map_type = DDI_MT_REGSPEC;
198110187SKrishna.Elango@Sun.COM 	mr.map_obj.rp = (struct regspec *)ph;
198210187SKrishna.Elango@Sun.COM 	mr.map_prot = PROT_READ | PROT_WRITE;
198310187SKrishna.Elango@Sun.COM 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
198410187SKrishna.Elango@Sun.COM 	mr.map_handlep = hp;
198510187SKrishna.Elango@Sun.COM 	mr.map_vers = DDI_MAP_VERSION;
198610187SKrishna.Elango@Sun.COM 
198710187SKrishna.Elango@Sun.COM 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
198810187SKrishna.Elango@Sun.COM 	    hp->ah_len, &hp->ah_addr);
198910187SKrishna.Elango@Sun.COM 
199010187SKrishna.Elango@Sun.COM 	impl_acc_hdl_free(*handlep);
199110187SKrishna.Elango@Sun.COM 	*handlep = (ddi_acc_handle_t)NULL;
199210187SKrishna.Elango@Sun.COM }
199310187SKrishna.Elango@Sun.COM 
199410187SKrishna.Elango@Sun.COM void
199510187SKrishna.Elango@Sun.COM pcie_set_rber_fatal(dev_info_t *dip, boolean_t val)
199610187SKrishna.Elango@Sun.COM {
199710187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
199810187SKrishna.Elango@Sun.COM 	bus_p->bus_pfd->pe_rber_fatal = val;
199910187SKrishna.Elango@Sun.COM }
200010187SKrishna.Elango@Sun.COM 
200110187SKrishna.Elango@Sun.COM /*
200210187SKrishna.Elango@Sun.COM  * Return parent Root Port's pe_rber_fatal value.
200310187SKrishna.Elango@Sun.COM  */
200410187SKrishna.Elango@Sun.COM boolean_t
200510187SKrishna.Elango@Sun.COM pcie_get_rber_fatal(dev_info_t *dip)
200610187SKrishna.Elango@Sun.COM {
200710187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
200810187SKrishna.Elango@Sun.COM 	pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip);
200910187SKrishna.Elango@Sun.COM 	return (rp_bus_p->bus_pfd->pe_rber_fatal);
201010187SKrishna.Elango@Sun.COM }
201110187SKrishna.Elango@Sun.COM 
201210923SEvan.Yan@Sun.COM int
201310923SEvan.Yan@Sun.COM pcie_ari_supported(dev_info_t *dip)
201410923SEvan.Yan@Sun.COM {
201510923SEvan.Yan@Sun.COM 	uint32_t devcap2;
201610923SEvan.Yan@Sun.COM 	uint16_t pciecap;
201710923SEvan.Yan@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
201810923SEvan.Yan@Sun.COM 	uint8_t dev_type;
201910923SEvan.Yan@Sun.COM 
202010923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_supported: dip=%p\n", dip);
202110923SEvan.Yan@Sun.COM 
202210923SEvan.Yan@Sun.COM 	if (bus_p == NULL)
202310923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
202410923SEvan.Yan@Sun.COM 
202510923SEvan.Yan@Sun.COM 	dev_type = bus_p->bus_dev_type;
202610923SEvan.Yan@Sun.COM 
202710923SEvan.Yan@Sun.COM 	if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) &&
202810923SEvan.Yan@Sun.COM 	    (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT))
202910923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
203010923SEvan.Yan@Sun.COM 
203110923SEvan.Yan@Sun.COM 	if (pcie_disable_ari) {
203210923SEvan.Yan@Sun.COM 		PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip);
203310923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
203410923SEvan.Yan@Sun.COM 	}
203510923SEvan.Yan@Sun.COM 
203610923SEvan.Yan@Sun.COM 	pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
203710923SEvan.Yan@Sun.COM 
203810923SEvan.Yan@Sun.COM 	if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) {
203910923SEvan.Yan@Sun.COM 		PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip);
204010923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
204110923SEvan.Yan@Sun.COM 	}
204210923SEvan.Yan@Sun.COM 
204310923SEvan.Yan@Sun.COM 	devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2);
204410923SEvan.Yan@Sun.COM 
204510923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n",
204610923SEvan.Yan@Sun.COM 	    dip, devcap2);
204710923SEvan.Yan@Sun.COM 
204810923SEvan.Yan@Sun.COM 	if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) {
204910923SEvan.Yan@Sun.COM 		PCIE_DBG("pcie_ari_supported: "
205010923SEvan.Yan@Sun.COM 		    "dip=%p: ARI Forwarding is supported\n", dip);
205110923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_SUPPORTED);
205210923SEvan.Yan@Sun.COM 	}
205310923SEvan.Yan@Sun.COM 	return (PCIE_ARI_FORW_NOT_SUPPORTED);
205410923SEvan.Yan@Sun.COM }
205510923SEvan.Yan@Sun.COM 
205610923SEvan.Yan@Sun.COM int
205710923SEvan.Yan@Sun.COM pcie_ari_enable(dev_info_t *dip)
205810923SEvan.Yan@Sun.COM {
205910923SEvan.Yan@Sun.COM 	uint16_t devctl2;
206010923SEvan.Yan@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
206110923SEvan.Yan@Sun.COM 
206210923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_enable: dip=%p\n", dip);
206310923SEvan.Yan@Sun.COM 
206410923SEvan.Yan@Sun.COM 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
206510923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
206610923SEvan.Yan@Sun.COM 
206710923SEvan.Yan@Sun.COM 	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
206810923SEvan.Yan@Sun.COM 	devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN;
206910923SEvan.Yan@Sun.COM 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
207010923SEvan.Yan@Sun.COM 
207110923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n",
207210923SEvan.Yan@Sun.COM 	    dip, devctl2);
207310923SEvan.Yan@Sun.COM 
207410923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
207510923SEvan.Yan@Sun.COM }
207610923SEvan.Yan@Sun.COM 
207710923SEvan.Yan@Sun.COM int
207810923SEvan.Yan@Sun.COM pcie_ari_disable(dev_info_t *dip)
207910923SEvan.Yan@Sun.COM {
208010923SEvan.Yan@Sun.COM 	uint16_t devctl2;
208110923SEvan.Yan@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
208210923SEvan.Yan@Sun.COM 
208310923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_disable: dip=%p\n", dip);
208410923SEvan.Yan@Sun.COM 
208510923SEvan.Yan@Sun.COM 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
208610923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
208710923SEvan.Yan@Sun.COM 
208810923SEvan.Yan@Sun.COM 	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
208910923SEvan.Yan@Sun.COM 	devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN;
209010923SEvan.Yan@Sun.COM 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
209110923SEvan.Yan@Sun.COM 
209210923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n",
209310923SEvan.Yan@Sun.COM 	    dip, devctl2);
209410923SEvan.Yan@Sun.COM 
209510923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
209610923SEvan.Yan@Sun.COM }
209710923SEvan.Yan@Sun.COM 
209810923SEvan.Yan@Sun.COM int
209910923SEvan.Yan@Sun.COM pcie_ari_is_enabled(dev_info_t *dip)
210010923SEvan.Yan@Sun.COM {
210110923SEvan.Yan@Sun.COM 	uint16_t devctl2;
210210923SEvan.Yan@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
210310923SEvan.Yan@Sun.COM 
210410923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip);
210510923SEvan.Yan@Sun.COM 
210610923SEvan.Yan@Sun.COM 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
210710923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_DISABLED);
210810923SEvan.Yan@Sun.COM 
210910923SEvan.Yan@Sun.COM 	devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2);
211010923SEvan.Yan@Sun.COM 
211110923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n",
211210923SEvan.Yan@Sun.COM 	    dip, devctl2);
211310923SEvan.Yan@Sun.COM 
211410923SEvan.Yan@Sun.COM 	if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) {
211510923SEvan.Yan@Sun.COM 		PCIE_DBG("pcie_ari_is_enabled: "
211610923SEvan.Yan@Sun.COM 		    "dip=%p: ARI Forwarding is enabled\n", dip);
211710923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_ENABLED);
211810923SEvan.Yan@Sun.COM 	}
211910923SEvan.Yan@Sun.COM 
212010923SEvan.Yan@Sun.COM 	return (PCIE_ARI_FORW_DISABLED);
212110923SEvan.Yan@Sun.COM }
212210923SEvan.Yan@Sun.COM 
212310923SEvan.Yan@Sun.COM int
212410923SEvan.Yan@Sun.COM pcie_ari_device(dev_info_t *dip)
212510923SEvan.Yan@Sun.COM {
212610923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle;
212710923SEvan.Yan@Sun.COM 	uint16_t cap_ptr;
212810923SEvan.Yan@Sun.COM 
212910923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_device: dip=%p\n", dip);
213010923SEvan.Yan@Sun.COM 
213110923SEvan.Yan@Sun.COM 	/*
213210923SEvan.Yan@Sun.COM 	 * XXX - This function may be called before the bus_p structure
213310923SEvan.Yan@Sun.COM 	 * has been populated.  This code can be changed to remove
213410923SEvan.Yan@Sun.COM 	 * pci_config_setup()/pci_config_teardown() when the RFE
213510923SEvan.Yan@Sun.COM 	 * to populate the bus_p structures early in boot is putback.
213610923SEvan.Yan@Sun.COM 	 */
213710923SEvan.Yan@Sun.COM 
213810923SEvan.Yan@Sun.COM 	/* First make sure it is a PCIe device */
213910923SEvan.Yan@Sun.COM 
214010923SEvan.Yan@Sun.COM 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
214110923SEvan.Yan@Sun.COM 		return (PCIE_NOT_ARI_DEVICE);
214210923SEvan.Yan@Sun.COM 
214310923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
214410923SEvan.Yan@Sun.COM 	    != DDI_SUCCESS) {
214510923SEvan.Yan@Sun.COM 		pci_config_teardown(&handle);
214610923SEvan.Yan@Sun.COM 		return (PCIE_NOT_ARI_DEVICE);
214710923SEvan.Yan@Sun.COM 	}
214810923SEvan.Yan@Sun.COM 
214910923SEvan.Yan@Sun.COM 	/* Locate the ARI Capability */
215010923SEvan.Yan@Sun.COM 
215110923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI),
215210923SEvan.Yan@Sun.COM 	    &cap_ptr)) == DDI_FAILURE) {
215310923SEvan.Yan@Sun.COM 		pci_config_teardown(&handle);
215410923SEvan.Yan@Sun.COM 		return (PCIE_NOT_ARI_DEVICE);
215510923SEvan.Yan@Sun.COM 	}
215610923SEvan.Yan@Sun.COM 
215710923SEvan.Yan@Sun.COM 	/* ARI Capability was found so it must be a ARI device */
215810923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip);
215910923SEvan.Yan@Sun.COM 
216010923SEvan.Yan@Sun.COM 	pci_config_teardown(&handle);
216110923SEvan.Yan@Sun.COM 	return (PCIE_ARI_DEVICE);
216210923SEvan.Yan@Sun.COM }
216310923SEvan.Yan@Sun.COM 
216410923SEvan.Yan@Sun.COM int
216510923SEvan.Yan@Sun.COM pcie_ari_get_next_function(dev_info_t *dip, int *func)
216610923SEvan.Yan@Sun.COM {
216710923SEvan.Yan@Sun.COM 	uint32_t val;
216810923SEvan.Yan@Sun.COM 	uint16_t cap_ptr, next_function;
216910923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle;
217010923SEvan.Yan@Sun.COM 
217110923SEvan.Yan@Sun.COM 	/*
217210923SEvan.Yan@Sun.COM 	 * XXX - This function may be called before the bus_p structure
217310923SEvan.Yan@Sun.COM 	 * has been populated.  This code can be changed to remove
217410923SEvan.Yan@Sun.COM 	 * pci_config_setup()/pci_config_teardown() when the RFE
217510923SEvan.Yan@Sun.COM 	 * to populate the bus_p structures early in boot is putback.
217610923SEvan.Yan@Sun.COM 	 */
217710923SEvan.Yan@Sun.COM 
217810923SEvan.Yan@Sun.COM 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
217910923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
218010923SEvan.Yan@Sun.COM 
218110923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle,
218210923SEvan.Yan@Sun.COM 	    PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) {
218310923SEvan.Yan@Sun.COM 		pci_config_teardown(&handle);
218410923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
218510923SEvan.Yan@Sun.COM 	}
218610923SEvan.Yan@Sun.COM 
218710923SEvan.Yan@Sun.COM 	val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP);
218810923SEvan.Yan@Sun.COM 
218910923SEvan.Yan@Sun.COM 	next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) &
219010923SEvan.Yan@Sun.COM 	    PCIE_ARI_CAP_NEXT_FUNC_MASK;
219110923SEvan.Yan@Sun.COM 
219210923SEvan.Yan@Sun.COM 	pci_config_teardown(&handle);
219310923SEvan.Yan@Sun.COM 
219410923SEvan.Yan@Sun.COM 	*func = next_function;
219510923SEvan.Yan@Sun.COM 
219610923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
219710923SEvan.Yan@Sun.COM }
219810923SEvan.Yan@Sun.COM 
219910923SEvan.Yan@Sun.COM dev_info_t *
220010923SEvan.Yan@Sun.COM pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function)
220110923SEvan.Yan@Sun.COM {
220210923SEvan.Yan@Sun.COM 	pcie_req_id_t child_bdf;
220310923SEvan.Yan@Sun.COM 	dev_info_t *cdip;
220410923SEvan.Yan@Sun.COM 
220510923SEvan.Yan@Sun.COM 	for (cdip = ddi_get_child(dip); cdip;
220610923SEvan.Yan@Sun.COM 	    cdip = ddi_get_next_sibling(cdip)) {
220710923SEvan.Yan@Sun.COM 
220810923SEvan.Yan@Sun.COM 		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
220910923SEvan.Yan@Sun.COM 			return (NULL);
221010923SEvan.Yan@Sun.COM 
221110923SEvan.Yan@Sun.COM 		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function)
221210923SEvan.Yan@Sun.COM 			return (cdip);
221310923SEvan.Yan@Sun.COM 	}
221410923SEvan.Yan@Sun.COM 	return (NULL);
221510923SEvan.Yan@Sun.COM }
221610923SEvan.Yan@Sun.COM 
221710187SKrishna.Elango@Sun.COM #ifdef	DEBUG
221810187SKrishna.Elango@Sun.COM 
221910187SKrishna.Elango@Sun.COM static void
222010187SKrishna.Elango@Sun.COM pcie_print_bus(pcie_bus_t *bus_p)
222110187SKrishna.Elango@Sun.COM {
222210187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip);
222310187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags);
222410187SKrishna.Elango@Sun.COM 
222510187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf);
222610187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id);
222710187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id);
222810187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type);
222910187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type);
223010187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus);
223110187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off);
223210187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off);
223310187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off);
223410187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver);
223510187SKrishna.Elango@Sun.COM }
223610187SKrishna.Elango@Sun.COM 
223710187SKrishna.Elango@Sun.COM /*
223810187SKrishna.Elango@Sun.COM  * For debugging purposes set pcie_dbg_print != 0 to see printf messages
223910187SKrishna.Elango@Sun.COM  * during interrupt.
224010187SKrishna.Elango@Sun.COM  *
224110187SKrishna.Elango@Sun.COM  * When a proper solution is in place this code will disappear.
224210187SKrishna.Elango@Sun.COM  * Potential solutions are:
224310187SKrishna.Elango@Sun.COM  * o circular buffers
224410187SKrishna.Elango@Sun.COM  * o taskq to print at lower pil
224510187SKrishna.Elango@Sun.COM  */
224610187SKrishna.Elango@Sun.COM int pcie_dbg_print = 0;
224710187SKrishna.Elango@Sun.COM void
224810187SKrishna.Elango@Sun.COM pcie_dbg(char *fmt, ...)
224910187SKrishna.Elango@Sun.COM {
225010187SKrishna.Elango@Sun.COM 	va_list ap;
225110187SKrishna.Elango@Sun.COM 
225210187SKrishna.Elango@Sun.COM 	if (!pcie_debug_flags) {
225310187SKrishna.Elango@Sun.COM 		return;
225410187SKrishna.Elango@Sun.COM 	}
225510187SKrishna.Elango@Sun.COM 	va_start(ap, fmt);
225610187SKrishna.Elango@Sun.COM 	if (servicing_interrupt()) {
225710187SKrishna.Elango@Sun.COM 		if (pcie_dbg_print) {
225810187SKrishna.Elango@Sun.COM 			prom_vprintf(fmt, ap);
225910187SKrishna.Elango@Sun.COM 		}
226010187SKrishna.Elango@Sun.COM 	} else {
226110187SKrishna.Elango@Sun.COM 		prom_vprintf(fmt, ap);
226210187SKrishna.Elango@Sun.COM 	}
226310187SKrishna.Elango@Sun.COM 	va_end(ap);
226410187SKrishna.Elango@Sun.COM }
226510187SKrishna.Elango@Sun.COM #endif	/* DEBUG */
226610187SKrishna.Elango@Sun.COM 
226710187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
226810187SKrishna.Elango@Sun.COM static void
226910187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range,
227010187SKrishna.Elango@Sun.COM     boolean_t *empty_mem_range)
227110187SKrishna.Elango@Sun.COM {
227210187SKrishna.Elango@Sun.COM 	uint8_t	class, subclass;
227310187SKrishna.Elango@Sun.COM 	uint_t	val;
227410187SKrishna.Elango@Sun.COM 
227510187SKrishna.Elango@Sun.COM 	class = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS);
227610187SKrishna.Elango@Sun.COM 	subclass = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS);
227710187SKrishna.Elango@Sun.COM 
227810187SKrishna.Elango@Sun.COM 	if ((class == PCI_CLASS_BRIDGE) && (subclass == PCI_BRIDGE_PCI)) {
227910187SKrishna.Elango@Sun.COM 		val = (((uint_t)pci_config_get8(cfg_hdl, PCI_BCNF_IO_BASE_LOW) &
228010187SKrishna.Elango@Sun.COM 		    PCI_BCNF_IO_MASK) << 8);
228110187SKrishna.Elango@Sun.COM 		/*
228210187SKrishna.Elango@Sun.COM 		 * Assuming that a zero based io_range[0] implies an
228310187SKrishna.Elango@Sun.COM 		 * invalid I/O range.  Likewise for mem_range[0].
228410187SKrishna.Elango@Sun.COM 		 */
228510187SKrishna.Elango@Sun.COM 		if (val == 0)
228610187SKrishna.Elango@Sun.COM 			*empty_io_range = B_TRUE;
228710187SKrishna.Elango@Sun.COM 		val = (((uint_t)pci_config_get16(cfg_hdl, PCI_BCNF_MEM_BASE) &
228810187SKrishna.Elango@Sun.COM 		    PCI_BCNF_MEM_MASK) << 16);
228910187SKrishna.Elango@Sun.COM 		if (val == 0)
229010187SKrishna.Elango@Sun.COM 			*empty_mem_range = B_TRUE;
229110187SKrishna.Elango@Sun.COM 	}
229210187SKrishna.Elango@Sun.COM }
229311245SZhijun.Fu@Sun.COM 
229410187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
2295