xref: /onnv-gate/usr/src/uts/common/io/pciex/pcie.c (revision 10923:df470fd79c3c)
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>
37*10923SEvan.Yan@Sun.COM #include <sys/stat.h>
38*10923SEvan.Yan@Sun.COM #include <sys/file.h>
3910187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h>
40*10923SEvan.Yan@Sun.COM #include <sys/pci_impl.h>
4110187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h>
42*10923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h>
43*10923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcicfg.h>
4410187SKrishna.Elango@Sun.COM 
45*10923SEvan.Yan@Sun.COM /* Local functions prototypes */
4610187SKrishna.Elango@Sun.COM static void pcie_init_pfd(dev_info_t *);
4710187SKrishna.Elango@Sun.COM static void pcie_fini_pfd(dev_info_t *);
4810187SKrishna.Elango@Sun.COM 
4910187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
5010187SKrishna.Elango@Sun.COM static void pcie_check_io_mem_range(ddi_acc_handle_t, boolean_t *, boolean_t *);
5110187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
5210187SKrishna.Elango@Sun.COM 
5310187SKrishna.Elango@Sun.COM #ifdef DEBUG
5410187SKrishna.Elango@Sun.COM uint_t pcie_debug_flags = 0;
5510187SKrishna.Elango@Sun.COM static void pcie_print_bus(pcie_bus_t *bus_p);
56*10923SEvan.Yan@Sun.COM void pcie_dbg(char *fmt, ...);
5710187SKrishna.Elango@Sun.COM #endif /* DEBUG */
5810187SKrishna.Elango@Sun.COM 
5910187SKrishna.Elango@Sun.COM /* Variable to control default PCI-Express config settings */
6010187SKrishna.Elango@Sun.COM ushort_t pcie_command_default =
6110187SKrishna.Elango@Sun.COM     PCI_COMM_SERR_ENABLE |
6210187SKrishna.Elango@Sun.COM     PCI_COMM_WAIT_CYC_ENAB |
6310187SKrishna.Elango@Sun.COM     PCI_COMM_PARITY_DETECT |
6410187SKrishna.Elango@Sun.COM     PCI_COMM_ME |
6510187SKrishna.Elango@Sun.COM     PCI_COMM_MAE |
6610187SKrishna.Elango@Sun.COM     PCI_COMM_IO;
6710187SKrishna.Elango@Sun.COM 
6810187SKrishna.Elango@Sun.COM /* xxx_fw are bits that are controlled by FW and should not be modified */
6910187SKrishna.Elango@Sun.COM ushort_t pcie_command_default_fw =
7010187SKrishna.Elango@Sun.COM     PCI_COMM_SPEC_CYC |
7110187SKrishna.Elango@Sun.COM     PCI_COMM_MEMWR_INVAL |
7210187SKrishna.Elango@Sun.COM     PCI_COMM_PALETTE_SNOOP |
7310187SKrishna.Elango@Sun.COM     PCI_COMM_WAIT_CYC_ENAB |
7410187SKrishna.Elango@Sun.COM     0xF800; /* Reserved Bits */
7510187SKrishna.Elango@Sun.COM 
7610187SKrishna.Elango@Sun.COM ushort_t pcie_bdg_command_default_fw =
7710187SKrishna.Elango@Sun.COM     PCI_BCNF_BCNTRL_ISA_ENABLE |
7810187SKrishna.Elango@Sun.COM     PCI_BCNF_BCNTRL_VGA_ENABLE |
7910187SKrishna.Elango@Sun.COM     0xF000; /* Reserved Bits */
8010187SKrishna.Elango@Sun.COM 
8110187SKrishna.Elango@Sun.COM /* PCI-Express Base error defaults */
8210187SKrishna.Elango@Sun.COM ushort_t pcie_base_err_default =
8310187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_CE_REPORTING_EN |
8410187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_NFE_REPORTING_EN |
8510187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_FE_REPORTING_EN |
8610187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_UR_REPORTING_EN;
8710187SKrishna.Elango@Sun.COM 
8810187SKrishna.Elango@Sun.COM /* PCI-Express Device Control Register */
8910187SKrishna.Elango@Sun.COM uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN |
9010187SKrishna.Elango@Sun.COM     PCIE_DEVCTL_MAX_READ_REQ_512;
9110187SKrishna.Elango@Sun.COM 
9210187SKrishna.Elango@Sun.COM /* PCI-Express AER Root Control Register */
9310187SKrishna.Elango@Sun.COM #define	PCIE_ROOT_SYS_ERR	(PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \
9410187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \
9510187SKrishna.Elango@Sun.COM 				PCIE_ROOTCTL_SYS_ERR_ON_FE_EN)
9610187SKrishna.Elango@Sun.COM 
9710187SKrishna.Elango@Sun.COM #if defined(__xpv)
9810187SKrishna.Elango@Sun.COM ushort_t pcie_root_ctrl_default =
9910187SKrishna.Elango@Sun.COM     PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
10010187SKrishna.Elango@Sun.COM     PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
10110187SKrishna.Elango@Sun.COM #else
10210187SKrishna.Elango@Sun.COM ushort_t pcie_root_ctrl_default =
10310187SKrishna.Elango@Sun.COM     PCIE_ROOTCTL_SYS_ERR_ON_CE_EN |
10410187SKrishna.Elango@Sun.COM     PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
10510187SKrishna.Elango@Sun.COM     PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
10610187SKrishna.Elango@Sun.COM #endif /* __xpv */
10710187SKrishna.Elango@Sun.COM 
10810187SKrishna.Elango@Sun.COM /* PCI-Express Root Error Command Register */
10910187SKrishna.Elango@Sun.COM ushort_t pcie_root_error_cmd_default =
11010187SKrishna.Elango@Sun.COM     PCIE_AER_RE_CMD_CE_REP_EN |
11110187SKrishna.Elango@Sun.COM     PCIE_AER_RE_CMD_NFE_REP_EN |
11210187SKrishna.Elango@Sun.COM     PCIE_AER_RE_CMD_FE_REP_EN;
11310187SKrishna.Elango@Sun.COM 
11410187SKrishna.Elango@Sun.COM /* ECRC settings in the PCIe AER Control Register */
11510187SKrishna.Elango@Sun.COM uint32_t pcie_ecrc_value =
11610187SKrishna.Elango@Sun.COM     PCIE_AER_CTL_ECRC_GEN_ENA |
11710187SKrishna.Elango@Sun.COM     PCIE_AER_CTL_ECRC_CHECK_ENA;
11810187SKrishna.Elango@Sun.COM 
11910187SKrishna.Elango@Sun.COM /*
12010187SKrishna.Elango@Sun.COM  * If a particular platform wants to disable certain errors such as UR/MA,
12110187SKrishna.Elango@Sun.COM  * instead of using #defines have the platform's PCIe Root Complex driver set
12210187SKrishna.Elango@Sun.COM  * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions.  For
123*10923SEvan.Yan@Sun.COM  * x86 the closest thing to a PCIe root complex driver is NPE.	For SPARC the
12410187SKrishna.Elango@Sun.COM  * closest PCIe root complex driver is PX.
12510187SKrishna.Elango@Sun.COM  *
12610187SKrishna.Elango@Sun.COM  * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86
12710187SKrishna.Elango@Sun.COM  * systems may want to disable SERR in general.  For root ports, enabling SERR
12810187SKrishna.Elango@Sun.COM  * causes NMIs which are not handled and results in a watchdog timeout error.
12910187SKrishna.Elango@Sun.COM  */
13010187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_mask = 0;		/* AER UE Mask */
13110187SKrishna.Elango@Sun.COM uint32_t pcie_aer_ce_mask = 0;		/* AER CE Mask */
13210187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_mask = 0;	/* AER Secondary UE Mask */
13310187SKrishna.Elango@Sun.COM uint32_t pcie_serr_disable_flag = 0;	/* Disable SERR */
13410187SKrishna.Elango@Sun.COM 
13510187SKrishna.Elango@Sun.COM /* Default severities needed for eversholt.  Error handling doesn't care */
13610187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \
13710187SKrishna.Elango@Sun.COM     PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \
13810187SKrishna.Elango@Sun.COM     PCIE_AER_UCE_TRAINING;
13910187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \
14010187SKrishna.Elango@Sun.COM     PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \
14110187SKrishna.Elango@Sun.COM     PCIE_AER_SUCE_USC_MSG_DATA_ERR;
14210187SKrishna.Elango@Sun.COM 
14310187SKrishna.Elango@Sun.COM int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5;
144*10923SEvan.Yan@Sun.COM int pcie_disable_ari = 0;
14510187SKrishna.Elango@Sun.COM 
14610187SKrishna.Elango@Sun.COM static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip,
14710187SKrishna.Elango@Sun.COM 	int *max_supported);
14810187SKrishna.Elango@Sun.COM static int pcie_get_max_supported(dev_info_t *dip, void *arg);
14910187SKrishna.Elango@Sun.COM static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
15010187SKrishna.Elango@Sun.COM     caddr_t *addrp, ddi_acc_handle_t *handlep);
151*10923SEvan.Yan@Sun.COM static void pcie_unmap_phys(ddi_acc_handle_t *handlep,	pci_regspec_t *ph);
15210187SKrishna.Elango@Sun.COM 
15310187SKrishna.Elango@Sun.COM /*
15410187SKrishna.Elango@Sun.COM  * modload support
15510187SKrishna.Elango@Sun.COM  */
15610187SKrishna.Elango@Sun.COM 
15710187SKrishna.Elango@Sun.COM static struct modlmisc modlmisc	= {
15810187SKrishna.Elango@Sun.COM 	&mod_miscops,	/* Type	of module */
159*10923SEvan.Yan@Sun.COM 	"PCI Express Framework Module"
16010187SKrishna.Elango@Sun.COM };
16110187SKrishna.Elango@Sun.COM 
16210187SKrishna.Elango@Sun.COM static struct modlinkage modlinkage = {
16310187SKrishna.Elango@Sun.COM 	MODREV_1,
16410187SKrishna.Elango@Sun.COM 	(void	*)&modlmisc,
16510187SKrishna.Elango@Sun.COM 	NULL
16610187SKrishna.Elango@Sun.COM };
16710187SKrishna.Elango@Sun.COM 
16810187SKrishna.Elango@Sun.COM /*
16910187SKrishna.Elango@Sun.COM  * Global Variables needed for a non-atomic version of ddi_fm_ereport_post.
17010187SKrishna.Elango@Sun.COM  * Currently used to send the pci.fabric ereports whose payload depends on the
17110187SKrishna.Elango@Sun.COM  * type of PCI device it is being sent for.
17210187SKrishna.Elango@Sun.COM  */
17310187SKrishna.Elango@Sun.COM char		*pcie_nv_buf;
17410187SKrishna.Elango@Sun.COM nv_alloc_t	*pcie_nvap;
17510187SKrishna.Elango@Sun.COM nvlist_t	*pcie_nvl;
17610187SKrishna.Elango@Sun.COM 
17710187SKrishna.Elango@Sun.COM int
17810187SKrishna.Elango@Sun.COM _init(void)
17910187SKrishna.Elango@Sun.COM {
18010187SKrishna.Elango@Sun.COM 	int rval;
18110187SKrishna.Elango@Sun.COM 
18210187SKrishna.Elango@Sun.COM 	pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP);
18310187SKrishna.Elango@Sun.COM 	pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ);
18410187SKrishna.Elango@Sun.COM 	pcie_nvl = fm_nvlist_create(pcie_nvap);
18510187SKrishna.Elango@Sun.COM 
18610187SKrishna.Elango@Sun.COM 	rval = mod_install(&modlinkage);
18710187SKrishna.Elango@Sun.COM 	return (rval);
18810187SKrishna.Elango@Sun.COM }
18910187SKrishna.Elango@Sun.COM 
19010187SKrishna.Elango@Sun.COM int
19110187SKrishna.Elango@Sun.COM _fini()
19210187SKrishna.Elango@Sun.COM {
19310187SKrishna.Elango@Sun.COM 	int		rval;
19410187SKrishna.Elango@Sun.COM 
19510187SKrishna.Elango@Sun.COM 	fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
19610187SKrishna.Elango@Sun.COM 	fm_nva_xdestroy(pcie_nvap);
19710187SKrishna.Elango@Sun.COM 	kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
19810187SKrishna.Elango@Sun.COM 
19910187SKrishna.Elango@Sun.COM 	rval = mod_remove(&modlinkage);
20010187SKrishna.Elango@Sun.COM 	return (rval);
20110187SKrishna.Elango@Sun.COM }
20210187SKrishna.Elango@Sun.COM 
20310187SKrishna.Elango@Sun.COM int
20410187SKrishna.Elango@Sun.COM _info(struct modinfo *modinfop)
20510187SKrishna.Elango@Sun.COM {
20610187SKrishna.Elango@Sun.COM 	return (mod_info(&modlinkage, modinfop));
20710187SKrishna.Elango@Sun.COM }
20810187SKrishna.Elango@Sun.COM 
209*10923SEvan.Yan@Sun.COM /* ARGSUSED */
210*10923SEvan.Yan@Sun.COM int
211*10923SEvan.Yan@Sun.COM pcie_init(dev_info_t *dip, caddr_t arg)
212*10923SEvan.Yan@Sun.COM {
213*10923SEvan.Yan@Sun.COM 	int	ret = DDI_SUCCESS;
214*10923SEvan.Yan@Sun.COM 
215*10923SEvan.Yan@Sun.COM 	/*
216*10923SEvan.Yan@Sun.COM 	 * Create a "devctl" minor node to support DEVCTL_DEVICE_*
217*10923SEvan.Yan@Sun.COM 	 * and DEVCTL_BUS_* ioctls to this bus.
218*10923SEvan.Yan@Sun.COM 	 */
219*10923SEvan.Yan@Sun.COM 	if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR,
220*10923SEvan.Yan@Sun.COM 	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR),
221*10923SEvan.Yan@Sun.COM 	    DDI_NT_NEXUS, 0)) != DDI_SUCCESS) {
222*10923SEvan.Yan@Sun.COM 		PCIE_DBG("Failed to create devctl minor node for %s%d\n",
223*10923SEvan.Yan@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip));
224*10923SEvan.Yan@Sun.COM 
225*10923SEvan.Yan@Sun.COM 		return (ret);
226*10923SEvan.Yan@Sun.COM 	}
227*10923SEvan.Yan@Sun.COM 
228*10923SEvan.Yan@Sun.COM 	if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) {
229*10923SEvan.Yan@Sun.COM 		/*
230*10923SEvan.Yan@Sun.COM 		 * On a few x86 platforms, we observed unexpected hotplug
231*10923SEvan.Yan@Sun.COM 		 * initialization failures in recent years. Continue with
232*10923SEvan.Yan@Sun.COM 		 * a message printed because we don't want to stop PCI
233*10923SEvan.Yan@Sun.COM 		 * driver attach and system boot because of this hotplug
234*10923SEvan.Yan@Sun.COM 		 * initialization failure before we address all those issues.
235*10923SEvan.Yan@Sun.COM 		 */
236*10923SEvan.Yan@Sun.COM 		cmn_err(CE_WARN, "%s%d: Failed setting hotplug framework\n",
237*10923SEvan.Yan@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip));
238*10923SEvan.Yan@Sun.COM 
239*10923SEvan.Yan@Sun.COM #if defined(__sparc)
240*10923SEvan.Yan@Sun.COM 		ddi_remove_minor_node(dip, "devctl");
241*10923SEvan.Yan@Sun.COM 
242*10923SEvan.Yan@Sun.COM 		return (ret);
243*10923SEvan.Yan@Sun.COM #endif /* defined(__sparc) */
244*10923SEvan.Yan@Sun.COM 	}
245*10923SEvan.Yan@Sun.COM 
246*10923SEvan.Yan@Sun.COM 	if ((pcie_ari_supported(dip) == PCIE_ARI_FORW_SUPPORTED) &&
247*10923SEvan.Yan@Sun.COM 	    (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_DISABLED))
248*10923SEvan.Yan@Sun.COM 		(void) pcicfg_configure(dip, 0, PCICFG_ALL_FUNC,
249*10923SEvan.Yan@Sun.COM 		    PCICFG_FLAG_ENABLE_ARI);
250*10923SEvan.Yan@Sun.COM 
251*10923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
252*10923SEvan.Yan@Sun.COM }
253*10923SEvan.Yan@Sun.COM 
254*10923SEvan.Yan@Sun.COM /* ARGSUSED */
255*10923SEvan.Yan@Sun.COM int
256*10923SEvan.Yan@Sun.COM pcie_uninit(dev_info_t *dip)
257*10923SEvan.Yan@Sun.COM {
258*10923SEvan.Yan@Sun.COM 	int	ret = DDI_SUCCESS;
259*10923SEvan.Yan@Sun.COM 
260*10923SEvan.Yan@Sun.COM 	if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED)
261*10923SEvan.Yan@Sun.COM 		(void) pcie_ari_disable(dip);
262*10923SEvan.Yan@Sun.COM 
263*10923SEvan.Yan@Sun.COM 	if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) {
264*10923SEvan.Yan@Sun.COM 		PCIE_DBG("Failed to uninitialize hotplug for %s%d\n",
265*10923SEvan.Yan@Sun.COM 		    ddi_driver_name(dip), ddi_get_instance(dip));
266*10923SEvan.Yan@Sun.COM 
267*10923SEvan.Yan@Sun.COM 		return (ret);
268*10923SEvan.Yan@Sun.COM 	}
269*10923SEvan.Yan@Sun.COM 
270*10923SEvan.Yan@Sun.COM 	ddi_remove_minor_node(dip, "devctl");
271*10923SEvan.Yan@Sun.COM 
272*10923SEvan.Yan@Sun.COM 	return (ret);
273*10923SEvan.Yan@Sun.COM }
274*10923SEvan.Yan@Sun.COM 
275*10923SEvan.Yan@Sun.COM /* ARGSUSED */
276*10923SEvan.Yan@Sun.COM int
277*10923SEvan.Yan@Sun.COM pcie_intr(dev_info_t *dip)
278*10923SEvan.Yan@Sun.COM {
279*10923SEvan.Yan@Sun.COM 	return (pcie_hp_intr(dip));
280*10923SEvan.Yan@Sun.COM }
281*10923SEvan.Yan@Sun.COM 
282*10923SEvan.Yan@Sun.COM /* ARGSUSED */
283*10923SEvan.Yan@Sun.COM int
284*10923SEvan.Yan@Sun.COM pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp)
285*10923SEvan.Yan@Sun.COM {
286*10923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
287*10923SEvan.Yan@Sun.COM 
288*10923SEvan.Yan@Sun.COM 	/*
289*10923SEvan.Yan@Sun.COM 	 * Make sure the open is for the right file type.
290*10923SEvan.Yan@Sun.COM 	 */
291*10923SEvan.Yan@Sun.COM 	if (otyp != OTYP_CHR)
292*10923SEvan.Yan@Sun.COM 		return (EINVAL);
293*10923SEvan.Yan@Sun.COM 
294*10923SEvan.Yan@Sun.COM 	/*
295*10923SEvan.Yan@Sun.COM 	 * Handle the open by tracking the device state.
296*10923SEvan.Yan@Sun.COM 	 */
297*10923SEvan.Yan@Sun.COM 	if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) ||
298*10923SEvan.Yan@Sun.COM 	    ((flags & FEXCL) &&
299*10923SEvan.Yan@Sun.COM 	    (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) {
300*10923SEvan.Yan@Sun.COM 		return (EBUSY);
301*10923SEvan.Yan@Sun.COM 	}
302*10923SEvan.Yan@Sun.COM 
303*10923SEvan.Yan@Sun.COM 	if (flags & FEXCL)
304*10923SEvan.Yan@Sun.COM 		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
305*10923SEvan.Yan@Sun.COM 	else
306*10923SEvan.Yan@Sun.COM 		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN;
307*10923SEvan.Yan@Sun.COM 
308*10923SEvan.Yan@Sun.COM 	return (0);
309*10923SEvan.Yan@Sun.COM }
310*10923SEvan.Yan@Sun.COM 
311*10923SEvan.Yan@Sun.COM /* ARGSUSED */
312*10923SEvan.Yan@Sun.COM int
313*10923SEvan.Yan@Sun.COM pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp)
314*10923SEvan.Yan@Sun.COM {
315*10923SEvan.Yan@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
316*10923SEvan.Yan@Sun.COM 
317*10923SEvan.Yan@Sun.COM 	if (otyp != OTYP_CHR)
318*10923SEvan.Yan@Sun.COM 		return (EINVAL);
319*10923SEvan.Yan@Sun.COM 
320*10923SEvan.Yan@Sun.COM 	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
321*10923SEvan.Yan@Sun.COM 
322*10923SEvan.Yan@Sun.COM 	return (0);
323*10923SEvan.Yan@Sun.COM }
324*10923SEvan.Yan@Sun.COM 
325*10923SEvan.Yan@Sun.COM /* ARGSUSED */
326*10923SEvan.Yan@Sun.COM int
327*10923SEvan.Yan@Sun.COM pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode,
328*10923SEvan.Yan@Sun.COM     cred_t *credp, int *rvalp)
329*10923SEvan.Yan@Sun.COM {
330*10923SEvan.Yan@Sun.COM 	struct devctl_iocdata	*dcp;
331*10923SEvan.Yan@Sun.COM 	uint_t			bus_state;
332*10923SEvan.Yan@Sun.COM 	int			rv = DDI_SUCCESS;
333*10923SEvan.Yan@Sun.COM 
334*10923SEvan.Yan@Sun.COM 	/*
335*10923SEvan.Yan@Sun.COM 	 * We can use the generic implementation for devctl ioctl
336*10923SEvan.Yan@Sun.COM 	 */
337*10923SEvan.Yan@Sun.COM 	switch (cmd) {
338*10923SEvan.Yan@Sun.COM 	case DEVCTL_DEVICE_GETSTATE:
339*10923SEvan.Yan@Sun.COM 	case DEVCTL_DEVICE_ONLINE:
340*10923SEvan.Yan@Sun.COM 	case DEVCTL_DEVICE_OFFLINE:
341*10923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_GETSTATE:
342*10923SEvan.Yan@Sun.COM 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
343*10923SEvan.Yan@Sun.COM 	default:
344*10923SEvan.Yan@Sun.COM 		break;
345*10923SEvan.Yan@Sun.COM 	}
346*10923SEvan.Yan@Sun.COM 
347*10923SEvan.Yan@Sun.COM 	/*
348*10923SEvan.Yan@Sun.COM 	 * read devctl ioctl data
349*10923SEvan.Yan@Sun.COM 	 */
350*10923SEvan.Yan@Sun.COM 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
351*10923SEvan.Yan@Sun.COM 		return (EFAULT);
352*10923SEvan.Yan@Sun.COM 
353*10923SEvan.Yan@Sun.COM 	switch (cmd) {
354*10923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_QUIESCE:
355*10923SEvan.Yan@Sun.COM 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
356*10923SEvan.Yan@Sun.COM 			if (bus_state == BUS_QUIESCED)
357*10923SEvan.Yan@Sun.COM 				break;
358*10923SEvan.Yan@Sun.COM 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
359*10923SEvan.Yan@Sun.COM 		break;
360*10923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_UNQUIESCE:
361*10923SEvan.Yan@Sun.COM 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
362*10923SEvan.Yan@Sun.COM 			if (bus_state == BUS_ACTIVE)
363*10923SEvan.Yan@Sun.COM 				break;
364*10923SEvan.Yan@Sun.COM 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
365*10923SEvan.Yan@Sun.COM 		break;
366*10923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_RESET:
367*10923SEvan.Yan@Sun.COM 	case DEVCTL_BUS_RESETALL:
368*10923SEvan.Yan@Sun.COM 	case DEVCTL_DEVICE_RESET:
369*10923SEvan.Yan@Sun.COM 		rv = ENOTSUP;
370*10923SEvan.Yan@Sun.COM 		break;
371*10923SEvan.Yan@Sun.COM 	default:
372*10923SEvan.Yan@Sun.COM 		rv = ENOTTY;
373*10923SEvan.Yan@Sun.COM 	}
374*10923SEvan.Yan@Sun.COM 
375*10923SEvan.Yan@Sun.COM 	ndi_dc_freehdl(dcp);
376*10923SEvan.Yan@Sun.COM 	return (rv);
377*10923SEvan.Yan@Sun.COM }
378*10923SEvan.Yan@Sun.COM 
379*10923SEvan.Yan@Sun.COM /* ARGSUSED */
380*10923SEvan.Yan@Sun.COM int
381*10923SEvan.Yan@Sun.COM pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
382*10923SEvan.Yan@Sun.COM     int flags, char *name, caddr_t valuep, int *lengthp)
383*10923SEvan.Yan@Sun.COM {
384*10923SEvan.Yan@Sun.COM 	if (dev == DDI_DEV_T_ANY)
385*10923SEvan.Yan@Sun.COM 		goto skip;
386*10923SEvan.Yan@Sun.COM 
387*10923SEvan.Yan@Sun.COM 	if (PCIE_IS_HOTPLUG_CAPABLE(dip) &&
388*10923SEvan.Yan@Sun.COM 	    strcmp(name, "pci-occupant") == 0) {
389*10923SEvan.Yan@Sun.COM 		int	pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
390*10923SEvan.Yan@Sun.COM 
391*10923SEvan.Yan@Sun.COM 		pcie_hp_create_occupant_props(dip, dev, pci_dev);
392*10923SEvan.Yan@Sun.COM 	}
393*10923SEvan.Yan@Sun.COM 
394*10923SEvan.Yan@Sun.COM skip:
395*10923SEvan.Yan@Sun.COM 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
396*10923SEvan.Yan@Sun.COM }
397*10923SEvan.Yan@Sun.COM 
39810187SKrishna.Elango@Sun.COM /*
39910187SKrishna.Elango@Sun.COM  * PCI-Express child device initialization.
40010187SKrishna.Elango@Sun.COM  * This function enables generic pci-express interrupts and error
40110187SKrishna.Elango@Sun.COM  * handling.
40210187SKrishna.Elango@Sun.COM  *
40310187SKrishna.Elango@Sun.COM  * @param pdip		root dip (root nexus's dip)
40410187SKrishna.Elango@Sun.COM  * @param cdip		child's dip (device's dip)
40510187SKrishna.Elango@Sun.COM  * @return		DDI_SUCCESS or DDI_FAILURE
40610187SKrishna.Elango@Sun.COM  */
40710187SKrishna.Elango@Sun.COM /* ARGSUSED */
40810187SKrishna.Elango@Sun.COM int
40910187SKrishna.Elango@Sun.COM pcie_initchild(dev_info_t *cdip)
41010187SKrishna.Elango@Sun.COM {
41110187SKrishna.Elango@Sun.COM 	uint16_t		tmp16, reg16;
41210187SKrishna.Elango@Sun.COM 	pcie_bus_t		*bus_p;
41310187SKrishna.Elango@Sun.COM 
41410187SKrishna.Elango@Sun.COM 	bus_p = PCIE_DIP2BUS(cdip);
41510187SKrishna.Elango@Sun.COM 	if (bus_p == NULL) {
41610187SKrishna.Elango@Sun.COM 		PCIE_DBG("%s: BUS not found.\n",
41710187SKrishna.Elango@Sun.COM 		    ddi_driver_name(cdip));
41810187SKrishna.Elango@Sun.COM 
41910187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
42010187SKrishna.Elango@Sun.COM 	}
42110187SKrishna.Elango@Sun.COM 
42210187SKrishna.Elango@Sun.COM 	/* Clear the device's status register */
42310187SKrishna.Elango@Sun.COM 	reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT);
42410187SKrishna.Elango@Sun.COM 	PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16);
42510187SKrishna.Elango@Sun.COM 
42610187SKrishna.Elango@Sun.COM 	/* Setup the device's command register */
42710187SKrishna.Elango@Sun.COM 	reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM);
42810187SKrishna.Elango@Sun.COM 	tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default;
42910187SKrishna.Elango@Sun.COM 
43010187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
43110187SKrishna.Elango@Sun.COM 	boolean_t empty_io_range = B_FALSE;
43210187SKrishna.Elango@Sun.COM 	boolean_t empty_mem_range = B_FALSE;
43310187SKrishna.Elango@Sun.COM 	/*
43410187SKrishna.Elango@Sun.COM 	 * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem
43510187SKrishna.Elango@Sun.COM 	 * access as it can cause a hang if enabled.
43610187SKrishna.Elango@Sun.COM 	 */
43710187SKrishna.Elango@Sun.COM 	pcie_check_io_mem_range(bus_p->bus_cfg_hdl, &empty_io_range,
43810187SKrishna.Elango@Sun.COM 	    &empty_mem_range);
43910187SKrishna.Elango@Sun.COM 	if ((empty_io_range == B_TRUE) &&
44010187SKrishna.Elango@Sun.COM 	    (pcie_command_default & PCI_COMM_IO)) {
44110187SKrishna.Elango@Sun.COM 		tmp16 &= ~PCI_COMM_IO;
44210187SKrishna.Elango@Sun.COM 		PCIE_DBG("No I/O range found for %s, bdf 0x%x\n",
44310187SKrishna.Elango@Sun.COM 		    ddi_driver_name(cdip), bus_p->bus_bdf);
44410187SKrishna.Elango@Sun.COM 	}
44510187SKrishna.Elango@Sun.COM 	if ((empty_mem_range == B_TRUE) &&
44610187SKrishna.Elango@Sun.COM 	    (pcie_command_default & PCI_COMM_MAE)) {
44710187SKrishna.Elango@Sun.COM 		tmp16 &= ~PCI_COMM_MAE;
44810187SKrishna.Elango@Sun.COM 		PCIE_DBG("No Mem range found for %s, bdf 0x%x\n",
44910187SKrishna.Elango@Sun.COM 		    ddi_driver_name(cdip), bus_p->bus_bdf);
45010187SKrishna.Elango@Sun.COM 	}
45110187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
45210187SKrishna.Elango@Sun.COM 
45310187SKrishna.Elango@Sun.COM 	if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p))
45410187SKrishna.Elango@Sun.COM 		tmp16 &= ~PCI_COMM_SERR_ENABLE;
45510187SKrishna.Elango@Sun.COM 
45610187SKrishna.Elango@Sun.COM 	PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16);
45710187SKrishna.Elango@Sun.COM 	PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16);
45810187SKrishna.Elango@Sun.COM 
45910187SKrishna.Elango@Sun.COM 	/*
46010187SKrishna.Elango@Sun.COM 	 * If the device has a bus control register then program it
46110187SKrishna.Elango@Sun.COM 	 * based on the settings in the command register.
46210187SKrishna.Elango@Sun.COM 	 */
46310187SKrishna.Elango@Sun.COM 	if (PCIE_IS_BDG(bus_p)) {
46410187SKrishna.Elango@Sun.COM 		/* Clear the device's secondary status register */
46510187SKrishna.Elango@Sun.COM 		reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
46610187SKrishna.Elango@Sun.COM 		PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16);
46710187SKrishna.Elango@Sun.COM 
46810187SKrishna.Elango@Sun.COM 		/* Setup the device's secondary command register */
46910187SKrishna.Elango@Sun.COM 		reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
47010187SKrishna.Elango@Sun.COM 		tmp16 = (reg16 & pcie_bdg_command_default_fw);
47110187SKrishna.Elango@Sun.COM 
47210187SKrishna.Elango@Sun.COM 		tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE;
47310187SKrishna.Elango@Sun.COM 		/*
47410187SKrishna.Elango@Sun.COM 		 * Workaround for this Nvidia bridge. Don't enable the SERR
47510187SKrishna.Elango@Sun.COM 		 * enable bit in the bridge control register as it could lead to
47610187SKrishna.Elango@Sun.COM 		 * bogus NMIs.
47710187SKrishna.Elango@Sun.COM 		 */
47810187SKrishna.Elango@Sun.COM 		if (bus_p->bus_dev_ven_id == 0x037010DE)
47910187SKrishna.Elango@Sun.COM 			tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
48010187SKrishna.Elango@Sun.COM 
48110187SKrishna.Elango@Sun.COM 		if (pcie_command_default & PCI_COMM_PARITY_DETECT)
48210187SKrishna.Elango@Sun.COM 			tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
48310187SKrishna.Elango@Sun.COM 
48410187SKrishna.Elango@Sun.COM 		/*
48510187SKrishna.Elango@Sun.COM 		 * Enable Master Abort Mode only if URs have not been masked.
48610187SKrishna.Elango@Sun.COM 		 * For PCI and PCIe-PCI bridges, enabling this bit causes a
48710187SKrishna.Elango@Sun.COM 		 * Master Aborts/UR to be forwarded as a UR/TA or SERR.  If this
48810187SKrishna.Elango@Sun.COM 		 * bit is masked, posted requests are dropped and non-posted
48910187SKrishna.Elango@Sun.COM 		 * requests are returned with -1.
49010187SKrishna.Elango@Sun.COM 		 */
49110187SKrishna.Elango@Sun.COM 		if (pcie_aer_uce_mask & PCIE_AER_UCE_UR)
49210187SKrishna.Elango@Sun.COM 			tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE;
49310187SKrishna.Elango@Sun.COM 		else
49410187SKrishna.Elango@Sun.COM 			tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
49510187SKrishna.Elango@Sun.COM 		PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16);
49610187SKrishna.Elango@Sun.COM 		PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL,
49710187SKrishna.Elango@Sun.COM 		    reg16);
49810187SKrishna.Elango@Sun.COM 	}
49910187SKrishna.Elango@Sun.COM 
50010187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p)) {
50110187SKrishna.Elango@Sun.COM 		/* Setup PCIe device control register */
50210187SKrishna.Elango@Sun.COM 		reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
50310187SKrishna.Elango@Sun.COM 		tmp16 = pcie_devctl_default;
50410187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
50510187SKrishna.Elango@Sun.COM 		PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
50610187SKrishna.Elango@Sun.COM 
50710187SKrishna.Elango@Sun.COM 		/* Enable PCIe errors */
50810187SKrishna.Elango@Sun.COM 		pcie_enable_errors(cdip);
50910187SKrishna.Elango@Sun.COM 	}
51010187SKrishna.Elango@Sun.COM 
511*10923SEvan.Yan@Sun.COM 	bus_p->bus_ari = B_FALSE;
512*10923SEvan.Yan@Sun.COM 	if ((pcie_ari_is_enabled(ddi_get_parent(cdip))
513*10923SEvan.Yan@Sun.COM 	    == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip)
514*10923SEvan.Yan@Sun.COM 	    == PCIE_ARI_DEVICE)) {
515*10923SEvan.Yan@Sun.COM 		bus_p->bus_ari = B_TRUE;
516*10923SEvan.Yan@Sun.COM 	}
517*10923SEvan.Yan@Sun.COM 
51810187SKrishna.Elango@Sun.COM 	if (pcie_initchild_mps(cdip) == DDI_FAILURE)
51910187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
52010187SKrishna.Elango@Sun.COM 
52110187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
52210187SKrishna.Elango@Sun.COM }
52310187SKrishna.Elango@Sun.COM 
52410187SKrishna.Elango@Sun.COM #define	PCIE_ZALLOC(data) kmem_zalloc(sizeof (data), KM_SLEEP)
52510187SKrishna.Elango@Sun.COM static void
52610187SKrishna.Elango@Sun.COM pcie_init_pfd(dev_info_t *dip)
52710187SKrishna.Elango@Sun.COM {
52810187SKrishna.Elango@Sun.COM 	pf_data_t	*pfd_p = PCIE_ZALLOC(pf_data_t);
52910187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
53010187SKrishna.Elango@Sun.COM 
53110187SKrishna.Elango@Sun.COM 	PCIE_DIP2PFD(dip) = pfd_p;
53210187SKrishna.Elango@Sun.COM 
53310187SKrishna.Elango@Sun.COM 	pfd_p->pe_bus_p = bus_p;
53410187SKrishna.Elango@Sun.COM 	pfd_p->pe_severity_flags = 0;
53510187SKrishna.Elango@Sun.COM 	pfd_p->pe_lock = B_FALSE;
53610187SKrishna.Elango@Sun.COM 	pfd_p->pe_valid = B_FALSE;
53710187SKrishna.Elango@Sun.COM 
53810187SKrishna.Elango@Sun.COM 	/* Allocate the root fault struct for both RC and RP */
53910187SKrishna.Elango@Sun.COM 	if (PCIE_IS_ROOT(bus_p)) {
54010187SKrishna.Elango@Sun.COM 		PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
54110187SKrishna.Elango@Sun.COM 		PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
54210187SKrishna.Elango@Sun.COM 	}
54310187SKrishna.Elango@Sun.COM 
54410187SKrishna.Elango@Sun.COM 	PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
54510187SKrishna.Elango@Sun.COM 
54610187SKrishna.Elango@Sun.COM 	if (PCIE_IS_BDG(bus_p))
54710187SKrishna.Elango@Sun.COM 		PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
54810187SKrishna.Elango@Sun.COM 
54910187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p)) {
55010187SKrishna.Elango@Sun.COM 		PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
55110187SKrishna.Elango@Sun.COM 
55210187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p))
55310187SKrishna.Elango@Sun.COM 			PCIE_RP_REG(pfd_p) =
55410187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
55510187SKrishna.Elango@Sun.COM 
55610187SKrishna.Elango@Sun.COM 		PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
55710187SKrishna.Elango@Sun.COM 		PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
55810187SKrishna.Elango@Sun.COM 
55910187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p)) {
56010187SKrishna.Elango@Sun.COM 			PCIE_ADV_RP_REG(pfd_p) =
56110187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
56210187SKrishna.Elango@Sun.COM 			PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id =
56310187SKrishna.Elango@Sun.COM 			    PCIE_INVALID_BDF;
56410187SKrishna.Elango@Sun.COM 			PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id =
56510187SKrishna.Elango@Sun.COM 			    PCIE_INVALID_BDF;
56610187SKrishna.Elango@Sun.COM 		} else if (PCIE_IS_PCIE_BDG(bus_p)) {
56710187SKrishna.Elango@Sun.COM 			PCIE_ADV_BDG_REG(pfd_p) =
56810187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t);
56910187SKrishna.Elango@Sun.COM 			PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf =
57010187SKrishna.Elango@Sun.COM 			    PCIE_INVALID_BDF;
57110187SKrishna.Elango@Sun.COM 		}
57210187SKrishna.Elango@Sun.COM 
57310187SKrishna.Elango@Sun.COM 		if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
57410187SKrishna.Elango@Sun.COM 			PCIX_BDG_ERR_REG(pfd_p) =
57510187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
57610187SKrishna.Elango@Sun.COM 
57710187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
57810187SKrishna.Elango@Sun.COM 				PCIX_BDG_ECC_REG(pfd_p, 0) =
57910187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
58010187SKrishna.Elango@Sun.COM 				PCIX_BDG_ECC_REG(pfd_p, 1) =
58110187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
58210187SKrishna.Elango@Sun.COM 			}
58310187SKrishna.Elango@Sun.COM 		}
58410187SKrishna.Elango@Sun.COM 	} else if (PCIE_IS_PCIX(bus_p)) {
58510187SKrishna.Elango@Sun.COM 		if (PCIE_IS_BDG(bus_p)) {
58610187SKrishna.Elango@Sun.COM 			PCIX_BDG_ERR_REG(pfd_p) =
58710187SKrishna.Elango@Sun.COM 			    PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
58810187SKrishna.Elango@Sun.COM 
58910187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
59010187SKrishna.Elango@Sun.COM 				PCIX_BDG_ECC_REG(pfd_p, 0) =
59110187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
59210187SKrishna.Elango@Sun.COM 				PCIX_BDG_ECC_REG(pfd_p, 1) =
59310187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
59410187SKrishna.Elango@Sun.COM 			}
59510187SKrishna.Elango@Sun.COM 		} else {
59610187SKrishna.Elango@Sun.COM 			PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t);
59710187SKrishna.Elango@Sun.COM 
59810187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p))
59910187SKrishna.Elango@Sun.COM 				PCIX_ECC_REG(pfd_p) =
60010187SKrishna.Elango@Sun.COM 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
60110187SKrishna.Elango@Sun.COM 		}
60210187SKrishna.Elango@Sun.COM 	}
60310187SKrishna.Elango@Sun.COM }
60410187SKrishna.Elango@Sun.COM 
60510187SKrishna.Elango@Sun.COM static void
60610187SKrishna.Elango@Sun.COM pcie_fini_pfd(dev_info_t *dip)
60710187SKrishna.Elango@Sun.COM {
60810187SKrishna.Elango@Sun.COM 	pf_data_t	*pfd_p = PCIE_DIP2PFD(dip);
60910187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
61010187SKrishna.Elango@Sun.COM 
61110187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p)) {
61210187SKrishna.Elango@Sun.COM 		if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
61310187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
61410187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
61510187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
61610187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
61710187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
61810187SKrishna.Elango@Sun.COM 			}
61910187SKrishna.Elango@Sun.COM 
62010187SKrishna.Elango@Sun.COM 			kmem_free(PCIX_BDG_ERR_REG(pfd_p),
62110187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcix_bdg_err_regs_t));
62210187SKrishna.Elango@Sun.COM 		}
62310187SKrishna.Elango@Sun.COM 
62410187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p))
62510187SKrishna.Elango@Sun.COM 			kmem_free(PCIE_ADV_RP_REG(pfd_p),
62610187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcie_adv_rp_err_regs_t));
62710187SKrishna.Elango@Sun.COM 		else if (PCIE_IS_PCIE_BDG(bus_p))
62810187SKrishna.Elango@Sun.COM 			kmem_free(PCIE_ADV_BDG_REG(pfd_p),
62910187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcie_adv_bdg_err_regs_t));
63010187SKrishna.Elango@Sun.COM 
63110187SKrishna.Elango@Sun.COM 		kmem_free(PCIE_ADV_REG(pfd_p),
63210187SKrishna.Elango@Sun.COM 		    sizeof (pf_pcie_adv_err_regs_t));
63310187SKrishna.Elango@Sun.COM 
63410187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p))
63510187SKrishna.Elango@Sun.COM 			kmem_free(PCIE_RP_REG(pfd_p),
63610187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcie_rp_err_regs_t));
63710187SKrishna.Elango@Sun.COM 
63810187SKrishna.Elango@Sun.COM 		kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
63910187SKrishna.Elango@Sun.COM 	} else if (PCIE_IS_PCIX(bus_p)) {
64010187SKrishna.Elango@Sun.COM 		if (PCIE_IS_BDG(bus_p)) {
64110187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
64210187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
64310187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
64410187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
64510187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
64610187SKrishna.Elango@Sun.COM 			}
64710187SKrishna.Elango@Sun.COM 
64810187SKrishna.Elango@Sun.COM 			kmem_free(PCIX_BDG_ERR_REG(pfd_p),
64910187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcix_bdg_err_regs_t));
65010187SKrishna.Elango@Sun.COM 		} else {
65110187SKrishna.Elango@Sun.COM 			if (PCIX_ECC_VERSION_CHECK(bus_p))
65210187SKrishna.Elango@Sun.COM 				kmem_free(PCIX_ECC_REG(pfd_p),
65310187SKrishna.Elango@Sun.COM 				    sizeof (pf_pcix_ecc_regs_t));
65410187SKrishna.Elango@Sun.COM 
65510187SKrishna.Elango@Sun.COM 			kmem_free(PCIX_ERR_REG(pfd_p),
65610187SKrishna.Elango@Sun.COM 			    sizeof (pf_pcix_err_regs_t));
65710187SKrishna.Elango@Sun.COM 		}
65810187SKrishna.Elango@Sun.COM 	}
65910187SKrishna.Elango@Sun.COM 
66010187SKrishna.Elango@Sun.COM 	if (PCIE_IS_BDG(bus_p))
66110187SKrishna.Elango@Sun.COM 		kmem_free(PCI_BDG_ERR_REG(pfd_p),
66210187SKrishna.Elango@Sun.COM 		    sizeof (pf_pci_bdg_err_regs_t));
66310187SKrishna.Elango@Sun.COM 
66410187SKrishna.Elango@Sun.COM 	kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
66510187SKrishna.Elango@Sun.COM 
66610187SKrishna.Elango@Sun.COM 	if (PCIE_IS_ROOT(bus_p))
66710187SKrishna.Elango@Sun.COM 		kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
66810187SKrishna.Elango@Sun.COM 
66910187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t));
67010187SKrishna.Elango@Sun.COM 
67110187SKrishna.Elango@Sun.COM 	PCIE_DIP2PFD(dip) = NULL;
67210187SKrishna.Elango@Sun.COM }
67310187SKrishna.Elango@Sun.COM 
67410187SKrishna.Elango@Sun.COM 
67510187SKrishna.Elango@Sun.COM /*
67610187SKrishna.Elango@Sun.COM  * Special functions to allocate pf_data_t's for PCIe root complexes.
67710187SKrishna.Elango@Sun.COM  * Note: Root Complex not Root Port
67810187SKrishna.Elango@Sun.COM  */
67910187SKrishna.Elango@Sun.COM void
68010187SKrishna.Elango@Sun.COM pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p)
68110187SKrishna.Elango@Sun.COM {
68210187SKrishna.Elango@Sun.COM 	pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip);
68310187SKrishna.Elango@Sun.COM 	pfd_p->pe_severity_flags = 0;
68410187SKrishna.Elango@Sun.COM 	pfd_p->pe_lock = B_FALSE;
68510187SKrishna.Elango@Sun.COM 	pfd_p->pe_valid = B_FALSE;
68610187SKrishna.Elango@Sun.COM 
68710187SKrishna.Elango@Sun.COM 	PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
68810187SKrishna.Elango@Sun.COM 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
68910187SKrishna.Elango@Sun.COM 	PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
69010187SKrishna.Elango@Sun.COM 	PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
69110187SKrishna.Elango@Sun.COM 	PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
69210187SKrishna.Elango@Sun.COM 	PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
69310187SKrishna.Elango@Sun.COM 	PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
69410187SKrishna.Elango@Sun.COM 	PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
69510187SKrishna.Elango@Sun.COM 
69610187SKrishna.Elango@Sun.COM 	PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity;
69710187SKrishna.Elango@Sun.COM }
69810187SKrishna.Elango@Sun.COM 
69910187SKrishna.Elango@Sun.COM void
70010187SKrishna.Elango@Sun.COM pcie_rc_fini_pfd(pf_data_t *pfd_p)
70110187SKrishna.Elango@Sun.COM {
70210187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t));
70310187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t));
70410187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t));
70510187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
70610187SKrishna.Elango@Sun.COM 	kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t));
70710187SKrishna.Elango@Sun.COM 	kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
70810187SKrishna.Elango@Sun.COM 	kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
70910187SKrishna.Elango@Sun.COM }
71010187SKrishna.Elango@Sun.COM 
71110187SKrishna.Elango@Sun.COM void
71210187SKrishna.Elango@Sun.COM pcie_rc_init_bus(dev_info_t *dip)
71310187SKrishna.Elango@Sun.COM {
71410187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p;
71510187SKrishna.Elango@Sun.COM 
71610187SKrishna.Elango@Sun.COM 	bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
71710187SKrishna.Elango@Sun.COM 	bus_p->bus_dip = dip;
71810187SKrishna.Elango@Sun.COM 	bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO;
71910187SKrishna.Elango@Sun.COM 	bus_p->bus_hdr_type = PCI_HEADER_ONE;
72010187SKrishna.Elango@Sun.COM 
72110187SKrishna.Elango@Sun.COM 	/* Fake that there are AER logs */
72210187SKrishna.Elango@Sun.COM 	bus_p->bus_aer_off = (uint16_t)-1;
72310187SKrishna.Elango@Sun.COM 
72410187SKrishna.Elango@Sun.COM 	/* Needed only for handle lookup */
72510187SKrishna.Elango@Sun.COM 	bus_p->bus_fm_flags |= PF_FM_READY;
72610187SKrishna.Elango@Sun.COM 
72710187SKrishna.Elango@Sun.COM 	ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p);
72810187SKrishna.Elango@Sun.COM }
72910187SKrishna.Elango@Sun.COM 
73010187SKrishna.Elango@Sun.COM void
73110187SKrishna.Elango@Sun.COM pcie_rc_fini_bus(dev_info_t *dip)
73210187SKrishna.Elango@Sun.COM {
73310187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = (pcie_bus_t *)ndi_get_bus_private(dip, B_FALSE);
734*10923SEvan.Yan@Sun.COM 
73510187SKrishna.Elango@Sun.COM 	ndi_set_bus_private(dip, B_FALSE, NULL, NULL);
73610187SKrishna.Elango@Sun.COM 	kmem_free(bus_p, sizeof (pcie_bus_t));
73710187SKrishna.Elango@Sun.COM }
73810187SKrishna.Elango@Sun.COM 
73910187SKrishna.Elango@Sun.COM /*
74010187SKrishna.Elango@Sun.COM  * Initialize PCIe Bus Private Data
74110187SKrishna.Elango@Sun.COM  *
74210187SKrishna.Elango@Sun.COM  * PCIe Bus Private Data contains commonly used PCI/PCIe information and offsets
74310187SKrishna.Elango@Sun.COM  * to key registers.
74410187SKrishna.Elango@Sun.COM  */
74510187SKrishna.Elango@Sun.COM pcie_bus_t *
74610187SKrishna.Elango@Sun.COM pcie_init_bus(dev_info_t *cdip)
74710187SKrishna.Elango@Sun.COM {
74810187SKrishna.Elango@Sun.COM 	pcie_bus_t		*bus_p = 0;
74910187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t	eh = NULL;
75010187SKrishna.Elango@Sun.COM 	int			range_size;
75110187SKrishna.Elango@Sun.COM 	dev_info_t		*pdip;
75210187SKrishna.Elango@Sun.COM 	const char		*errstr = NULL;
75310187SKrishna.Elango@Sun.COM 
75410187SKrishna.Elango@Sun.COM 	ASSERT(PCIE_DIP2UPBUS(cdip) == NULL);
75510187SKrishna.Elango@Sun.COM 
75610187SKrishna.Elango@Sun.COM 	/* allocate memory for pcie bus data */
75710187SKrishna.Elango@Sun.COM 	bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
75810187SKrishna.Elango@Sun.COM 
75910187SKrishna.Elango@Sun.COM 	/* Set back pointer to dip */
76010187SKrishna.Elango@Sun.COM 	bus_p->bus_dip = cdip;
76110187SKrishna.Elango@Sun.COM 
76210187SKrishna.Elango@Sun.COM 	/* Create an config access special to error handling */
76310187SKrishna.Elango@Sun.COM 	if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
76410187SKrishna.Elango@Sun.COM 		errstr = "Cannot setup config access";
76510187SKrishna.Elango@Sun.COM 		goto fail;
76610187SKrishna.Elango@Sun.COM 	}
767*10923SEvan.Yan@Sun.COM 
76810187SKrishna.Elango@Sun.COM 	bus_p->bus_cfg_hdl = eh;
76910187SKrishna.Elango@Sun.COM 	bus_p->bus_fm_flags = 0;
770*10923SEvan.Yan@Sun.COM 	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
77110187SKrishna.Elango@Sun.COM 
77210187SKrishna.Elango@Sun.COM 	/* get device's bus/dev/function number */
77310187SKrishna.Elango@Sun.COM 	if (pcie_get_bdf_from_dip(cdip, &bus_p->bus_bdf) != DDI_SUCCESS) {
77410187SKrishna.Elango@Sun.COM 		errstr = "Cannot get device BDF";
77510187SKrishna.Elango@Sun.COM 		goto fail;
77610187SKrishna.Elango@Sun.COM 	}
77710187SKrishna.Elango@Sun.COM 
77810187SKrishna.Elango@Sun.COM 	/* Save the Vendor Id Device Id */
77910187SKrishna.Elango@Sun.COM 	bus_p->bus_dev_ven_id = PCIE_GET(32, bus_p, PCI_CONF_VENID);
78010187SKrishna.Elango@Sun.COM 	bus_p->bus_rev_id = PCIE_GET(8, bus_p, PCI_CONF_REVID);
78110187SKrishna.Elango@Sun.COM 
78210187SKrishna.Elango@Sun.COM 	/* Save the Header Type */
78310187SKrishna.Elango@Sun.COM 	bus_p->bus_hdr_type = PCIE_GET(8, bus_p, PCI_CONF_HEADER);
78410187SKrishna.Elango@Sun.COM 	bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
78510187SKrishna.Elango@Sun.COM 
78610187SKrishna.Elango@Sun.COM 	/* Figure out the device type and all the relavant capability offsets */
78710187SKrishna.Elango@Sun.COM 	if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_E, &bus_p->bus_pcie_off))
78810187SKrishna.Elango@Sun.COM 	    != DDI_FAILURE) {
78910187SKrishna.Elango@Sun.COM 		bus_p->bus_dev_type = PCI_CAP_GET16(eh, NULL,
79010187SKrishna.Elango@Sun.COM 		    bus_p->bus_pcie_off, PCIE_PCIECAP) &
79110187SKrishna.Elango@Sun.COM 		    PCIE_PCIECAP_DEV_TYPE_MASK;
79210187SKrishna.Elango@Sun.COM 
79310187SKrishna.Elango@Sun.COM 		if (PCI_CAP_LOCATE(eh, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_AER),
79410187SKrishna.Elango@Sun.COM 		    &bus_p->bus_aer_off) != DDI_SUCCESS)
79510187SKrishna.Elango@Sun.COM 			bus_p->bus_aer_off = NULL;
796*10923SEvan.Yan@Sun.COM 
797*10923SEvan.Yan@Sun.COM 		/* Check and save PCIe hotplug capability information */
798*10923SEvan.Yan@Sun.COM 		if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
799*10923SEvan.Yan@Sun.COM 		    (PCI_CAP_GET16(eh, NULL, bus_p->bus_pcie_off, PCIE_PCIECAP)
800*10923SEvan.Yan@Sun.COM 		    & PCIE_PCIECAP_SLOT_IMPL) &&
801*10923SEvan.Yan@Sun.COM 		    (PCI_CAP_GET32(eh, NULL, bus_p->bus_pcie_off, PCIE_SLOTCAP)
802*10923SEvan.Yan@Sun.COM 		    & PCIE_SLOTCAP_HP_CAPABLE))
803*10923SEvan.Yan@Sun.COM 			bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
80410187SKrishna.Elango@Sun.COM 	} else {
80510187SKrishna.Elango@Sun.COM 		bus_p->bus_pcie_off = NULL;
80610187SKrishna.Elango@Sun.COM 		bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
80710187SKrishna.Elango@Sun.COM 	}
80810187SKrishna.Elango@Sun.COM 
80910187SKrishna.Elango@Sun.COM 	if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCIX, &bus_p->bus_pcix_off))
81010187SKrishna.Elango@Sun.COM 	    != DDI_FAILURE) {
81110187SKrishna.Elango@Sun.COM 		if (PCIE_IS_BDG(bus_p))
81210187SKrishna.Elango@Sun.COM 			bus_p->bus_ecc_ver = PCIX_CAP_GET(16, bus_p,
81310187SKrishna.Elango@Sun.COM 			    PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
81410187SKrishna.Elango@Sun.COM 		else
81510187SKrishna.Elango@Sun.COM 			bus_p->bus_ecc_ver = PCIX_CAP_GET(16, bus_p,
81610187SKrishna.Elango@Sun.COM 			    PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
81710187SKrishna.Elango@Sun.COM 	} else {
81810187SKrishna.Elango@Sun.COM 		bus_p->bus_pcix_off = NULL;
81910187SKrishna.Elango@Sun.COM 		bus_p->bus_ecc_ver = NULL;
82010187SKrishna.Elango@Sun.COM 	}
82110187SKrishna.Elango@Sun.COM 
82210187SKrishna.Elango@Sun.COM 	/* Save the Range information if device is a switch/bridge */
82310187SKrishna.Elango@Sun.COM 	if (PCIE_IS_BDG(bus_p)) {
824*10923SEvan.Yan@Sun.COM 		/* Check and save PCI hotplug (SHPC) capability information */
825*10923SEvan.Yan@Sun.COM 		if ((PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCI_HOTPLUG,
826*10923SEvan.Yan@Sun.COM 		    &bus_p->bus_pci_hp_off)) == DDI_SUCCESS)
827*10923SEvan.Yan@Sun.COM 			bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
828*10923SEvan.Yan@Sun.COM 
82910187SKrishna.Elango@Sun.COM 		/* get "bus_range" property */
83010187SKrishna.Elango@Sun.COM 		range_size = sizeof (pci_bus_range_t);
83110187SKrishna.Elango@Sun.COM 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
83210187SKrishna.Elango@Sun.COM 		    "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
83310187SKrishna.Elango@Sun.COM 		    != DDI_PROP_SUCCESS) {
83410187SKrishna.Elango@Sun.COM 			errstr = "Cannot find \"bus-range\" property";
83510187SKrishna.Elango@Sun.COM 			goto fail;
83610187SKrishna.Elango@Sun.COM 		}
83710187SKrishna.Elango@Sun.COM 
83810187SKrishna.Elango@Sun.COM 		/* get secondary bus number */
83910187SKrishna.Elango@Sun.COM 		bus_p->bus_bdg_secbus = PCIE_GET(8, bus_p, PCI_BCNF_SECBUS);
84010187SKrishna.Elango@Sun.COM 
84110187SKrishna.Elango@Sun.COM 		/* Get "ranges" property */
84210187SKrishna.Elango@Sun.COM 		if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
84310187SKrishna.Elango@Sun.COM 		    "ranges", (caddr_t)&bus_p->bus_addr_ranges,
84410187SKrishna.Elango@Sun.COM 		    &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
84510187SKrishna.Elango@Sun.COM 			bus_p->bus_addr_entries = 0;
84610187SKrishna.Elango@Sun.COM 		bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
84710187SKrishna.Elango@Sun.COM 	}
84810187SKrishna.Elango@Sun.COM 
84910187SKrishna.Elango@Sun.COM 	/* save "assigned-addresses" property array, ignore failues */
85010187SKrishna.Elango@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
85110187SKrishna.Elango@Sun.COM 	    "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
85210187SKrishna.Elango@Sun.COM 	    &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
85310187SKrishna.Elango@Sun.COM 		bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
85410187SKrishna.Elango@Sun.COM 	else
85510187SKrishna.Elango@Sun.COM 		bus_p->bus_assigned_entries = 0;
85610187SKrishna.Elango@Sun.COM 
85710187SKrishna.Elango@Sun.COM 	/* save RP dip and RP bdf */
85810187SKrishna.Elango@Sun.COM 	if (PCIE_IS_RP(bus_p)) {
85910187SKrishna.Elango@Sun.COM 		bus_p->bus_rp_dip = cdip;
86010187SKrishna.Elango@Sun.COM 		bus_p->bus_rp_bdf = bus_p->bus_bdf;
86110187SKrishna.Elango@Sun.COM 	} else {
86210187SKrishna.Elango@Sun.COM 		for (pdip = ddi_get_parent(cdip); pdip;
86310187SKrishna.Elango@Sun.COM 		    pdip = ddi_get_parent(pdip)) {
86410187SKrishna.Elango@Sun.COM 			pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
86510187SKrishna.Elango@Sun.COM 
86610187SKrishna.Elango@Sun.COM 			/*
86710187SKrishna.Elango@Sun.COM 			 * When debugging be aware that some NVIDIA x86
86810187SKrishna.Elango@Sun.COM 			 * architectures have 2 nodes for each RP, One at Bus
86910187SKrishna.Elango@Sun.COM 			 * 0x0 and one at Bus 0x80.  The requester is from Bus
87010187SKrishna.Elango@Sun.COM 			 * 0x80
87110187SKrishna.Elango@Sun.COM 			 */
87210187SKrishna.Elango@Sun.COM 			if (PCIE_IS_ROOT(parent_bus_p)) {
87310187SKrishna.Elango@Sun.COM 				bus_p->bus_rp_dip = pdip;
87410187SKrishna.Elango@Sun.COM 				bus_p->bus_rp_bdf = parent_bus_p->bus_bdf;
87510187SKrishna.Elango@Sun.COM 				break;
87610187SKrishna.Elango@Sun.COM 			}
87710187SKrishna.Elango@Sun.COM 		}
87810187SKrishna.Elango@Sun.COM 	}
87910187SKrishna.Elango@Sun.COM 
88010187SKrishna.Elango@Sun.COM 	ndi_set_bus_private(cdip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
88110187SKrishna.Elango@Sun.COM 
882*10923SEvan.Yan@Sun.COM 	if (PCIE_IS_HOTPLUG_CAPABLE(cdip))
883*10923SEvan.Yan@Sun.COM 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
884*10923SEvan.Yan@Sun.COM 		    "hotplug-capable");
885*10923SEvan.Yan@Sun.COM 
88610187SKrishna.Elango@Sun.COM 	pcie_init_pfd(cdip);
88710187SKrishna.Elango@Sun.COM 
88810187SKrishna.Elango@Sun.COM 	bus_p->bus_mps = 0;
88910187SKrishna.Elango@Sun.COM 
89010187SKrishna.Elango@Sun.COM 	pcie_init_plat(cdip);
89110187SKrishna.Elango@Sun.COM 
89210187SKrishna.Elango@Sun.COM 	PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
89310187SKrishna.Elango@Sun.COM 	    ddi_driver_name(cdip), (void *)cdip, bus_p->bus_bdf,
89410187SKrishna.Elango@Sun.COM 	    bus_p->bus_bdg_secbus);
89510187SKrishna.Elango@Sun.COM #ifdef DEBUG
89610187SKrishna.Elango@Sun.COM 	pcie_print_bus(bus_p);
89710187SKrishna.Elango@Sun.COM #endif
89810187SKrishna.Elango@Sun.COM 
89910187SKrishna.Elango@Sun.COM 	return (bus_p);
90010187SKrishna.Elango@Sun.COM fail:
90110187SKrishna.Elango@Sun.COM 	cmn_err(CE_WARN, "PCIE init err info failed BDF 0x%x:%s\n",
90210187SKrishna.Elango@Sun.COM 	    bus_p->bus_bdf, errstr);
90310187SKrishna.Elango@Sun.COM 	if (eh)
90410187SKrishna.Elango@Sun.COM 		pci_config_teardown(&eh);
90510187SKrishna.Elango@Sun.COM 	kmem_free(bus_p, sizeof (pcie_bus_t));
90610187SKrishna.Elango@Sun.COM 	return (NULL);
90710187SKrishna.Elango@Sun.COM }
90810187SKrishna.Elango@Sun.COM 
90910187SKrishna.Elango@Sun.COM int
91010187SKrishna.Elango@Sun.COM pcie_postattach_child(dev_info_t *cdip)
91110187SKrishna.Elango@Sun.COM {
91210187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
91310187SKrishna.Elango@Sun.COM 
91410187SKrishna.Elango@Sun.COM 	if (!bus_p)
91510187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
91610187SKrishna.Elango@Sun.COM 
91710187SKrishna.Elango@Sun.COM 	return (pcie_enable_ce(cdip));
91810187SKrishna.Elango@Sun.COM }
91910187SKrishna.Elango@Sun.COM 
92010187SKrishna.Elango@Sun.COM /*
92110187SKrishna.Elango@Sun.COM  * PCI-Express child device de-initialization.
92210187SKrishna.Elango@Sun.COM  * This function disables generic pci-express interrupts and error
92310187SKrishna.Elango@Sun.COM  * handling.
92410187SKrishna.Elango@Sun.COM  */
92510187SKrishna.Elango@Sun.COM void
92610187SKrishna.Elango@Sun.COM pcie_uninitchild(dev_info_t *cdip)
92710187SKrishna.Elango@Sun.COM {
92810187SKrishna.Elango@Sun.COM 	pcie_disable_errors(cdip);
92910187SKrishna.Elango@Sun.COM 	pcie_fini_bus(cdip);
93010187SKrishna.Elango@Sun.COM }
93110187SKrishna.Elango@Sun.COM 
93210187SKrishna.Elango@Sun.COM void
93310187SKrishna.Elango@Sun.COM pcie_fini_bus(dev_info_t *cdip)
93410187SKrishna.Elango@Sun.COM {
93510187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p;
93610187SKrishna.Elango@Sun.COM 
93710187SKrishna.Elango@Sun.COM 	pcie_fini_plat(cdip);
93810187SKrishna.Elango@Sun.COM 	pcie_fini_pfd(cdip);
93910187SKrishna.Elango@Sun.COM 
94010187SKrishna.Elango@Sun.COM 	bus_p = PCIE_DIP2UPBUS(cdip);
94110187SKrishna.Elango@Sun.COM 	ASSERT(bus_p);
942*10923SEvan.Yan@Sun.COM 
943*10923SEvan.Yan@Sun.COM 	if (PCIE_IS_HOTPLUG_CAPABLE(cdip))
944*10923SEvan.Yan@Sun.COM 		(void) ndi_prop_remove(DDI_DEV_T_NONE, cdip, "hotplug-capable");
945*10923SEvan.Yan@Sun.COM 
94610187SKrishna.Elango@Sun.COM 	pci_config_teardown(&bus_p->bus_cfg_hdl);
94710187SKrishna.Elango@Sun.COM 	ndi_set_bus_private(cdip, B_TRUE, NULL, NULL);
94810187SKrishna.Elango@Sun.COM 	kmem_free(bus_p->bus_assigned_addr,
94910187SKrishna.Elango@Sun.COM 	    (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
95010187SKrishna.Elango@Sun.COM 	kmem_free(bus_p->bus_addr_ranges,
95110187SKrishna.Elango@Sun.COM 	    (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
95210187SKrishna.Elango@Sun.COM 
95310187SKrishna.Elango@Sun.COM 	kmem_free(bus_p, sizeof (pcie_bus_t));
95410187SKrishna.Elango@Sun.COM }
95510187SKrishna.Elango@Sun.COM 
95610187SKrishna.Elango@Sun.COM void
95710187SKrishna.Elango@Sun.COM pcie_enable_errors(dev_info_t *dip)
95810187SKrishna.Elango@Sun.COM {
95910187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
96010187SKrishna.Elango@Sun.COM 	uint16_t	reg16, tmp16;
96110187SKrishna.Elango@Sun.COM 	uint32_t	reg32, tmp32;
96210187SKrishna.Elango@Sun.COM 
96310187SKrishna.Elango@Sun.COM 	ASSERT(bus_p);
96410187SKrishna.Elango@Sun.COM 
96510187SKrishna.Elango@Sun.COM 	/*
96610187SKrishna.Elango@Sun.COM 	 * Clear any pending errors
96710187SKrishna.Elango@Sun.COM 	 */
96810187SKrishna.Elango@Sun.COM 	pcie_clear_errors(dip);
96910187SKrishna.Elango@Sun.COM 
97010187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE(bus_p))
97110187SKrishna.Elango@Sun.COM 		return;
97210187SKrishna.Elango@Sun.COM 
97310187SKrishna.Elango@Sun.COM 	/*
97410187SKrishna.Elango@Sun.COM 	 * Enable Baseline Error Handling but leave CE reporting off (poweron
97510187SKrishna.Elango@Sun.COM 	 * default).
97610187SKrishna.Elango@Sun.COM 	 */
97710187SKrishna.Elango@Sun.COM 	if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) !=
97810187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16) {
97910187SKrishna.Elango@Sun.COM 		tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
98010187SKrishna.Elango@Sun.COM 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
98110187SKrishna.Elango@Sun.COM 		    (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
98210187SKrishna.Elango@Sun.COM 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
98310187SKrishna.Elango@Sun.COM 		    (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN));
98410187SKrishna.Elango@Sun.COM 
98510187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
98610187SKrishna.Elango@Sun.COM 		PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
98710187SKrishna.Elango@Sun.COM 	}
98810187SKrishna.Elango@Sun.COM 
98910187SKrishna.Elango@Sun.COM 	/* Enable Root Port Baseline Error Receiving */
99010187SKrishna.Elango@Sun.COM 	if (PCIE_IS_ROOT(bus_p) &&
99110187SKrishna.Elango@Sun.COM 	    (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) !=
99210187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16) {
99310187SKrishna.Elango@Sun.COM 
99410187SKrishna.Elango@Sun.COM #if defined(__xpv)
99510187SKrishna.Elango@Sun.COM 		/*
99610187SKrishna.Elango@Sun.COM 		 * When we're booted under the hypervisor we won't receive
99710187SKrishna.Elango@Sun.COM 		 * MSI's, so to ensure that uncorrectable errors aren't ignored
99810187SKrishna.Elango@Sun.COM 		 * we set the SERR_FAT and SERR_NONFAT bits in the Root Control
99910187SKrishna.Elango@Sun.COM 		 * Register.
100010187SKrishna.Elango@Sun.COM 		 */
100110187SKrishna.Elango@Sun.COM 		tmp16 = pcie_root_ctrl_default;
100210187SKrishna.Elango@Sun.COM #else
100310187SKrishna.Elango@Sun.COM 		tmp16 = pcie_serr_disable_flag ?
100410187SKrishna.Elango@Sun.COM 		    (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) :
100510187SKrishna.Elango@Sun.COM 		    pcie_root_ctrl_default;
100610187SKrishna.Elango@Sun.COM #endif /* __xpv */
100710187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16);
100810187SKrishna.Elango@Sun.COM 		PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL,
100910187SKrishna.Elango@Sun.COM 		    reg16);
101010187SKrishna.Elango@Sun.COM 	}
101110187SKrishna.Elango@Sun.COM 
101210187SKrishna.Elango@Sun.COM 	/*
101310187SKrishna.Elango@Sun.COM 	 * Enable PCI-Express Advanced Error Handling if Exists
101410187SKrishna.Elango@Sun.COM 	 */
101510187SKrishna.Elango@Sun.COM 	if (!PCIE_HAS_AER(bus_p))
101610187SKrishna.Elango@Sun.COM 		return;
101710187SKrishna.Elango@Sun.COM 
101810187SKrishna.Elango@Sun.COM 	/* Set Uncorrectable Severity */
101910187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) !=
102010187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
102110187SKrishna.Elango@Sun.COM 		tmp32 = pcie_aer_uce_severity;
102210187SKrishna.Elango@Sun.COM 
102310187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32);
102410187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV,
102510187SKrishna.Elango@Sun.COM 		    reg32);
102610187SKrishna.Elango@Sun.COM 	}
102710187SKrishna.Elango@Sun.COM 
102810187SKrishna.Elango@Sun.COM 	/* Enable Uncorrectable errors */
102910187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) !=
103010187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
103110187SKrishna.Elango@Sun.COM 		tmp32 = pcie_aer_uce_mask;
103210187SKrishna.Elango@Sun.COM 
103310187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32);
103410187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK,
103510187SKrishna.Elango@Sun.COM 		    reg32);
103610187SKrishna.Elango@Sun.COM 	}
103710187SKrishna.Elango@Sun.COM 
103810187SKrishna.Elango@Sun.COM 	/* Enable ECRC generation and checking */
103910187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
104010187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
104110187SKrishna.Elango@Sun.COM 		tmp32 = reg32 | pcie_ecrc_value;
104210187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32);
104310187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32);
104410187SKrishna.Elango@Sun.COM 	}
104510187SKrishna.Elango@Sun.COM 
104610187SKrishna.Elango@Sun.COM 	/* Enable Secondary Uncorrectable errors if this is a bridge */
104710187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE_BDG(bus_p))
104810187SKrishna.Elango@Sun.COM 		goto root;
104910187SKrishna.Elango@Sun.COM 
105010187SKrishna.Elango@Sun.COM 	/* Set Uncorrectable Severity */
105110187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) !=
105210187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
105310187SKrishna.Elango@Sun.COM 		tmp32 = pcie_aer_suce_severity;
105410187SKrishna.Elango@Sun.COM 
105510187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32);
105610187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV,
105710187SKrishna.Elango@Sun.COM 		    reg32);
105810187SKrishna.Elango@Sun.COM 	}
105910187SKrishna.Elango@Sun.COM 
106010187SKrishna.Elango@Sun.COM 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) !=
106110187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
106210187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask);
106310187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32,
106410187SKrishna.Elango@Sun.COM 		    PCIE_AER_SUCE_MASK, reg32);
106510187SKrishna.Elango@Sun.COM 	}
106610187SKrishna.Elango@Sun.COM 
106710187SKrishna.Elango@Sun.COM root:
106810187SKrishna.Elango@Sun.COM 	/*
106910187SKrishna.Elango@Sun.COM 	 * Enable Root Control this is a Root device
107010187SKrishna.Elango@Sun.COM 	 */
107110187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_ROOT(bus_p))
107210187SKrishna.Elango@Sun.COM 		return;
107310187SKrishna.Elango@Sun.COM 
107410187SKrishna.Elango@Sun.COM #if !defined(__xpv)
107510187SKrishna.Elango@Sun.COM 	if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
107610187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16) {
107710187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD,
107810187SKrishna.Elango@Sun.COM 		    pcie_root_error_cmd_default);
107910187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16,
108010187SKrishna.Elango@Sun.COM 		    PCIE_AER_RE_CMD, reg16);
108110187SKrishna.Elango@Sun.COM 	}
108210187SKrishna.Elango@Sun.COM #endif /* __xpv */
108310187SKrishna.Elango@Sun.COM }
108410187SKrishna.Elango@Sun.COM 
108510187SKrishna.Elango@Sun.COM /*
108610187SKrishna.Elango@Sun.COM  * This function is used for enabling CE reporting and setting the AER CE mask.
108710187SKrishna.Elango@Sun.COM  * When called from outside the pcie module it should always be preceded by
108810187SKrishna.Elango@Sun.COM  * a call to pcie_enable_errors.
108910187SKrishna.Elango@Sun.COM  */
109010187SKrishna.Elango@Sun.COM int
109110187SKrishna.Elango@Sun.COM pcie_enable_ce(dev_info_t *dip)
109210187SKrishna.Elango@Sun.COM {
109310187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
109410187SKrishna.Elango@Sun.COM 	uint16_t	device_sts, device_ctl;
109510187SKrishna.Elango@Sun.COM 	uint32_t	tmp_pcie_aer_ce_mask;
109610187SKrishna.Elango@Sun.COM 
109710187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE(bus_p))
109810187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
109910187SKrishna.Elango@Sun.COM 
110010187SKrishna.Elango@Sun.COM 	/*
110110187SKrishna.Elango@Sun.COM 	 * The "pcie_ce_mask" property is used to control both the CE reporting
110210187SKrishna.Elango@Sun.COM 	 * enable field in the device control register and the AER CE mask. We
110310187SKrishna.Elango@Sun.COM 	 * leave CE reporting disabled if pcie_ce_mask is set to -1.
110410187SKrishna.Elango@Sun.COM 	 */
110510187SKrishna.Elango@Sun.COM 
110610187SKrishna.Elango@Sun.COM 	tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
110710187SKrishna.Elango@Sun.COM 	    DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask);
110810187SKrishna.Elango@Sun.COM 
110910187SKrishna.Elango@Sun.COM 	if (tmp_pcie_aer_ce_mask == (uint32_t)-1) {
111010187SKrishna.Elango@Sun.COM 		/*
111110187SKrishna.Elango@Sun.COM 		 * Nothing to do since CE reporting has already been disabled.
111210187SKrishna.Elango@Sun.COM 		 */
111310187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
111410187SKrishna.Elango@Sun.COM 	}
111510187SKrishna.Elango@Sun.COM 
111610187SKrishna.Elango@Sun.COM 	if (PCIE_HAS_AER(bus_p)) {
111710187SKrishna.Elango@Sun.COM 		/* Enable AER CE */
111810187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask);
111910187SKrishna.Elango@Sun.COM 		PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK,
112010187SKrishna.Elango@Sun.COM 		    0);
112110187SKrishna.Elango@Sun.COM 
112210187SKrishna.Elango@Sun.COM 		/* Clear any pending AER CE errors */
112310187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1);
112410187SKrishna.Elango@Sun.COM 	}
112510187SKrishna.Elango@Sun.COM 
112610187SKrishna.Elango@Sun.COM 	/* clear any pending CE errors */
112710187SKrishna.Elango@Sun.COM 	if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) !=
112810187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16)
112910187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS,
113010187SKrishna.Elango@Sun.COM 		    device_sts & (~PCIE_DEVSTS_CE_DETECTED));
113110187SKrishna.Elango@Sun.COM 
113210187SKrishna.Elango@Sun.COM 	/* Enable CE reporting */
113310187SKrishna.Elango@Sun.COM 	device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
113410187SKrishna.Elango@Sun.COM 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL,
113510187SKrishna.Elango@Sun.COM 	    (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default);
113610187SKrishna.Elango@Sun.COM 	PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl);
113710187SKrishna.Elango@Sun.COM 
113810187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
113910187SKrishna.Elango@Sun.COM }
114010187SKrishna.Elango@Sun.COM 
114110187SKrishna.Elango@Sun.COM /* ARGSUSED */
114210187SKrishna.Elango@Sun.COM void
114310187SKrishna.Elango@Sun.COM pcie_disable_errors(dev_info_t *dip)
114410187SKrishna.Elango@Sun.COM {
114510187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
114610187SKrishna.Elango@Sun.COM 	uint16_t	device_ctl;
114710187SKrishna.Elango@Sun.COM 	uint32_t	aer_reg;
114810187SKrishna.Elango@Sun.COM 
114910187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE(bus_p))
115010187SKrishna.Elango@Sun.COM 		return;
115110187SKrishna.Elango@Sun.COM 
115210187SKrishna.Elango@Sun.COM 	/*
115310187SKrishna.Elango@Sun.COM 	 * Disable PCI-Express Baseline Error Handling
115410187SKrishna.Elango@Sun.COM 	 */
115510187SKrishna.Elango@Sun.COM 	device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
115610187SKrishna.Elango@Sun.COM 	device_ctl &= ~PCIE_DEVCTL_ERR_MASK;
115710187SKrishna.Elango@Sun.COM 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl);
115810187SKrishna.Elango@Sun.COM 
115910187SKrishna.Elango@Sun.COM 	/*
116010187SKrishna.Elango@Sun.COM 	 * Disable PCI-Express Advanced Error Handling if Exists
116110187SKrishna.Elango@Sun.COM 	 */
116210187SKrishna.Elango@Sun.COM 	if (!PCIE_HAS_AER(bus_p))
116310187SKrishna.Elango@Sun.COM 		goto root;
116410187SKrishna.Elango@Sun.COM 
116510187SKrishna.Elango@Sun.COM 	/* Disable Uncorrectable errors */
116610187SKrishna.Elango@Sun.COM 	PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS);
116710187SKrishna.Elango@Sun.COM 
116810187SKrishna.Elango@Sun.COM 	/* Disable Correctable errors */
116910187SKrishna.Elango@Sun.COM 	PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS);
117010187SKrishna.Elango@Sun.COM 
117110187SKrishna.Elango@Sun.COM 	/* Disable ECRC generation and checking */
117210187SKrishna.Elango@Sun.COM 	if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
117310187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL32) {
117410187SKrishna.Elango@Sun.COM 		aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA |
117510187SKrishna.Elango@Sun.COM 		    PCIE_AER_CTL_ECRC_CHECK_ENA);
117610187SKrishna.Elango@Sun.COM 
117710187SKrishna.Elango@Sun.COM 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg);
117810187SKrishna.Elango@Sun.COM 	}
117910187SKrishna.Elango@Sun.COM 	/*
118010187SKrishna.Elango@Sun.COM 	 * Disable Secondary Uncorrectable errors if this is a bridge
118110187SKrishna.Elango@Sun.COM 	 */
118210187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_PCIE_BDG(bus_p))
118310187SKrishna.Elango@Sun.COM 		goto root;
118410187SKrishna.Elango@Sun.COM 
118510187SKrishna.Elango@Sun.COM 	PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS);
118610187SKrishna.Elango@Sun.COM 
118710187SKrishna.Elango@Sun.COM root:
118810187SKrishna.Elango@Sun.COM 	/*
118910187SKrishna.Elango@Sun.COM 	 * disable Root Control this is a Root device
119010187SKrishna.Elango@Sun.COM 	 */
119110187SKrishna.Elango@Sun.COM 	if (!PCIE_IS_ROOT(bus_p))
119210187SKrishna.Elango@Sun.COM 		return;
119310187SKrishna.Elango@Sun.COM 
119410187SKrishna.Elango@Sun.COM 	if (!pcie_serr_disable_flag) {
119510187SKrishna.Elango@Sun.COM 		device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL);
119610187SKrishna.Elango@Sun.COM 		device_ctl &= ~PCIE_ROOT_SYS_ERR;
119710187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl);
119810187SKrishna.Elango@Sun.COM 	}
119910187SKrishna.Elango@Sun.COM 
120010187SKrishna.Elango@Sun.COM 	if (!PCIE_HAS_AER(bus_p))
120110187SKrishna.Elango@Sun.COM 		return;
120210187SKrishna.Elango@Sun.COM 
120310187SKrishna.Elango@Sun.COM 	if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
120410187SKrishna.Elango@Sun.COM 	    PCI_CAP_EINVAL16) {
120510187SKrishna.Elango@Sun.COM 		device_ctl &= ~pcie_root_error_cmd_default;
120610187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl);
120710187SKrishna.Elango@Sun.COM 	}
120810187SKrishna.Elango@Sun.COM }
120910187SKrishna.Elango@Sun.COM 
121010187SKrishna.Elango@Sun.COM /*
121110187SKrishna.Elango@Sun.COM  * Extract bdf from "reg" property.
121210187SKrishna.Elango@Sun.COM  */
121310187SKrishna.Elango@Sun.COM int
121410187SKrishna.Elango@Sun.COM pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf)
121510187SKrishna.Elango@Sun.COM {
121610187SKrishna.Elango@Sun.COM 	pci_regspec_t	*regspec;
121710187SKrishna.Elango@Sun.COM 	int		reglen;
121810187SKrishna.Elango@Sun.COM 
121910187SKrishna.Elango@Sun.COM 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
122010187SKrishna.Elango@Sun.COM 	    "reg", (int **)&regspec, (uint_t *)&reglen) != DDI_SUCCESS)
122110187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
122210187SKrishna.Elango@Sun.COM 
122310187SKrishna.Elango@Sun.COM 	if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) {
122410187SKrishna.Elango@Sun.COM 		ddi_prop_free(regspec);
122510187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
122610187SKrishna.Elango@Sun.COM 	}
122710187SKrishna.Elango@Sun.COM 
122810187SKrishna.Elango@Sun.COM 	/* Get phys_hi from first element.  All have same bdf. */
122910187SKrishna.Elango@Sun.COM 	*bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8;
123010187SKrishna.Elango@Sun.COM 
123110187SKrishna.Elango@Sun.COM 	ddi_prop_free(regspec);
123210187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
123310187SKrishna.Elango@Sun.COM }
123410187SKrishna.Elango@Sun.COM 
123510187SKrishna.Elango@Sun.COM dev_info_t *
123610187SKrishna.Elango@Sun.COM pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip)
123710187SKrishna.Elango@Sun.COM {
123810187SKrishna.Elango@Sun.COM 	dev_info_t *cdip = rdip;
123910187SKrishna.Elango@Sun.COM 
124010187SKrishna.Elango@Sun.COM 	for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip))
124110187SKrishna.Elango@Sun.COM 		;
124210187SKrishna.Elango@Sun.COM 
124310187SKrishna.Elango@Sun.COM 	return (cdip);
124410187SKrishna.Elango@Sun.COM }
124510187SKrishna.Elango@Sun.COM 
124610187SKrishna.Elango@Sun.COM uint32_t
124710187SKrishna.Elango@Sun.COM pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
124810187SKrishna.Elango@Sun.COM {
124910187SKrishna.Elango@Sun.COM 	dev_info_t *cdip;
125010187SKrishna.Elango@Sun.COM 
125110187SKrishna.Elango@Sun.COM 	/*
125210187SKrishna.Elango@Sun.COM 	 * As part of the probing, the PCI fcode interpreter may setup a DMA
125310187SKrishna.Elango@Sun.COM 	 * request if a given card has a fcode on it using dip and rdip of the
1254*10923SEvan.Yan@Sun.COM 	 * hotplug connector i.e, dip and rdip of px/pcieb driver. In this
125510187SKrishna.Elango@Sun.COM 	 * case, return a invalid value for the bdf since we cannot get to the
125610187SKrishna.Elango@Sun.COM 	 * bdf value of the actual device which will be initiating this DMA.
125710187SKrishna.Elango@Sun.COM 	 */
125810187SKrishna.Elango@Sun.COM 	if (rdip == dip)
125910187SKrishna.Elango@Sun.COM 		return (PCIE_INVALID_BDF);
126010187SKrishna.Elango@Sun.COM 
126110187SKrishna.Elango@Sun.COM 	cdip = pcie_get_my_childs_dip(dip, rdip);
126210187SKrishna.Elango@Sun.COM 
126310187SKrishna.Elango@Sun.COM 	/*
126410187SKrishna.Elango@Sun.COM 	 * For a given rdip, return the bdf value of dip's (px or pcieb)
126510187SKrishna.Elango@Sun.COM 	 * immediate child or secondary bus-id if dip is a PCIe2PCI bridge.
126610187SKrishna.Elango@Sun.COM 	 *
126710187SKrishna.Elango@Sun.COM 	 * XXX - For now, return a invalid bdf value for all PCI and PCI-X
126810187SKrishna.Elango@Sun.COM 	 * devices since this needs more work.
126910187SKrishna.Elango@Sun.COM 	 */
127010187SKrishna.Elango@Sun.COM 	return (PCI_GET_PCIE2PCI_SECBUS(cdip) ?
127110187SKrishna.Elango@Sun.COM 	    PCIE_INVALID_BDF : PCI_GET_BDF(cdip));
127210187SKrishna.Elango@Sun.COM }
127310187SKrishna.Elango@Sun.COM 
127410187SKrishna.Elango@Sun.COM uint32_t
127510187SKrishna.Elango@Sun.COM pcie_get_aer_uce_mask() {
127610187SKrishna.Elango@Sun.COM 	return (pcie_aer_uce_mask);
127710187SKrishna.Elango@Sun.COM }
127810187SKrishna.Elango@Sun.COM uint32_t
127910187SKrishna.Elango@Sun.COM pcie_get_aer_ce_mask() {
128010187SKrishna.Elango@Sun.COM 	return (pcie_aer_ce_mask);
128110187SKrishna.Elango@Sun.COM }
128210187SKrishna.Elango@Sun.COM uint32_t
128310187SKrishna.Elango@Sun.COM pcie_get_aer_suce_mask() {
128410187SKrishna.Elango@Sun.COM 	return (pcie_aer_suce_mask);
128510187SKrishna.Elango@Sun.COM }
128610187SKrishna.Elango@Sun.COM uint32_t
128710187SKrishna.Elango@Sun.COM pcie_get_serr_mask() {
128810187SKrishna.Elango@Sun.COM 	return (pcie_serr_disable_flag);
128910187SKrishna.Elango@Sun.COM }
129010187SKrishna.Elango@Sun.COM 
129110187SKrishna.Elango@Sun.COM void
129210187SKrishna.Elango@Sun.COM pcie_set_aer_uce_mask(uint32_t mask) {
129310187SKrishna.Elango@Sun.COM 	pcie_aer_uce_mask = mask;
129410187SKrishna.Elango@Sun.COM 	if (mask & PCIE_AER_UCE_UR)
129510187SKrishna.Elango@Sun.COM 		pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN;
129610187SKrishna.Elango@Sun.COM 	else
129710187SKrishna.Elango@Sun.COM 		pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN;
129810187SKrishna.Elango@Sun.COM 
129910187SKrishna.Elango@Sun.COM 	if (mask & PCIE_AER_UCE_ECRC)
130010187SKrishna.Elango@Sun.COM 		pcie_ecrc_value = 0;
130110187SKrishna.Elango@Sun.COM }
130210187SKrishna.Elango@Sun.COM 
130310187SKrishna.Elango@Sun.COM void
130410187SKrishna.Elango@Sun.COM pcie_set_aer_ce_mask(uint32_t mask) {
130510187SKrishna.Elango@Sun.COM 	pcie_aer_ce_mask = mask;
130610187SKrishna.Elango@Sun.COM }
130710187SKrishna.Elango@Sun.COM void
130810187SKrishna.Elango@Sun.COM pcie_set_aer_suce_mask(uint32_t mask) {
130910187SKrishna.Elango@Sun.COM 	pcie_aer_suce_mask = mask;
131010187SKrishna.Elango@Sun.COM }
131110187SKrishna.Elango@Sun.COM void
131210187SKrishna.Elango@Sun.COM pcie_set_serr_mask(uint32_t mask) {
131310187SKrishna.Elango@Sun.COM 	pcie_serr_disable_flag = mask;
131410187SKrishna.Elango@Sun.COM }
131510187SKrishna.Elango@Sun.COM 
131610187SKrishna.Elango@Sun.COM /*
131710187SKrishna.Elango@Sun.COM  * Is the rdip a child of dip.	Used for checking certain CTLOPS from bubbling
131810187SKrishna.Elango@Sun.COM  * up erronously.  Ex.	ISA ctlops to a PCI-PCI Bridge.
131910187SKrishna.Elango@Sun.COM  */
132010187SKrishna.Elango@Sun.COM boolean_t
132110187SKrishna.Elango@Sun.COM pcie_is_child(dev_info_t *dip, dev_info_t *rdip)
132210187SKrishna.Elango@Sun.COM {
132310187SKrishna.Elango@Sun.COM 	dev_info_t	*cdip = ddi_get_child(dip);
132410187SKrishna.Elango@Sun.COM 	for (; cdip; cdip = ddi_get_next_sibling(cdip))
132510187SKrishna.Elango@Sun.COM 		if (cdip == rdip)
132610187SKrishna.Elango@Sun.COM 			break;
132710187SKrishna.Elango@Sun.COM 	return (cdip != NULL);
132810187SKrishna.Elango@Sun.COM }
132910187SKrishna.Elango@Sun.COM 
133010187SKrishna.Elango@Sun.COM boolean_t
133110187SKrishna.Elango@Sun.COM pcie_is_link_disabled(dev_info_t *dip)
133210187SKrishna.Elango@Sun.COM {
133310187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
133410187SKrishna.Elango@Sun.COM 
133510187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p)) {
133610187SKrishna.Elango@Sun.COM 		if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) &
133710187SKrishna.Elango@Sun.COM 		    PCIE_LINKCTL_LINK_DISABLE)
133810187SKrishna.Elango@Sun.COM 			return (B_TRUE);
133910187SKrishna.Elango@Sun.COM 	}
134010187SKrishna.Elango@Sun.COM 	return (B_FALSE);
134110187SKrishna.Elango@Sun.COM }
134210187SKrishna.Elango@Sun.COM 
134310187SKrishna.Elango@Sun.COM /*
134410187SKrishna.Elango@Sun.COM  * Initialize the MPS for a root port.
134510187SKrishna.Elango@Sun.COM  *
134610187SKrishna.Elango@Sun.COM  * dip - dip of root port device.
134710187SKrishna.Elango@Sun.COM  */
134810187SKrishna.Elango@Sun.COM void
134910187SKrishna.Elango@Sun.COM pcie_init_root_port_mps(dev_info_t *dip)
135010187SKrishna.Elango@Sun.COM {
135110187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
135210187SKrishna.Elango@Sun.COM 	int rp_cap, max_supported = pcie_max_mps;
135310187SKrishna.Elango@Sun.COM 
135410187SKrishna.Elango@Sun.COM 	(void) pcie_get_fabric_mps(ddi_get_parent(dip),
135510187SKrishna.Elango@Sun.COM 	    ddi_get_child(dip), &max_supported);
135610187SKrishna.Elango@Sun.COM 
135710187SKrishna.Elango@Sun.COM 	rp_cap = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL,
135810187SKrishna.Elango@Sun.COM 	    bus_p->bus_pcie_off, PCIE_DEVCAP) &
135910187SKrishna.Elango@Sun.COM 	    PCIE_DEVCAP_MAX_PAYLOAD_MASK;
136010187SKrishna.Elango@Sun.COM 
136110187SKrishna.Elango@Sun.COM 	if (rp_cap < max_supported)
136210187SKrishna.Elango@Sun.COM 		max_supported = rp_cap;
136310187SKrishna.Elango@Sun.COM 
136410187SKrishna.Elango@Sun.COM 	bus_p->bus_mps = max_supported;
136510187SKrishna.Elango@Sun.COM 	(void) pcie_initchild_mps(dip);
136610187SKrishna.Elango@Sun.COM }
136710187SKrishna.Elango@Sun.COM 
136810187SKrishna.Elango@Sun.COM /*
136910187SKrishna.Elango@Sun.COM  * Initialize the Maximum Payload Size of a device.
137010187SKrishna.Elango@Sun.COM  *
137110187SKrishna.Elango@Sun.COM  * cdip - dip of device.
137210187SKrishna.Elango@Sun.COM  *
137310187SKrishna.Elango@Sun.COM  * returns - DDI_SUCCESS or DDI_FAILURE
137410187SKrishna.Elango@Sun.COM  */
137510187SKrishna.Elango@Sun.COM int
137610187SKrishna.Elango@Sun.COM pcie_initchild_mps(dev_info_t *cdip)
137710187SKrishna.Elango@Sun.COM {
137810187SKrishna.Elango@Sun.COM 	int		max_payload_size;
137910187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p;
138010187SKrishna.Elango@Sun.COM 	dev_info_t	*pdip = ddi_get_parent(cdip);
1381*10923SEvan.Yan@Sun.COM 	uint8_t		dev_type;
138210187SKrishna.Elango@Sun.COM 
138310187SKrishna.Elango@Sun.COM 	bus_p = PCIE_DIP2BUS(cdip);
138410187SKrishna.Elango@Sun.COM 	if (bus_p == NULL) {
138510187SKrishna.Elango@Sun.COM 		PCIE_DBG("%s: BUS not found.\n",
138610187SKrishna.Elango@Sun.COM 		    ddi_driver_name(cdip));
138710187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
138810187SKrishna.Elango@Sun.COM 	}
138910187SKrishna.Elango@Sun.COM 
1390*10923SEvan.Yan@Sun.COM 	dev_type = bus_p->bus_dev_type;
1391*10923SEvan.Yan@Sun.COM 
1392*10923SEvan.Yan@Sun.COM 	/*
1393*10923SEvan.Yan@Sun.COM 	 * For ARI Devices, only function zero's MPS needs to be set.
1394*10923SEvan.Yan@Sun.COM 	 */
1395*10923SEvan.Yan@Sun.COM 	if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
1396*10923SEvan.Yan@Sun.COM 	    (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) {
1397*10923SEvan.Yan@Sun.COM 		pcie_req_id_t child_bdf;
1398*10923SEvan.Yan@Sun.COM 
1399*10923SEvan.Yan@Sun.COM 		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
1400*10923SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
1401*10923SEvan.Yan@Sun.COM 		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0)
1402*10923SEvan.Yan@Sun.COM 			return (DDI_SUCCESS);
1403*10923SEvan.Yan@Sun.COM 	}
1404*10923SEvan.Yan@Sun.COM 
140510187SKrishna.Elango@Sun.COM 	if (PCIE_IS_RP(bus_p)) {
140610187SKrishna.Elango@Sun.COM 		/*
140710187SKrishna.Elango@Sun.COM 		 * If this device is a root port, then the mps scan
140810187SKrishna.Elango@Sun.COM 		 * saved the mps in the root ports bus_p.
140910187SKrishna.Elango@Sun.COM 		 */
141010187SKrishna.Elango@Sun.COM 		max_payload_size = bus_p->bus_mps;
141110187SKrishna.Elango@Sun.COM 	} else {
141210187SKrishna.Elango@Sun.COM 		/*
141310187SKrishna.Elango@Sun.COM 		 * If the device is not a root port, then the mps of
141410187SKrishna.Elango@Sun.COM 		 * its parent should be used.
141510187SKrishna.Elango@Sun.COM 		 */
141610187SKrishna.Elango@Sun.COM 		pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
141710187SKrishna.Elango@Sun.COM 		max_payload_size = parent_bus_p->bus_mps;
141810187SKrishna.Elango@Sun.COM 	}
141910187SKrishna.Elango@Sun.COM 
142010187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCIE(bus_p) && (max_payload_size >= 0)) {
142110187SKrishna.Elango@Sun.COM 		pcie_bus_t *rootp_bus_p = PCIE_DIP2BUS(bus_p->bus_rp_dip);
142210187SKrishna.Elango@Sun.COM 		uint16_t mask, dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL),
142310187SKrishna.Elango@Sun.COM 		    mps = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) &
142410187SKrishna.Elango@Sun.COM 		    PCIE_DEVCAP_MAX_PAYLOAD_MASK;
142510187SKrishna.Elango@Sun.COM 
142610187SKrishna.Elango@Sun.COM 		mps = MIN(mps, (uint16_t)max_payload_size);
142710187SKrishna.Elango@Sun.COM 
142810187SKrishna.Elango@Sun.COM 		/*
142910187SKrishna.Elango@Sun.COM 		 * If the MPS to be set is less than the root ports
143010187SKrishna.Elango@Sun.COM 		 * MPS, then MRRS will have to be set the same as MPS.
143110187SKrishna.Elango@Sun.COM 		 */
143210187SKrishna.Elango@Sun.COM 		mask = ((mps < rootp_bus_p->bus_mps) ?
143310187SKrishna.Elango@Sun.COM 		    PCIE_DEVCTL_MAX_READ_REQ_MASK : 0) |
143410187SKrishna.Elango@Sun.COM 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK;
143510187SKrishna.Elango@Sun.COM 
143610187SKrishna.Elango@Sun.COM 		dev_ctrl &= ~mask;
143710187SKrishna.Elango@Sun.COM 		mask = ((mps < rootp_bus_p->bus_mps)
143810187SKrishna.Elango@Sun.COM 		    ? mps << PCIE_DEVCTL_MAX_READ_REQ_SHIFT : 0)
143910187SKrishna.Elango@Sun.COM 		    | (mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT);
144010187SKrishna.Elango@Sun.COM 
144110187SKrishna.Elango@Sun.COM 		dev_ctrl |= mask;
144210187SKrishna.Elango@Sun.COM 
144310187SKrishna.Elango@Sun.COM 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl);
144410187SKrishna.Elango@Sun.COM 
144510187SKrishna.Elango@Sun.COM 		bus_p->bus_mps = mps;
144610187SKrishna.Elango@Sun.COM 	}
1447*10923SEvan.Yan@Sun.COM 
144810187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
144910187SKrishna.Elango@Sun.COM }
145010187SKrishna.Elango@Sun.COM 
145110187SKrishna.Elango@Sun.COM /*
145210187SKrishna.Elango@Sun.COM  * Scans a device tree/branch for a maximum payload size capabilities.
145310187SKrishna.Elango@Sun.COM  *
145410187SKrishna.Elango@Sun.COM  * rc_dip - dip of Root Complex.
145510187SKrishna.Elango@Sun.COM  * dip - dip of device where scan will begin.
145610187SKrishna.Elango@Sun.COM  * max_supported (IN) - maximum allowable MPS.
145710187SKrishna.Elango@Sun.COM  * max_supported (OUT) - maximum payload size capability of fabric.
145810187SKrishna.Elango@Sun.COM  */
145910187SKrishna.Elango@Sun.COM void
146010187SKrishna.Elango@Sun.COM pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
146110187SKrishna.Elango@Sun.COM {
146210187SKrishna.Elango@Sun.COM 	if (dip == NULL)
146310187SKrishna.Elango@Sun.COM 		return;
146410187SKrishna.Elango@Sun.COM 
146510187SKrishna.Elango@Sun.COM 	/*
146610187SKrishna.Elango@Sun.COM 	 * Perform a fabric scan to obtain Maximum Payload Capabilities
146710187SKrishna.Elango@Sun.COM 	 */
146810187SKrishna.Elango@Sun.COM 	(void) pcie_scan_mps(rc_dip, dip, max_supported);
146910187SKrishna.Elango@Sun.COM 
147010187SKrishna.Elango@Sun.COM 	PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported);
147110187SKrishna.Elango@Sun.COM }
147210187SKrishna.Elango@Sun.COM 
147310187SKrishna.Elango@Sun.COM /*
147410187SKrishna.Elango@Sun.COM  * Scans fabric and determines Maximum Payload Size based on
147510187SKrishna.Elango@Sun.COM  * highest common denominator alogorithm
147610187SKrishna.Elango@Sun.COM  */
147710187SKrishna.Elango@Sun.COM static void
147810187SKrishna.Elango@Sun.COM pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
147910187SKrishna.Elango@Sun.COM {
148010187SKrishna.Elango@Sun.COM 	int circular_count;
148110187SKrishna.Elango@Sun.COM 	pcie_max_supported_t max_pay_load_supported;
148210187SKrishna.Elango@Sun.COM 
148310187SKrishna.Elango@Sun.COM 	max_pay_load_supported.dip = rc_dip;
148410187SKrishna.Elango@Sun.COM 	max_pay_load_supported.highest_common_mps = *max_supported;
148510187SKrishna.Elango@Sun.COM 
148610187SKrishna.Elango@Sun.COM 	ndi_devi_enter(ddi_get_parent(dip), &circular_count);
148710187SKrishna.Elango@Sun.COM 	ddi_walk_devs(dip, pcie_get_max_supported,
148810187SKrishna.Elango@Sun.COM 	    (void *)&max_pay_load_supported);
148910187SKrishna.Elango@Sun.COM 	ndi_devi_exit(ddi_get_parent(dip), circular_count);
1490*10923SEvan.Yan@Sun.COM 
149110187SKrishna.Elango@Sun.COM 	*max_supported = max_pay_load_supported.highest_common_mps;
149210187SKrishna.Elango@Sun.COM }
149310187SKrishna.Elango@Sun.COM 
149410187SKrishna.Elango@Sun.COM /*
149510187SKrishna.Elango@Sun.COM  * Called as part of the Maximum Payload Size scan.
149610187SKrishna.Elango@Sun.COM  */
149710187SKrishna.Elango@Sun.COM static int
149810187SKrishna.Elango@Sun.COM pcie_get_max_supported(dev_info_t *dip, void *arg)
149910187SKrishna.Elango@Sun.COM {
150010187SKrishna.Elango@Sun.COM 	uint32_t max_supported;
150110187SKrishna.Elango@Sun.COM 	uint16_t cap_ptr;
150210187SKrishna.Elango@Sun.COM 	pcie_max_supported_t *current = (pcie_max_supported_t *)arg;
150310187SKrishna.Elango@Sun.COM 	pci_regspec_t *reg;
150410187SKrishna.Elango@Sun.COM 	int rlen;
150510187SKrishna.Elango@Sun.COM 	caddr_t virt;
150610187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t config_handle;
150710187SKrishna.Elango@Sun.COM 
150810187SKrishna.Elango@Sun.COM 	if (ddi_get_child(current->dip) == NULL) {
150910187SKrishna.Elango@Sun.COM 		goto fail1;
151010187SKrishna.Elango@Sun.COM 	}
151110187SKrishna.Elango@Sun.COM 
151210187SKrishna.Elango@Sun.COM 	if (pcie_dev(dip) == DDI_FAILURE) {
151310187SKrishna.Elango@Sun.COM 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  "
151410187SKrishna.Elango@Sun.COM 		    "Not a PCIe dev\n", ddi_driver_name(dip));
151510187SKrishna.Elango@Sun.COM 		goto fail1;
151610187SKrishna.Elango@Sun.COM 	}
151710187SKrishna.Elango@Sun.COM 
151810187SKrishna.Elango@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
151910187SKrishna.Elango@Sun.COM 	    (caddr_t)&reg, &rlen) != DDI_PROP_SUCCESS) {
152010187SKrishna.Elango@Sun.COM 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  "
152110187SKrishna.Elango@Sun.COM 		    "Can not read reg\n", ddi_driver_name(dip));
152210187SKrishna.Elango@Sun.COM 		goto fail1;
152310187SKrishna.Elango@Sun.COM 	}
152410187SKrishna.Elango@Sun.COM 
152510187SKrishna.Elango@Sun.COM 	if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt,
152610187SKrishna.Elango@Sun.COM 	    &config_handle) != DDI_SUCCESS) {
152710187SKrishna.Elango@Sun.COM 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  pcie_map_phys "
152810187SKrishna.Elango@Sun.COM 		    "failed\n", ddi_driver_name(dip));
152910187SKrishna.Elango@Sun.COM 		goto fail2;
153010187SKrishna.Elango@Sun.COM 	}
153110187SKrishna.Elango@Sun.COM 
153210187SKrishna.Elango@Sun.COM 	if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
153310187SKrishna.Elango@Sun.COM 	    DDI_FAILURE) {
153410187SKrishna.Elango@Sun.COM 		goto fail3;
153510187SKrishna.Elango@Sun.COM 	}
153610187SKrishna.Elango@Sun.COM 
153710187SKrishna.Elango@Sun.COM 	max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
153810187SKrishna.Elango@Sun.COM 	    PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK;
153910187SKrishna.Elango@Sun.COM 
154010187SKrishna.Elango@Sun.COM 	PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip),
154110187SKrishna.Elango@Sun.COM 	    max_supported);
154210187SKrishna.Elango@Sun.COM 
154310187SKrishna.Elango@Sun.COM 	if (max_supported < current->highest_common_mps)
154410187SKrishna.Elango@Sun.COM 		current->highest_common_mps = max_supported;
154510187SKrishna.Elango@Sun.COM 
154610187SKrishna.Elango@Sun.COM fail3:
154710187SKrishna.Elango@Sun.COM 	pcie_unmap_phys(&config_handle, reg);
154810187SKrishna.Elango@Sun.COM fail2:
154910187SKrishna.Elango@Sun.COM 	kmem_free(reg, rlen);
155010187SKrishna.Elango@Sun.COM fail1:
155110187SKrishna.Elango@Sun.COM 	return (DDI_WALK_CONTINUE);
155210187SKrishna.Elango@Sun.COM }
155310187SKrishna.Elango@Sun.COM 
155410187SKrishna.Elango@Sun.COM /*
155510187SKrishna.Elango@Sun.COM  * Determines if there are any root ports attached to a root complex.
155610187SKrishna.Elango@Sun.COM  *
155710187SKrishna.Elango@Sun.COM  * dip - dip of root complex
155810187SKrishna.Elango@Sun.COM  *
155910187SKrishna.Elango@Sun.COM  * Returns - DDI_SUCCESS if there is at least one root port otherwise
1560*10923SEvan.Yan@Sun.COM  *	     DDI_FAILURE.
156110187SKrishna.Elango@Sun.COM  */
156210187SKrishna.Elango@Sun.COM int
156310187SKrishna.Elango@Sun.COM pcie_root_port(dev_info_t *dip)
156410187SKrishna.Elango@Sun.COM {
156510187SKrishna.Elango@Sun.COM 	int port_type;
156610187SKrishna.Elango@Sun.COM 	uint16_t cap_ptr;
156710187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t config_handle;
156810187SKrishna.Elango@Sun.COM 	dev_info_t *cdip = ddi_get_child(dip);
156910187SKrishna.Elango@Sun.COM 
157010187SKrishna.Elango@Sun.COM 	/*
157110187SKrishna.Elango@Sun.COM 	 * Determine if any of the children of the passed in dip
157210187SKrishna.Elango@Sun.COM 	 * are root ports.
157310187SKrishna.Elango@Sun.COM 	 */
157410187SKrishna.Elango@Sun.COM 	for (; cdip; cdip = ddi_get_next_sibling(cdip)) {
157510187SKrishna.Elango@Sun.COM 
157610187SKrishna.Elango@Sun.COM 		if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS)
157710187SKrishna.Elango@Sun.COM 			continue;
157810187SKrishna.Elango@Sun.COM 
157910187SKrishna.Elango@Sun.COM 		if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E,
158010187SKrishna.Elango@Sun.COM 		    &cap_ptr)) == DDI_FAILURE) {
158110187SKrishna.Elango@Sun.COM 			pci_config_teardown(&config_handle);
158210187SKrishna.Elango@Sun.COM 			continue;
158310187SKrishna.Elango@Sun.COM 		}
158410187SKrishna.Elango@Sun.COM 
158510187SKrishna.Elango@Sun.COM 		port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
158610187SKrishna.Elango@Sun.COM 		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
158710187SKrishna.Elango@Sun.COM 
158810187SKrishna.Elango@Sun.COM 		pci_config_teardown(&config_handle);
158910187SKrishna.Elango@Sun.COM 
159010187SKrishna.Elango@Sun.COM 		if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT)
159110187SKrishna.Elango@Sun.COM 			return (DDI_SUCCESS);
159210187SKrishna.Elango@Sun.COM 	}
159310187SKrishna.Elango@Sun.COM 
159410187SKrishna.Elango@Sun.COM 	/* No root ports were found */
159510187SKrishna.Elango@Sun.COM 
159610187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
159710187SKrishna.Elango@Sun.COM }
159810187SKrishna.Elango@Sun.COM 
159910187SKrishna.Elango@Sun.COM /*
160010187SKrishna.Elango@Sun.COM  * Function that determines if a device a PCIe device.
160110187SKrishna.Elango@Sun.COM  *
160210187SKrishna.Elango@Sun.COM  * dip - dip of device.
160310187SKrishna.Elango@Sun.COM  *
160410187SKrishna.Elango@Sun.COM  * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE.
160510187SKrishna.Elango@Sun.COM  */
160610187SKrishna.Elango@Sun.COM int
160710187SKrishna.Elango@Sun.COM pcie_dev(dev_info_t *dip)
160810187SKrishna.Elango@Sun.COM {
160910187SKrishna.Elango@Sun.COM 	/* get parent device's device_type property */
161010187SKrishna.Elango@Sun.COM 	char *device_type;
161110187SKrishna.Elango@Sun.COM 	int rc = DDI_FAILURE;
161210187SKrishna.Elango@Sun.COM 	dev_info_t *pdip = ddi_get_parent(dip);
161310187SKrishna.Elango@Sun.COM 
161410187SKrishna.Elango@Sun.COM 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
161510187SKrishna.Elango@Sun.COM 	    DDI_PROP_DONTPASS, "device_type", &device_type)
161610187SKrishna.Elango@Sun.COM 	    != DDI_PROP_SUCCESS) {
161710187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
161810187SKrishna.Elango@Sun.COM 	}
161910187SKrishna.Elango@Sun.COM 
162010187SKrishna.Elango@Sun.COM 	if (strcmp(device_type, "pciex") == 0)
162110187SKrishna.Elango@Sun.COM 		rc = DDI_SUCCESS;
162210187SKrishna.Elango@Sun.COM 	else
162310187SKrishna.Elango@Sun.COM 		rc = DDI_FAILURE;
162410187SKrishna.Elango@Sun.COM 
162510187SKrishna.Elango@Sun.COM 	ddi_prop_free(device_type);
162610187SKrishna.Elango@Sun.COM 	return (rc);
162710187SKrishna.Elango@Sun.COM }
162810187SKrishna.Elango@Sun.COM 
162910187SKrishna.Elango@Sun.COM /*
163010187SKrishna.Elango@Sun.COM  * Function to map in a device's memory space.
163110187SKrishna.Elango@Sun.COM  */
163210187SKrishna.Elango@Sun.COM static int
163310187SKrishna.Elango@Sun.COM pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
163410187SKrishna.Elango@Sun.COM     caddr_t *addrp, ddi_acc_handle_t *handlep)
163510187SKrishna.Elango@Sun.COM {
163610187SKrishna.Elango@Sun.COM 	ddi_map_req_t mr;
163710187SKrishna.Elango@Sun.COM 	ddi_acc_hdl_t *hp;
163810187SKrishna.Elango@Sun.COM 	int result;
163910187SKrishna.Elango@Sun.COM 	ddi_device_acc_attr_t attr;
164010187SKrishna.Elango@Sun.COM 
164110187SKrishna.Elango@Sun.COM 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
164210187SKrishna.Elango@Sun.COM 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
164310187SKrishna.Elango@Sun.COM 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
164410187SKrishna.Elango@Sun.COM 	attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
164510187SKrishna.Elango@Sun.COM 
164610187SKrishna.Elango@Sun.COM 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
164710187SKrishna.Elango@Sun.COM 	hp = impl_acc_hdl_get(*handlep);
164810187SKrishna.Elango@Sun.COM 	hp->ah_vers = VERS_ACCHDL;
164910187SKrishna.Elango@Sun.COM 	hp->ah_dip = dip;
165010187SKrishna.Elango@Sun.COM 	hp->ah_rnumber = 0;
165110187SKrishna.Elango@Sun.COM 	hp->ah_offset = 0;
165210187SKrishna.Elango@Sun.COM 	hp->ah_len = 0;
165310187SKrishna.Elango@Sun.COM 	hp->ah_acc = attr;
165410187SKrishna.Elango@Sun.COM 
165510187SKrishna.Elango@Sun.COM 	mr.map_op = DDI_MO_MAP_LOCKED;
165610187SKrishna.Elango@Sun.COM 	mr.map_type = DDI_MT_REGSPEC;
165710187SKrishna.Elango@Sun.COM 	mr.map_obj.rp = (struct regspec *)phys_spec;
165810187SKrishna.Elango@Sun.COM 	mr.map_prot = PROT_READ | PROT_WRITE;
165910187SKrishna.Elango@Sun.COM 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
166010187SKrishna.Elango@Sun.COM 	mr.map_handlep = hp;
166110187SKrishna.Elango@Sun.COM 	mr.map_vers = DDI_MAP_VERSION;
166210187SKrishna.Elango@Sun.COM 
166310187SKrishna.Elango@Sun.COM 	result = ddi_map(dip, &mr, 0, 0, addrp);
166410187SKrishna.Elango@Sun.COM 
166510187SKrishna.Elango@Sun.COM 	if (result != DDI_SUCCESS) {
166610187SKrishna.Elango@Sun.COM 		impl_acc_hdl_free(*handlep);
166710187SKrishna.Elango@Sun.COM 		*handlep = (ddi_acc_handle_t)NULL;
166810187SKrishna.Elango@Sun.COM 	} else {
166910187SKrishna.Elango@Sun.COM 		hp->ah_addr = *addrp;
167010187SKrishna.Elango@Sun.COM 	}
167110187SKrishna.Elango@Sun.COM 
167210187SKrishna.Elango@Sun.COM 	return (result);
167310187SKrishna.Elango@Sun.COM }
167410187SKrishna.Elango@Sun.COM 
167510187SKrishna.Elango@Sun.COM /*
167610187SKrishna.Elango@Sun.COM  * Map out memory that was mapped in with pcie_map_phys();
167710187SKrishna.Elango@Sun.COM  */
167810187SKrishna.Elango@Sun.COM static void
167910187SKrishna.Elango@Sun.COM pcie_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph)
168010187SKrishna.Elango@Sun.COM {
168110187SKrishna.Elango@Sun.COM 	ddi_map_req_t mr;
168210187SKrishna.Elango@Sun.COM 	ddi_acc_hdl_t *hp;
168310187SKrishna.Elango@Sun.COM 
168410187SKrishna.Elango@Sun.COM 	hp = impl_acc_hdl_get(*handlep);
168510187SKrishna.Elango@Sun.COM 	ASSERT(hp);
168610187SKrishna.Elango@Sun.COM 
168710187SKrishna.Elango@Sun.COM 	mr.map_op = DDI_MO_UNMAP;
168810187SKrishna.Elango@Sun.COM 	mr.map_type = DDI_MT_REGSPEC;
168910187SKrishna.Elango@Sun.COM 	mr.map_obj.rp = (struct regspec *)ph;
169010187SKrishna.Elango@Sun.COM 	mr.map_prot = PROT_READ | PROT_WRITE;
169110187SKrishna.Elango@Sun.COM 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
169210187SKrishna.Elango@Sun.COM 	mr.map_handlep = hp;
169310187SKrishna.Elango@Sun.COM 	mr.map_vers = DDI_MAP_VERSION;
169410187SKrishna.Elango@Sun.COM 
169510187SKrishna.Elango@Sun.COM 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
169610187SKrishna.Elango@Sun.COM 	    hp->ah_len, &hp->ah_addr);
169710187SKrishna.Elango@Sun.COM 
169810187SKrishna.Elango@Sun.COM 	impl_acc_hdl_free(*handlep);
169910187SKrishna.Elango@Sun.COM 	*handlep = (ddi_acc_handle_t)NULL;
170010187SKrishna.Elango@Sun.COM }
170110187SKrishna.Elango@Sun.COM 
170210187SKrishna.Elango@Sun.COM void
170310187SKrishna.Elango@Sun.COM pcie_set_rber_fatal(dev_info_t *dip, boolean_t val)
170410187SKrishna.Elango@Sun.COM {
170510187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
170610187SKrishna.Elango@Sun.COM 	bus_p->bus_pfd->pe_rber_fatal = val;
170710187SKrishna.Elango@Sun.COM }
170810187SKrishna.Elango@Sun.COM 
170910187SKrishna.Elango@Sun.COM /*
171010187SKrishna.Elango@Sun.COM  * Return parent Root Port's pe_rber_fatal value.
171110187SKrishna.Elango@Sun.COM  */
171210187SKrishna.Elango@Sun.COM boolean_t
171310187SKrishna.Elango@Sun.COM pcie_get_rber_fatal(dev_info_t *dip)
171410187SKrishna.Elango@Sun.COM {
171510187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
171610187SKrishna.Elango@Sun.COM 	pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip);
171710187SKrishna.Elango@Sun.COM 	return (rp_bus_p->bus_pfd->pe_rber_fatal);
171810187SKrishna.Elango@Sun.COM }
171910187SKrishna.Elango@Sun.COM 
1720*10923SEvan.Yan@Sun.COM int
1721*10923SEvan.Yan@Sun.COM pcie_ari_supported(dev_info_t *dip)
1722*10923SEvan.Yan@Sun.COM {
1723*10923SEvan.Yan@Sun.COM 	uint32_t devcap2;
1724*10923SEvan.Yan@Sun.COM 	uint16_t pciecap;
1725*10923SEvan.Yan@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
1726*10923SEvan.Yan@Sun.COM 	uint8_t dev_type;
1727*10923SEvan.Yan@Sun.COM 
1728*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_supported: dip=%p\n", dip);
1729*10923SEvan.Yan@Sun.COM 
1730*10923SEvan.Yan@Sun.COM 	if (bus_p == NULL)
1731*10923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
1732*10923SEvan.Yan@Sun.COM 
1733*10923SEvan.Yan@Sun.COM 	dev_type = bus_p->bus_dev_type;
1734*10923SEvan.Yan@Sun.COM 
1735*10923SEvan.Yan@Sun.COM 	if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) &&
1736*10923SEvan.Yan@Sun.COM 	    (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT))
1737*10923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
1738*10923SEvan.Yan@Sun.COM 
1739*10923SEvan.Yan@Sun.COM 	if (pcie_disable_ari) {
1740*10923SEvan.Yan@Sun.COM 		PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip);
1741*10923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
1742*10923SEvan.Yan@Sun.COM 	}
1743*10923SEvan.Yan@Sun.COM 
1744*10923SEvan.Yan@Sun.COM 	pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
1745*10923SEvan.Yan@Sun.COM 
1746*10923SEvan.Yan@Sun.COM 	if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) {
1747*10923SEvan.Yan@Sun.COM 		PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip);
1748*10923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
1749*10923SEvan.Yan@Sun.COM 	}
1750*10923SEvan.Yan@Sun.COM 
1751*10923SEvan.Yan@Sun.COM 	devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2);
1752*10923SEvan.Yan@Sun.COM 
1753*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n",
1754*10923SEvan.Yan@Sun.COM 	    dip, devcap2);
1755*10923SEvan.Yan@Sun.COM 
1756*10923SEvan.Yan@Sun.COM 	if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) {
1757*10923SEvan.Yan@Sun.COM 		PCIE_DBG("pcie_ari_supported: "
1758*10923SEvan.Yan@Sun.COM 		    "dip=%p: ARI Forwarding is supported\n", dip);
1759*10923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_SUPPORTED);
1760*10923SEvan.Yan@Sun.COM 	}
1761*10923SEvan.Yan@Sun.COM 	return (PCIE_ARI_FORW_NOT_SUPPORTED);
1762*10923SEvan.Yan@Sun.COM }
1763*10923SEvan.Yan@Sun.COM 
1764*10923SEvan.Yan@Sun.COM int
1765*10923SEvan.Yan@Sun.COM pcie_ari_enable(dev_info_t *dip)
1766*10923SEvan.Yan@Sun.COM {
1767*10923SEvan.Yan@Sun.COM 	uint16_t devctl2;
1768*10923SEvan.Yan@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
1769*10923SEvan.Yan@Sun.COM 
1770*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_enable: dip=%p\n", dip);
1771*10923SEvan.Yan@Sun.COM 
1772*10923SEvan.Yan@Sun.COM 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
1773*10923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
1774*10923SEvan.Yan@Sun.COM 
1775*10923SEvan.Yan@Sun.COM 	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
1776*10923SEvan.Yan@Sun.COM 	devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN;
1777*10923SEvan.Yan@Sun.COM 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
1778*10923SEvan.Yan@Sun.COM 
1779*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n",
1780*10923SEvan.Yan@Sun.COM 	    dip, devctl2);
1781*10923SEvan.Yan@Sun.COM 
1782*10923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
1783*10923SEvan.Yan@Sun.COM }
1784*10923SEvan.Yan@Sun.COM 
1785*10923SEvan.Yan@Sun.COM int
1786*10923SEvan.Yan@Sun.COM pcie_ari_disable(dev_info_t *dip)
1787*10923SEvan.Yan@Sun.COM {
1788*10923SEvan.Yan@Sun.COM 	uint16_t devctl2;
1789*10923SEvan.Yan@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
1790*10923SEvan.Yan@Sun.COM 
1791*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_disable: dip=%p\n", dip);
1792*10923SEvan.Yan@Sun.COM 
1793*10923SEvan.Yan@Sun.COM 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
1794*10923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
1795*10923SEvan.Yan@Sun.COM 
1796*10923SEvan.Yan@Sun.COM 	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
1797*10923SEvan.Yan@Sun.COM 	devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN;
1798*10923SEvan.Yan@Sun.COM 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
1799*10923SEvan.Yan@Sun.COM 
1800*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n",
1801*10923SEvan.Yan@Sun.COM 	    dip, devctl2);
1802*10923SEvan.Yan@Sun.COM 
1803*10923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
1804*10923SEvan.Yan@Sun.COM }
1805*10923SEvan.Yan@Sun.COM 
1806*10923SEvan.Yan@Sun.COM int
1807*10923SEvan.Yan@Sun.COM pcie_ari_is_enabled(dev_info_t *dip)
1808*10923SEvan.Yan@Sun.COM {
1809*10923SEvan.Yan@Sun.COM 	uint16_t devctl2;
1810*10923SEvan.Yan@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
1811*10923SEvan.Yan@Sun.COM 
1812*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip);
1813*10923SEvan.Yan@Sun.COM 
1814*10923SEvan.Yan@Sun.COM 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
1815*10923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_DISABLED);
1816*10923SEvan.Yan@Sun.COM 
1817*10923SEvan.Yan@Sun.COM 	devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2);
1818*10923SEvan.Yan@Sun.COM 
1819*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n",
1820*10923SEvan.Yan@Sun.COM 	    dip, devctl2);
1821*10923SEvan.Yan@Sun.COM 
1822*10923SEvan.Yan@Sun.COM 	if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) {
1823*10923SEvan.Yan@Sun.COM 		PCIE_DBG("pcie_ari_is_enabled: "
1824*10923SEvan.Yan@Sun.COM 		    "dip=%p: ARI Forwarding is enabled\n", dip);
1825*10923SEvan.Yan@Sun.COM 		return (PCIE_ARI_FORW_ENABLED);
1826*10923SEvan.Yan@Sun.COM 	}
1827*10923SEvan.Yan@Sun.COM 
1828*10923SEvan.Yan@Sun.COM 	return (PCIE_ARI_FORW_DISABLED);
1829*10923SEvan.Yan@Sun.COM }
1830*10923SEvan.Yan@Sun.COM 
1831*10923SEvan.Yan@Sun.COM int
1832*10923SEvan.Yan@Sun.COM pcie_ari_device(dev_info_t *dip)
1833*10923SEvan.Yan@Sun.COM {
1834*10923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle;
1835*10923SEvan.Yan@Sun.COM 	uint16_t cap_ptr;
1836*10923SEvan.Yan@Sun.COM 
1837*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_device: dip=%p\n", dip);
1838*10923SEvan.Yan@Sun.COM 
1839*10923SEvan.Yan@Sun.COM 	/*
1840*10923SEvan.Yan@Sun.COM 	 * XXX - This function may be called before the bus_p structure
1841*10923SEvan.Yan@Sun.COM 	 * has been populated.  This code can be changed to remove
1842*10923SEvan.Yan@Sun.COM 	 * pci_config_setup()/pci_config_teardown() when the RFE
1843*10923SEvan.Yan@Sun.COM 	 * to populate the bus_p structures early in boot is putback.
1844*10923SEvan.Yan@Sun.COM 	 */
1845*10923SEvan.Yan@Sun.COM 
1846*10923SEvan.Yan@Sun.COM 	/* First make sure it is a PCIe device */
1847*10923SEvan.Yan@Sun.COM 
1848*10923SEvan.Yan@Sun.COM 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
1849*10923SEvan.Yan@Sun.COM 		return (PCIE_NOT_ARI_DEVICE);
1850*10923SEvan.Yan@Sun.COM 
1851*10923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
1852*10923SEvan.Yan@Sun.COM 	    != DDI_SUCCESS) {
1853*10923SEvan.Yan@Sun.COM 		pci_config_teardown(&handle);
1854*10923SEvan.Yan@Sun.COM 		return (PCIE_NOT_ARI_DEVICE);
1855*10923SEvan.Yan@Sun.COM 	}
1856*10923SEvan.Yan@Sun.COM 
1857*10923SEvan.Yan@Sun.COM 	/* Locate the ARI Capability */
1858*10923SEvan.Yan@Sun.COM 
1859*10923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI),
1860*10923SEvan.Yan@Sun.COM 	    &cap_ptr)) == DDI_FAILURE) {
1861*10923SEvan.Yan@Sun.COM 		pci_config_teardown(&handle);
1862*10923SEvan.Yan@Sun.COM 		return (PCIE_NOT_ARI_DEVICE);
1863*10923SEvan.Yan@Sun.COM 	}
1864*10923SEvan.Yan@Sun.COM 
1865*10923SEvan.Yan@Sun.COM 	/* ARI Capability was found so it must be a ARI device */
1866*10923SEvan.Yan@Sun.COM 	PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip);
1867*10923SEvan.Yan@Sun.COM 
1868*10923SEvan.Yan@Sun.COM 	pci_config_teardown(&handle);
1869*10923SEvan.Yan@Sun.COM 	return (PCIE_ARI_DEVICE);
1870*10923SEvan.Yan@Sun.COM }
1871*10923SEvan.Yan@Sun.COM 
1872*10923SEvan.Yan@Sun.COM int
1873*10923SEvan.Yan@Sun.COM pcie_ari_get_next_function(dev_info_t *dip, int *func)
1874*10923SEvan.Yan@Sun.COM {
1875*10923SEvan.Yan@Sun.COM 	uint32_t val;
1876*10923SEvan.Yan@Sun.COM 	uint16_t cap_ptr, next_function;
1877*10923SEvan.Yan@Sun.COM 	ddi_acc_handle_t handle;
1878*10923SEvan.Yan@Sun.COM 
1879*10923SEvan.Yan@Sun.COM 	/*
1880*10923SEvan.Yan@Sun.COM 	 * XXX - This function may be called before the bus_p structure
1881*10923SEvan.Yan@Sun.COM 	 * has been populated.  This code can be changed to remove
1882*10923SEvan.Yan@Sun.COM 	 * pci_config_setup()/pci_config_teardown() when the RFE
1883*10923SEvan.Yan@Sun.COM 	 * to populate the bus_p structures early in boot is putback.
1884*10923SEvan.Yan@Sun.COM 	 */
1885*10923SEvan.Yan@Sun.COM 
1886*10923SEvan.Yan@Sun.COM 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
1887*10923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
1888*10923SEvan.Yan@Sun.COM 
1889*10923SEvan.Yan@Sun.COM 	if ((PCI_CAP_LOCATE(handle,
1890*10923SEvan.Yan@Sun.COM 	    PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) {
1891*10923SEvan.Yan@Sun.COM 		pci_config_teardown(&handle);
1892*10923SEvan.Yan@Sun.COM 		return (DDI_FAILURE);
1893*10923SEvan.Yan@Sun.COM 	}
1894*10923SEvan.Yan@Sun.COM 
1895*10923SEvan.Yan@Sun.COM 	val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP);
1896*10923SEvan.Yan@Sun.COM 
1897*10923SEvan.Yan@Sun.COM 	next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) &
1898*10923SEvan.Yan@Sun.COM 	    PCIE_ARI_CAP_NEXT_FUNC_MASK;
1899*10923SEvan.Yan@Sun.COM 
1900*10923SEvan.Yan@Sun.COM 	pci_config_teardown(&handle);
1901*10923SEvan.Yan@Sun.COM 
1902*10923SEvan.Yan@Sun.COM 	*func = next_function;
1903*10923SEvan.Yan@Sun.COM 
1904*10923SEvan.Yan@Sun.COM 	return (DDI_SUCCESS);
1905*10923SEvan.Yan@Sun.COM }
1906*10923SEvan.Yan@Sun.COM 
1907*10923SEvan.Yan@Sun.COM dev_info_t *
1908*10923SEvan.Yan@Sun.COM pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function)
1909*10923SEvan.Yan@Sun.COM {
1910*10923SEvan.Yan@Sun.COM 	pcie_req_id_t child_bdf;
1911*10923SEvan.Yan@Sun.COM 	dev_info_t *cdip;
1912*10923SEvan.Yan@Sun.COM 
1913*10923SEvan.Yan@Sun.COM 	for (cdip = ddi_get_child(dip); cdip;
1914*10923SEvan.Yan@Sun.COM 	    cdip = ddi_get_next_sibling(cdip)) {
1915*10923SEvan.Yan@Sun.COM 
1916*10923SEvan.Yan@Sun.COM 		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
1917*10923SEvan.Yan@Sun.COM 			return (NULL);
1918*10923SEvan.Yan@Sun.COM 
1919*10923SEvan.Yan@Sun.COM 		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function)
1920*10923SEvan.Yan@Sun.COM 			return (cdip);
1921*10923SEvan.Yan@Sun.COM 	}
1922*10923SEvan.Yan@Sun.COM 	return (NULL);
1923*10923SEvan.Yan@Sun.COM }
1924*10923SEvan.Yan@Sun.COM 
192510187SKrishna.Elango@Sun.COM #ifdef	DEBUG
192610187SKrishna.Elango@Sun.COM 
192710187SKrishna.Elango@Sun.COM static void
192810187SKrishna.Elango@Sun.COM pcie_print_bus(pcie_bus_t *bus_p)
192910187SKrishna.Elango@Sun.COM {
193010187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip);
193110187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags);
193210187SKrishna.Elango@Sun.COM 
193310187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf);
193410187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id);
193510187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id);
193610187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type);
193710187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type);
193810187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus);
193910187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off);
194010187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off);
194110187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off);
194210187SKrishna.Elango@Sun.COM 	pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver);
194310187SKrishna.Elango@Sun.COM }
194410187SKrishna.Elango@Sun.COM 
194510187SKrishna.Elango@Sun.COM /*
194610187SKrishna.Elango@Sun.COM  * For debugging purposes set pcie_dbg_print != 0 to see printf messages
194710187SKrishna.Elango@Sun.COM  * during interrupt.
194810187SKrishna.Elango@Sun.COM  *
194910187SKrishna.Elango@Sun.COM  * When a proper solution is in place this code will disappear.
195010187SKrishna.Elango@Sun.COM  * Potential solutions are:
195110187SKrishna.Elango@Sun.COM  * o circular buffers
195210187SKrishna.Elango@Sun.COM  * o taskq to print at lower pil
195310187SKrishna.Elango@Sun.COM  */
195410187SKrishna.Elango@Sun.COM int pcie_dbg_print = 0;
195510187SKrishna.Elango@Sun.COM void
195610187SKrishna.Elango@Sun.COM pcie_dbg(char *fmt, ...)
195710187SKrishna.Elango@Sun.COM {
195810187SKrishna.Elango@Sun.COM 	va_list ap;
195910187SKrishna.Elango@Sun.COM 
196010187SKrishna.Elango@Sun.COM 	if (!pcie_debug_flags) {
196110187SKrishna.Elango@Sun.COM 		return;
196210187SKrishna.Elango@Sun.COM 	}
196310187SKrishna.Elango@Sun.COM 	va_start(ap, fmt);
196410187SKrishna.Elango@Sun.COM 	if (servicing_interrupt()) {
196510187SKrishna.Elango@Sun.COM 		if (pcie_dbg_print) {
196610187SKrishna.Elango@Sun.COM 			prom_vprintf(fmt, ap);
196710187SKrishna.Elango@Sun.COM 		}
196810187SKrishna.Elango@Sun.COM 	} else {
196910187SKrishna.Elango@Sun.COM 		prom_vprintf(fmt, ap);
197010187SKrishna.Elango@Sun.COM 	}
197110187SKrishna.Elango@Sun.COM 	va_end(ap);
197210187SKrishna.Elango@Sun.COM }
197310187SKrishna.Elango@Sun.COM #endif	/* DEBUG */
197410187SKrishna.Elango@Sun.COM 
197510187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
197610187SKrishna.Elango@Sun.COM static void
197710187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range,
197810187SKrishna.Elango@Sun.COM     boolean_t *empty_mem_range)
197910187SKrishna.Elango@Sun.COM {
198010187SKrishna.Elango@Sun.COM 	uint8_t	class, subclass;
198110187SKrishna.Elango@Sun.COM 	uint_t	val;
198210187SKrishna.Elango@Sun.COM 
198310187SKrishna.Elango@Sun.COM 	class = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS);
198410187SKrishna.Elango@Sun.COM 	subclass = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS);
198510187SKrishna.Elango@Sun.COM 
198610187SKrishna.Elango@Sun.COM 	if ((class == PCI_CLASS_BRIDGE) && (subclass == PCI_BRIDGE_PCI)) {
198710187SKrishna.Elango@Sun.COM 		val = (((uint_t)pci_config_get8(cfg_hdl, PCI_BCNF_IO_BASE_LOW) &
198810187SKrishna.Elango@Sun.COM 		    PCI_BCNF_IO_MASK) << 8);
198910187SKrishna.Elango@Sun.COM 		/*
199010187SKrishna.Elango@Sun.COM 		 * Assuming that a zero based io_range[0] implies an
199110187SKrishna.Elango@Sun.COM 		 * invalid I/O range.  Likewise for mem_range[0].
199210187SKrishna.Elango@Sun.COM 		 */
199310187SKrishna.Elango@Sun.COM 		if (val == 0)
199410187SKrishna.Elango@Sun.COM 			*empty_io_range = B_TRUE;
199510187SKrishna.Elango@Sun.COM 		val = (((uint_t)pci_config_get16(cfg_hdl, PCI_BCNF_MEM_BASE) &
199610187SKrishna.Elango@Sun.COM 		    PCI_BCNF_MEM_MASK) << 16);
199710187SKrishna.Elango@Sun.COM 		if (val == 0)
199810187SKrishna.Elango@Sun.COM 			*empty_mem_range = B_TRUE;
199910187SKrishna.Elango@Sun.COM 	}
200010187SKrishna.Elango@Sun.COM }
200110187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
2002