xref: /titanic_51/usr/src/uts/common/io/pciex/pcie.c (revision c92295a9ebe31a65582ec97d4d772e0efd2ff240)
1d4bc0535SKrishna Elango /*
2d4bc0535SKrishna Elango  * CDDL HEADER START
3d4bc0535SKrishna Elango  *
4d4bc0535SKrishna Elango  * The contents of this file are subject to the terms of the
5d4bc0535SKrishna Elango  * Common Development and Distribution License (the "License").
6d4bc0535SKrishna Elango  * You may not use this file except in compliance with the License.
7d4bc0535SKrishna Elango  *
8d4bc0535SKrishna Elango  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d4bc0535SKrishna Elango  * or http://www.opensolaris.org/os/licensing.
10d4bc0535SKrishna Elango  * See the License for the specific language governing permissions
11d4bc0535SKrishna Elango  * and limitations under the License.
12d4bc0535SKrishna Elango  *
13d4bc0535SKrishna Elango  * When distributing Covered Code, include this CDDL HEADER in each
14d4bc0535SKrishna Elango  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d4bc0535SKrishna Elango  * If applicable, add the following below this CDDL HEADER, with the
16d4bc0535SKrishna Elango  * fields enclosed by brackets "[]" replaced with your own identifying
17d4bc0535SKrishna Elango  * information: Portions Copyright [yyyy] [name of copyright owner]
18d4bc0535SKrishna Elango  *
19d4bc0535SKrishna Elango  * CDDL HEADER END
20d4bc0535SKrishna Elango  */
219187c210SAlan Adamson, SD OSSD 
22d4bc0535SKrishna Elango /*
2383e6495bSDaniel Ice  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24d4bc0535SKrishna Elango  */
25d4bc0535SKrishna Elango 
26d4bc0535SKrishna Elango #include <sys/sysmacros.h>
27d4bc0535SKrishna Elango #include <sys/types.h>
28d4bc0535SKrishna Elango #include <sys/kmem.h>
29d4bc0535SKrishna Elango #include <sys/modctl.h>
30d4bc0535SKrishna Elango #include <sys/ddi.h>
31d4bc0535SKrishna Elango #include <sys/sunddi.h>
32d4bc0535SKrishna Elango #include <sys/sunndi.h>
33d4bc0535SKrishna Elango #include <sys/fm/protocol.h>
34d4bc0535SKrishna Elango #include <sys/fm/util.h>
35d4bc0535SKrishna Elango #include <sys/promif.h>
36d4bc0535SKrishna Elango #include <sys/disp.h>
3726947304SEvan Yan #include <sys/stat.h>
3826947304SEvan Yan #include <sys/file.h>
39d4bc0535SKrishna Elango #include <sys/pci_cap.h>
4026947304SEvan Yan #include <sys/pci_impl.h>
41d4bc0535SKrishna Elango #include <sys/pcie_impl.h>
4226947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h>
4370f83219SEvan Yan #include <sys/hotplug/pci/pciehpc.h>
4470f83219SEvan Yan #include <sys/hotplug/pci/pcishpc.h>
4526947304SEvan Yan #include <sys/hotplug/pci/pcicfg.h>
46c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
47d4bc0535SKrishna Elango 
4826947304SEvan Yan /* Local functions prototypes */
49d4bc0535SKrishna Elango static void pcie_init_pfd(dev_info_t *);
50d4bc0535SKrishna Elango static void pcie_fini_pfd(dev_info_t *);
51d4bc0535SKrishna Elango 
52d4bc0535SKrishna Elango #if defined(__i386) || defined(__amd64)
53d4bc0535SKrishna Elango static void pcie_check_io_mem_range(ddi_acc_handle_t, boolean_t *, boolean_t *);
54d4bc0535SKrishna Elango #endif /* defined(__i386) || defined(__amd64) */
55d4bc0535SKrishna Elango 
56d4bc0535SKrishna Elango #ifdef DEBUG
57d4bc0535SKrishna Elango uint_t pcie_debug_flags = 0;
58d4bc0535SKrishna Elango static void pcie_print_bus(pcie_bus_t *bus_p);
5926947304SEvan Yan void pcie_dbg(char *fmt, ...);
60d4bc0535SKrishna Elango #endif /* DEBUG */
61d4bc0535SKrishna Elango 
62d4bc0535SKrishna Elango /* Variable to control default PCI-Express config settings */
63d4bc0535SKrishna Elango ushort_t pcie_command_default =
64d4bc0535SKrishna Elango     PCI_COMM_SERR_ENABLE |
65d4bc0535SKrishna Elango     PCI_COMM_WAIT_CYC_ENAB |
66d4bc0535SKrishna Elango     PCI_COMM_PARITY_DETECT |
67d4bc0535SKrishna Elango     PCI_COMM_ME |
68d4bc0535SKrishna Elango     PCI_COMM_MAE |
69d4bc0535SKrishna Elango     PCI_COMM_IO;
70d4bc0535SKrishna Elango 
71d4bc0535SKrishna Elango /* xxx_fw are bits that are controlled by FW and should not be modified */
72d4bc0535SKrishna Elango ushort_t pcie_command_default_fw =
73d4bc0535SKrishna Elango     PCI_COMM_SPEC_CYC |
74d4bc0535SKrishna Elango     PCI_COMM_MEMWR_INVAL |
75d4bc0535SKrishna Elango     PCI_COMM_PALETTE_SNOOP |
76d4bc0535SKrishna Elango     PCI_COMM_WAIT_CYC_ENAB |
77d4bc0535SKrishna Elango     0xF800; /* Reserved Bits */
78d4bc0535SKrishna Elango 
79d4bc0535SKrishna Elango ushort_t pcie_bdg_command_default_fw =
80d4bc0535SKrishna Elango     PCI_BCNF_BCNTRL_ISA_ENABLE |
81d4bc0535SKrishna Elango     PCI_BCNF_BCNTRL_VGA_ENABLE |
82d4bc0535SKrishna Elango     0xF000; /* Reserved Bits */
83d4bc0535SKrishna Elango 
84d4bc0535SKrishna Elango /* PCI-Express Base error defaults */
85d4bc0535SKrishna Elango ushort_t pcie_base_err_default =
86d4bc0535SKrishna Elango     PCIE_DEVCTL_CE_REPORTING_EN |
87d4bc0535SKrishna Elango     PCIE_DEVCTL_NFE_REPORTING_EN |
88d4bc0535SKrishna Elango     PCIE_DEVCTL_FE_REPORTING_EN |
89d4bc0535SKrishna Elango     PCIE_DEVCTL_UR_REPORTING_EN;
90d4bc0535SKrishna Elango 
91d4bc0535SKrishna Elango /* PCI-Express Device Control Register */
92d4bc0535SKrishna Elango uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN |
93d4bc0535SKrishna Elango     PCIE_DEVCTL_MAX_READ_REQ_512;
94d4bc0535SKrishna Elango 
95d4bc0535SKrishna Elango /* PCI-Express AER Root Control Register */
96d4bc0535SKrishna Elango #define	PCIE_ROOT_SYS_ERR	(PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \
97d4bc0535SKrishna Elango 				PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \
98d4bc0535SKrishna Elango 				PCIE_ROOTCTL_SYS_ERR_ON_FE_EN)
99d4bc0535SKrishna Elango 
100d4bc0535SKrishna Elango ushort_t pcie_root_ctrl_default =
101d4bc0535SKrishna Elango     PCIE_ROOTCTL_SYS_ERR_ON_CE_EN |
102d4bc0535SKrishna Elango     PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
103d4bc0535SKrishna Elango     PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
104d4bc0535SKrishna Elango 
105d4bc0535SKrishna Elango /* PCI-Express Root Error Command Register */
106d4bc0535SKrishna Elango ushort_t pcie_root_error_cmd_default =
107d4bc0535SKrishna Elango     PCIE_AER_RE_CMD_CE_REP_EN |
108d4bc0535SKrishna Elango     PCIE_AER_RE_CMD_NFE_REP_EN |
109d4bc0535SKrishna Elango     PCIE_AER_RE_CMD_FE_REP_EN;
110d4bc0535SKrishna Elango 
111d4bc0535SKrishna Elango /* ECRC settings in the PCIe AER Control Register */
112d4bc0535SKrishna Elango uint32_t pcie_ecrc_value =
113d4bc0535SKrishna Elango     PCIE_AER_CTL_ECRC_GEN_ENA |
114d4bc0535SKrishna Elango     PCIE_AER_CTL_ECRC_CHECK_ENA;
115d4bc0535SKrishna Elango 
116d4bc0535SKrishna Elango /*
117d4bc0535SKrishna Elango  * If a particular platform wants to disable certain errors such as UR/MA,
118d4bc0535SKrishna Elango  * instead of using #defines have the platform's PCIe Root Complex driver set
119d4bc0535SKrishna Elango  * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions.  For
120d4bc0535SKrishna Elango  * x86 the closest thing to a PCIe root complex driver is NPE.	For SPARC the
121d4bc0535SKrishna Elango  * closest PCIe root complex driver is PX.
122d4bc0535SKrishna Elango  *
123d4bc0535SKrishna Elango  * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86
124d4bc0535SKrishna Elango  * systems may want to disable SERR in general.  For root ports, enabling SERR
125d4bc0535SKrishna Elango  * causes NMIs which are not handled and results in a watchdog timeout error.
126d4bc0535SKrishna Elango  */
127d4bc0535SKrishna Elango uint32_t pcie_aer_uce_mask = 0;		/* AER UE Mask */
128d4bc0535SKrishna Elango uint32_t pcie_aer_ce_mask = 0;		/* AER CE Mask */
129d4bc0535SKrishna Elango uint32_t pcie_aer_suce_mask = 0;	/* AER Secondary UE Mask */
130d4bc0535SKrishna Elango uint32_t pcie_serr_disable_flag = 0;	/* Disable SERR */
131d4bc0535SKrishna Elango 
132d4bc0535SKrishna Elango /* Default severities needed for eversholt.  Error handling doesn't care */
133d4bc0535SKrishna Elango uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \
134d4bc0535SKrishna Elango     PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \
135d4bc0535SKrishna Elango     PCIE_AER_UCE_TRAINING;
136d4bc0535SKrishna Elango uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \
137d4bc0535SKrishna Elango     PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \
138d4bc0535SKrishna Elango     PCIE_AER_SUCE_USC_MSG_DATA_ERR;
139d4bc0535SKrishna Elango 
140d4bc0535SKrishna Elango int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5;
14126947304SEvan Yan int pcie_disable_ari = 0;
142d4bc0535SKrishna Elango 
143d4bc0535SKrishna Elango static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip,
144d4bc0535SKrishna Elango 	int *max_supported);
145d4bc0535SKrishna Elango static int pcie_get_max_supported(dev_info_t *dip, void *arg);
146d4bc0535SKrishna Elango static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
147d4bc0535SKrishna Elango     caddr_t *addrp, ddi_acc_handle_t *handlep);
148d4bc0535SKrishna Elango static void pcie_unmap_phys(ddi_acc_handle_t *handlep,	pci_regspec_t *ph);
149d4bc0535SKrishna Elango 
150c0da6274SZhi-Jun Robin Fu dev_info_t *pcie_get_rc_dip(dev_info_t *dip);
151c0da6274SZhi-Jun Robin Fu 
152d4bc0535SKrishna Elango /*
153d4bc0535SKrishna Elango  * modload support
154d4bc0535SKrishna Elango  */
155d4bc0535SKrishna Elango 
156d4bc0535SKrishna Elango static struct modlmisc modlmisc	= {
157d4bc0535SKrishna Elango 	&mod_miscops,	/* Type	of module */
15826947304SEvan Yan 	"PCI Express Framework Module"
159d4bc0535SKrishna Elango };
160d4bc0535SKrishna Elango 
161d4bc0535SKrishna Elango static struct modlinkage modlinkage = {
162d4bc0535SKrishna Elango 	MODREV_1,
163d4bc0535SKrishna Elango 	(void	*)&modlmisc,
164d4bc0535SKrishna Elango 	NULL
165d4bc0535SKrishna Elango };
166d4bc0535SKrishna Elango 
167d4bc0535SKrishna Elango /*
168d4bc0535SKrishna Elango  * Global Variables needed for a non-atomic version of ddi_fm_ereport_post.
169d4bc0535SKrishna Elango  * Currently used to send the pci.fabric ereports whose payload depends on the
170d4bc0535SKrishna Elango  * type of PCI device it is being sent for.
171d4bc0535SKrishna Elango  */
172d4bc0535SKrishna Elango char		*pcie_nv_buf;
173d4bc0535SKrishna Elango nv_alloc_t	*pcie_nvap;
174d4bc0535SKrishna Elango nvlist_t	*pcie_nvl;
175d4bc0535SKrishna Elango 
176d4bc0535SKrishna Elango int
177d4bc0535SKrishna Elango _init(void)
178d4bc0535SKrishna Elango {
179d4bc0535SKrishna Elango 	int rval;
180d4bc0535SKrishna Elango 
181d4bc0535SKrishna Elango 	pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP);
182d4bc0535SKrishna Elango 	pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ);
183d4bc0535SKrishna Elango 	pcie_nvl = fm_nvlist_create(pcie_nvap);
184d4bc0535SKrishna Elango 
185*c92295a9SAn Bui 	if ((rval = mod_install(&modlinkage)) != 0) {
186*c92295a9SAn Bui 		fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
187*c92295a9SAn Bui 		fm_nva_xdestroy(pcie_nvap);
188*c92295a9SAn Bui 		kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
189*c92295a9SAn Bui 	}
190d4bc0535SKrishna Elango 	return (rval);
191d4bc0535SKrishna Elango }
192d4bc0535SKrishna Elango 
193d4bc0535SKrishna Elango int
194d4bc0535SKrishna Elango _fini()
195d4bc0535SKrishna Elango {
196d4bc0535SKrishna Elango 	int		rval;
197d4bc0535SKrishna Elango 
198*c92295a9SAn Bui 	if ((rval = mod_remove(&modlinkage)) == 0) {
199d4bc0535SKrishna Elango 		fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
200d4bc0535SKrishna Elango 		fm_nva_xdestroy(pcie_nvap);
201d4bc0535SKrishna Elango 		kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
202*c92295a9SAn Bui 	}
203d4bc0535SKrishna Elango 	return (rval);
204d4bc0535SKrishna Elango }
205d4bc0535SKrishna Elango 
206d4bc0535SKrishna Elango int
207d4bc0535SKrishna Elango _info(struct modinfo *modinfop)
208d4bc0535SKrishna Elango {
209d4bc0535SKrishna Elango 	return (mod_info(&modlinkage, modinfop));
210d4bc0535SKrishna Elango }
211d4bc0535SKrishna Elango 
21226947304SEvan Yan /* ARGSUSED */
21326947304SEvan Yan int
21426947304SEvan Yan pcie_init(dev_info_t *dip, caddr_t arg)
21526947304SEvan Yan {
21626947304SEvan Yan 	int	ret = DDI_SUCCESS;
21726947304SEvan Yan 
21826947304SEvan Yan 	/*
21926947304SEvan Yan 	 * Create a "devctl" minor node to support DEVCTL_DEVICE_*
22026947304SEvan Yan 	 * and DEVCTL_BUS_* ioctls to this bus.
22126947304SEvan Yan 	 */
22226947304SEvan Yan 	if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR,
22326947304SEvan Yan 	    PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR),
22426947304SEvan Yan 	    DDI_NT_NEXUS, 0)) != DDI_SUCCESS) {
22526947304SEvan Yan 		PCIE_DBG("Failed to create devctl minor node for %s%d\n",
22626947304SEvan Yan 		    ddi_driver_name(dip), ddi_get_instance(dip));
22726947304SEvan Yan 
22826947304SEvan Yan 		return (ret);
22926947304SEvan Yan 	}
23026947304SEvan Yan 
23126947304SEvan Yan 	if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) {
23226947304SEvan Yan 		/*
233ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * On some x86 platforms, we observed unexpected hotplug
234ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * initialization failures in recent years. The known cause
235ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * is a hardware issue: while the problem PCI bridges have
236ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * the Hotplug Capable registers set, the machine actually
237ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * does not implement the expected ACPI object.
238ed11b501SColin Zou - Sun Microsystems - Beijing China 		 *
239ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * We don't want to stop PCI driver attach and system boot
240ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * just because of this hotplug initialization failure.
241ed11b501SColin Zou - Sun Microsystems - Beijing China 		 * Continue with a debug message printed.
24226947304SEvan Yan 		 */
243ed11b501SColin Zou - Sun Microsystems - Beijing China 		PCIE_DBG("%s%d: Failed setting hotplug framework\n",
24426947304SEvan Yan 		    ddi_driver_name(dip), ddi_get_instance(dip));
24526947304SEvan Yan 
24626947304SEvan Yan #if defined(__sparc)
24726947304SEvan Yan 		ddi_remove_minor_node(dip, "devctl");
24826947304SEvan Yan 
24926947304SEvan Yan 		return (ret);
25026947304SEvan Yan #endif /* defined(__sparc) */
25126947304SEvan Yan 	}
25226947304SEvan Yan 
25326947304SEvan Yan 	return (DDI_SUCCESS);
25426947304SEvan Yan }
25526947304SEvan Yan 
25626947304SEvan Yan /* ARGSUSED */
25726947304SEvan Yan int
25826947304SEvan Yan pcie_uninit(dev_info_t *dip)
25926947304SEvan Yan {
26026947304SEvan Yan 	int	ret = DDI_SUCCESS;
26126947304SEvan Yan 
26226947304SEvan Yan 	if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED)
26326947304SEvan Yan 		(void) pcie_ari_disable(dip);
26426947304SEvan Yan 
26526947304SEvan Yan 	if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) {
26626947304SEvan Yan 		PCIE_DBG("Failed to uninitialize hotplug for %s%d\n",
26726947304SEvan Yan 		    ddi_driver_name(dip), ddi_get_instance(dip));
26826947304SEvan Yan 
26926947304SEvan Yan 		return (ret);
27026947304SEvan Yan 	}
27126947304SEvan Yan 
27226947304SEvan Yan 	ddi_remove_minor_node(dip, "devctl");
27326947304SEvan Yan 
27426947304SEvan Yan 	return (ret);
27526947304SEvan Yan }
27626947304SEvan Yan 
27770f83219SEvan Yan /*
27870f83219SEvan Yan  * PCIe module interface for enabling hotplug interrupt.
27970f83219SEvan Yan  *
28070f83219SEvan Yan  * It should be called after pcie_init() is done and bus driver's
28170f83219SEvan Yan  * interrupt handlers have being attached.
28270f83219SEvan Yan  */
28370f83219SEvan Yan int
28470f83219SEvan Yan pcie_hpintr_enable(dev_info_t *dip)
28570f83219SEvan Yan {
28670f83219SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
28770f83219SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = PCIE_GET_HP_CTRL(dip);
28870f83219SEvan Yan 
28970f83219SEvan Yan 	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
29070f83219SEvan Yan 		(void) (ctrl_p->hc_ops.enable_hpc_intr)(ctrl_p);
29170f83219SEvan Yan 	} else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
29270f83219SEvan Yan 		(void) pcishpc_enable_irqs(ctrl_p);
29370f83219SEvan Yan 	}
29470f83219SEvan Yan 	return (DDI_SUCCESS);
29570f83219SEvan Yan }
29670f83219SEvan Yan 
29770f83219SEvan Yan /*
29870f83219SEvan Yan  * PCIe module interface for disabling hotplug interrupt.
29970f83219SEvan Yan  *
30070f83219SEvan Yan  * It should be called before pcie_uninit() is called and bus driver's
30170f83219SEvan Yan  * interrupt handlers is dettached.
30270f83219SEvan Yan  */
30370f83219SEvan Yan int
30470f83219SEvan Yan pcie_hpintr_disable(dev_info_t *dip)
30570f83219SEvan Yan {
30670f83219SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
30770f83219SEvan Yan 	pcie_hp_ctrl_t	*ctrl_p = PCIE_GET_HP_CTRL(dip);
30870f83219SEvan Yan 
30970f83219SEvan Yan 	if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
31070f83219SEvan Yan 		(void) (ctrl_p->hc_ops.disable_hpc_intr)(ctrl_p);
31170f83219SEvan Yan 	} else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
31270f83219SEvan Yan 		(void) pcishpc_disable_irqs(ctrl_p);
31370f83219SEvan Yan 	}
31470f83219SEvan Yan 	return (DDI_SUCCESS);
31570f83219SEvan Yan }
31670f83219SEvan Yan 
31726947304SEvan Yan /* ARGSUSED */
31826947304SEvan Yan int
31926947304SEvan Yan pcie_intr(dev_info_t *dip)
32026947304SEvan Yan {
32126947304SEvan Yan 	return (pcie_hp_intr(dip));
32226947304SEvan Yan }
32326947304SEvan Yan 
32426947304SEvan Yan /* ARGSUSED */
32526947304SEvan Yan int
32626947304SEvan Yan pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp)
32726947304SEvan Yan {
32826947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
32926947304SEvan Yan 
33026947304SEvan Yan 	/*
33126947304SEvan Yan 	 * Make sure the open is for the right file type.
33226947304SEvan Yan 	 */
33326947304SEvan Yan 	if (otyp != OTYP_CHR)
33426947304SEvan Yan 		return (EINVAL);
33526947304SEvan Yan 
33626947304SEvan Yan 	/*
33726947304SEvan Yan 	 * Handle the open by tracking the device state.
33826947304SEvan Yan 	 */
33926947304SEvan Yan 	if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) ||
34026947304SEvan Yan 	    ((flags & FEXCL) &&
34126947304SEvan Yan 	    (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) {
34226947304SEvan Yan 		return (EBUSY);
34326947304SEvan Yan 	}
34426947304SEvan Yan 
34526947304SEvan Yan 	if (flags & FEXCL)
34626947304SEvan Yan 		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
34726947304SEvan Yan 	else
34826947304SEvan Yan 		bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN;
34926947304SEvan Yan 
35026947304SEvan Yan 	return (0);
35126947304SEvan Yan }
35226947304SEvan Yan 
35326947304SEvan Yan /* ARGSUSED */
35426947304SEvan Yan int
35526947304SEvan Yan pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp)
35626947304SEvan Yan {
35726947304SEvan Yan 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
35826947304SEvan Yan 
35926947304SEvan Yan 	if (otyp != OTYP_CHR)
36026947304SEvan Yan 		return (EINVAL);
36126947304SEvan Yan 
36226947304SEvan Yan 	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
36326947304SEvan Yan 
36426947304SEvan Yan 	return (0);
36526947304SEvan Yan }
36626947304SEvan Yan 
36726947304SEvan Yan /* ARGSUSED */
36826947304SEvan Yan int
36926947304SEvan Yan pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode,
37026947304SEvan Yan     cred_t *credp, int *rvalp)
37126947304SEvan Yan {
37226947304SEvan Yan 	struct devctl_iocdata	*dcp;
37326947304SEvan Yan 	uint_t			bus_state;
37426947304SEvan Yan 	int			rv = DDI_SUCCESS;
37526947304SEvan Yan 
37626947304SEvan Yan 	/*
37726947304SEvan Yan 	 * We can use the generic implementation for devctl ioctl
37826947304SEvan Yan 	 */
37926947304SEvan Yan 	switch (cmd) {
38026947304SEvan Yan 	case DEVCTL_DEVICE_GETSTATE:
38126947304SEvan Yan 	case DEVCTL_DEVICE_ONLINE:
38226947304SEvan Yan 	case DEVCTL_DEVICE_OFFLINE:
38326947304SEvan Yan 	case DEVCTL_BUS_GETSTATE:
38426947304SEvan Yan 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
38526947304SEvan Yan 	default:
38626947304SEvan Yan 		break;
38726947304SEvan Yan 	}
38826947304SEvan Yan 
38926947304SEvan Yan 	/*
39026947304SEvan Yan 	 * read devctl ioctl data
39126947304SEvan Yan 	 */
39226947304SEvan Yan 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
39326947304SEvan Yan 		return (EFAULT);
39426947304SEvan Yan 
39526947304SEvan Yan 	switch (cmd) {
39626947304SEvan Yan 	case DEVCTL_BUS_QUIESCE:
39726947304SEvan Yan 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
39826947304SEvan Yan 			if (bus_state == BUS_QUIESCED)
39926947304SEvan Yan 				break;
40026947304SEvan Yan 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
40126947304SEvan Yan 		break;
40226947304SEvan Yan 	case DEVCTL_BUS_UNQUIESCE:
40326947304SEvan Yan 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
40426947304SEvan Yan 			if (bus_state == BUS_ACTIVE)
40526947304SEvan Yan 				break;
40626947304SEvan Yan 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
40726947304SEvan Yan 		break;
40826947304SEvan Yan 	case DEVCTL_BUS_RESET:
40926947304SEvan Yan 	case DEVCTL_BUS_RESETALL:
41026947304SEvan Yan 	case DEVCTL_DEVICE_RESET:
41126947304SEvan Yan 		rv = ENOTSUP;
41226947304SEvan Yan 		break;
41326947304SEvan Yan 	default:
41426947304SEvan Yan 		rv = ENOTTY;
41526947304SEvan Yan 	}
41626947304SEvan Yan 
41726947304SEvan Yan 	ndi_dc_freehdl(dcp);
41826947304SEvan Yan 	return (rv);
41926947304SEvan Yan }
42026947304SEvan Yan 
42126947304SEvan Yan /* ARGSUSED */
42226947304SEvan Yan int
42326947304SEvan Yan pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
42426947304SEvan Yan     int flags, char *name, caddr_t valuep, int *lengthp)
42526947304SEvan Yan {
42626947304SEvan Yan 	if (dev == DDI_DEV_T_ANY)
42726947304SEvan Yan 		goto skip;
42826947304SEvan Yan 
42926947304SEvan Yan 	if (PCIE_IS_HOTPLUG_CAPABLE(dip) &&
43026947304SEvan Yan 	    strcmp(name, "pci-occupant") == 0) {
43126947304SEvan Yan 		int	pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
43226947304SEvan Yan 
43326947304SEvan Yan 		pcie_hp_create_occupant_props(dip, dev, pci_dev);
43426947304SEvan Yan 	}
43526947304SEvan Yan 
43626947304SEvan Yan skip:
43726947304SEvan Yan 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
43826947304SEvan Yan }
43926947304SEvan Yan 
440c0da6274SZhi-Jun Robin Fu int
441c0da6274SZhi-Jun Robin Fu pcie_init_cfghdl(dev_info_t *cdip)
442c0da6274SZhi-Jun Robin Fu {
443c0da6274SZhi-Jun Robin Fu 	pcie_bus_t		*bus_p;
444c0da6274SZhi-Jun Robin Fu 	ddi_acc_handle_t	eh = NULL;
445c0da6274SZhi-Jun Robin Fu 
446c0da6274SZhi-Jun Robin Fu 	bus_p = PCIE_DIP2BUS(cdip);
447c0da6274SZhi-Jun Robin Fu 	if (bus_p == NULL)
448c0da6274SZhi-Jun Robin Fu 		return (DDI_FAILURE);
449c0da6274SZhi-Jun Robin Fu 
450c0da6274SZhi-Jun Robin Fu 	/* Create an config access special to error handling */
451c0da6274SZhi-Jun Robin Fu 	if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
452c0da6274SZhi-Jun Robin Fu 		cmn_err(CE_WARN, "Cannot setup config access"
453c0da6274SZhi-Jun Robin Fu 		    " for BDF 0x%x\n", bus_p->bus_bdf);
454c0da6274SZhi-Jun Robin Fu 		return (DDI_FAILURE);
455c0da6274SZhi-Jun Robin Fu 	}
456c0da6274SZhi-Jun Robin Fu 
457c0da6274SZhi-Jun Robin Fu 	bus_p->bus_cfg_hdl = eh;
458c0da6274SZhi-Jun Robin Fu 	return (DDI_SUCCESS);
459c0da6274SZhi-Jun Robin Fu }
460c0da6274SZhi-Jun Robin Fu 
461c0da6274SZhi-Jun Robin Fu void
462c0da6274SZhi-Jun Robin Fu pcie_fini_cfghdl(dev_info_t *cdip)
463c0da6274SZhi-Jun Robin Fu {
464c0da6274SZhi-Jun Robin Fu 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(cdip);
465c0da6274SZhi-Jun Robin Fu 
466c0da6274SZhi-Jun Robin Fu 	pci_config_teardown(&bus_p->bus_cfg_hdl);
467c0da6274SZhi-Jun Robin Fu }
468c0da6274SZhi-Jun Robin Fu 
469d4bc0535SKrishna Elango /*
470d4bc0535SKrishna Elango  * PCI-Express child device initialization.
471d4bc0535SKrishna Elango  * This function enables generic pci-express interrupts and error
472d4bc0535SKrishna Elango  * handling.
473d4bc0535SKrishna Elango  *
474d4bc0535SKrishna Elango  * @param pdip		root dip (root nexus's dip)
475d4bc0535SKrishna Elango  * @param cdip		child's dip (device's dip)
476d4bc0535SKrishna Elango  * @return		DDI_SUCCESS or DDI_FAILURE
477d4bc0535SKrishna Elango  */
478d4bc0535SKrishna Elango /* ARGSUSED */
479d4bc0535SKrishna Elango int
480d4bc0535SKrishna Elango pcie_initchild(dev_info_t *cdip)
481d4bc0535SKrishna Elango {
482d4bc0535SKrishna Elango 	uint16_t		tmp16, reg16;
483d4bc0535SKrishna Elango 	pcie_bus_t		*bus_p;
484fc256490SJason Beloro 	uint32_t		devid, venid;
485d4bc0535SKrishna Elango 
486d4bc0535SKrishna Elango 	bus_p = PCIE_DIP2BUS(cdip);
487d4bc0535SKrishna Elango 	if (bus_p == NULL) {
488d4bc0535SKrishna Elango 		PCIE_DBG("%s: BUS not found.\n",
489d4bc0535SKrishna Elango 		    ddi_driver_name(cdip));
490d4bc0535SKrishna Elango 
491d4bc0535SKrishna Elango 		return (DDI_FAILURE);
492d4bc0535SKrishna Elango 	}
493d4bc0535SKrishna Elango 
494c0da6274SZhi-Jun Robin Fu 	if (pcie_init_cfghdl(cdip) != DDI_SUCCESS)
495c0da6274SZhi-Jun Robin Fu 		return (DDI_FAILURE);
496c0da6274SZhi-Jun Robin Fu 
497fc256490SJason Beloro 	/*
498fc256490SJason Beloro 	 * Update pcie_bus_t with real Vendor Id Device Id.
499fc256490SJason Beloro 	 *
500fc256490SJason Beloro 	 * For assigned devices in IOV environment, the OBP will return
501fc256490SJason Beloro 	 * faked device id/vendor id on configration read and for both
502fc256490SJason Beloro 	 * properties in root domain. translate_devid() function will
503fc256490SJason Beloro 	 * update the properties with real device-id/vendor-id on such
504fc256490SJason Beloro 	 * platforms, so that we can utilize the properties here to get
505fc256490SJason Beloro 	 * real device-id/vendor-id and overwrite the faked ids.
506fc256490SJason Beloro 	 *
507fc256490SJason Beloro 	 * For unassigned devices or devices in non-IOV environment, the
508fc256490SJason Beloro 	 * operation below won't make a difference.
509fc256490SJason Beloro 	 *
510fc256490SJason Beloro 	 * The IOV implementation only supports assignment of PCIE
511fc256490SJason Beloro 	 * endpoint devices. Devices under pci-pci bridges don't need
512fc256490SJason Beloro 	 * operation like this.
513fc256490SJason Beloro 	 */
514fc256490SJason Beloro 	devid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
515fc256490SJason Beloro 	    "device-id", -1);
516fc256490SJason Beloro 	venid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
517fc256490SJason Beloro 	    "vendor-id", -1);
518fc256490SJason Beloro 	bus_p->bus_dev_ven_id = (devid << 16) | (venid & 0xffff);
519fc256490SJason Beloro 
520d4bc0535SKrishna Elango 	/* Clear the device's status register */
521d4bc0535SKrishna Elango 	reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT);
522d4bc0535SKrishna Elango 	PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16);
523d4bc0535SKrishna Elango 
524d4bc0535SKrishna Elango 	/* Setup the device's command register */
525d4bc0535SKrishna Elango 	reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM);
526d4bc0535SKrishna Elango 	tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default;
527d4bc0535SKrishna Elango 
528d4bc0535SKrishna Elango #if defined(__i386) || defined(__amd64)
529d4bc0535SKrishna Elango 	boolean_t empty_io_range = B_FALSE;
530d4bc0535SKrishna Elango 	boolean_t empty_mem_range = B_FALSE;
531d4bc0535SKrishna Elango 	/*
532d4bc0535SKrishna Elango 	 * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem
533d4bc0535SKrishna Elango 	 * access as it can cause a hang if enabled.
534d4bc0535SKrishna Elango 	 */
535d4bc0535SKrishna Elango 	pcie_check_io_mem_range(bus_p->bus_cfg_hdl, &empty_io_range,
536d4bc0535SKrishna Elango 	    &empty_mem_range);
537d4bc0535SKrishna Elango 	if ((empty_io_range == B_TRUE) &&
538d4bc0535SKrishna Elango 	    (pcie_command_default & PCI_COMM_IO)) {
539d4bc0535SKrishna Elango 		tmp16 &= ~PCI_COMM_IO;
540d4bc0535SKrishna Elango 		PCIE_DBG("No I/O range found for %s, bdf 0x%x\n",
541d4bc0535SKrishna Elango 		    ddi_driver_name(cdip), bus_p->bus_bdf);
542d4bc0535SKrishna Elango 	}
543d4bc0535SKrishna Elango 	if ((empty_mem_range == B_TRUE) &&
544d4bc0535SKrishna Elango 	    (pcie_command_default & PCI_COMM_MAE)) {
545d4bc0535SKrishna Elango 		tmp16 &= ~PCI_COMM_MAE;
546d4bc0535SKrishna Elango 		PCIE_DBG("No Mem range found for %s, bdf 0x%x\n",
547d4bc0535SKrishna Elango 		    ddi_driver_name(cdip), bus_p->bus_bdf);
548d4bc0535SKrishna Elango 	}
549d4bc0535SKrishna Elango #endif /* defined(__i386) || defined(__amd64) */
550d4bc0535SKrishna Elango 
551d4bc0535SKrishna Elango 	if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p))
552d4bc0535SKrishna Elango 		tmp16 &= ~PCI_COMM_SERR_ENABLE;
553d4bc0535SKrishna Elango 
554d4bc0535SKrishna Elango 	PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16);
555d4bc0535SKrishna Elango 	PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16);
556d4bc0535SKrishna Elango 
557d4bc0535SKrishna Elango 	/*
558d4bc0535SKrishna Elango 	 * If the device has a bus control register then program it
559d4bc0535SKrishna Elango 	 * based on the settings in the command register.
560d4bc0535SKrishna Elango 	 */
561d4bc0535SKrishna Elango 	if (PCIE_IS_BDG(bus_p)) {
562d4bc0535SKrishna Elango 		/* Clear the device's secondary status register */
563d4bc0535SKrishna Elango 		reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
564d4bc0535SKrishna Elango 		PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16);
565d4bc0535SKrishna Elango 
566d4bc0535SKrishna Elango 		/* Setup the device's secondary command register */
567d4bc0535SKrishna Elango 		reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
568d4bc0535SKrishna Elango 		tmp16 = (reg16 & pcie_bdg_command_default_fw);
569d4bc0535SKrishna Elango 
570d4bc0535SKrishna Elango 		tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE;
571d4bc0535SKrishna Elango 		/*
572d4bc0535SKrishna Elango 		 * Workaround for this Nvidia bridge. Don't enable the SERR
573d4bc0535SKrishna Elango 		 * enable bit in the bridge control register as it could lead to
574d4bc0535SKrishna Elango 		 * bogus NMIs.
575d4bc0535SKrishna Elango 		 */
576d4bc0535SKrishna Elango 		if (bus_p->bus_dev_ven_id == 0x037010DE)
577d4bc0535SKrishna Elango 			tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
578d4bc0535SKrishna Elango 
579d4bc0535SKrishna Elango 		if (pcie_command_default & PCI_COMM_PARITY_DETECT)
580d4bc0535SKrishna Elango 			tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
581d4bc0535SKrishna Elango 
582d4bc0535SKrishna Elango 		/*
583d4bc0535SKrishna Elango 		 * Enable Master Abort Mode only if URs have not been masked.
584d4bc0535SKrishna Elango 		 * For PCI and PCIe-PCI bridges, enabling this bit causes a
585d4bc0535SKrishna Elango 		 * Master Aborts/UR to be forwarded as a UR/TA or SERR.  If this
586d4bc0535SKrishna Elango 		 * bit is masked, posted requests are dropped and non-posted
587d4bc0535SKrishna Elango 		 * requests are returned with -1.
588d4bc0535SKrishna Elango 		 */
589d4bc0535SKrishna Elango 		if (pcie_aer_uce_mask & PCIE_AER_UCE_UR)
590d4bc0535SKrishna Elango 			tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE;
591d4bc0535SKrishna Elango 		else
592d4bc0535SKrishna Elango 			tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
593d4bc0535SKrishna Elango 		PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16);
594d4bc0535SKrishna Elango 		PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL,
595d4bc0535SKrishna Elango 		    reg16);
596d4bc0535SKrishna Elango 	}
597d4bc0535SKrishna Elango 
598d4bc0535SKrishna Elango 	if (PCIE_IS_PCIE(bus_p)) {
599d4bc0535SKrishna Elango 		/* Setup PCIe device control register */
600d4bc0535SKrishna Elango 		reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
60183e6495bSDaniel Ice 		/* note: MPS/MRRS are initialized in pcie_initchild_mps() */
60283e6495bSDaniel Ice 		tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
60383e6495bSDaniel Ice 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
60483e6495bSDaniel Ice 		    (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
60583e6495bSDaniel Ice 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK));
606d4bc0535SKrishna Elango 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
607d4bc0535SKrishna Elango 		PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
608d4bc0535SKrishna Elango 
609d4bc0535SKrishna Elango 		/* Enable PCIe errors */
610d4bc0535SKrishna Elango 		pcie_enable_errors(cdip);
611d4bc0535SKrishna Elango 	}
612d4bc0535SKrishna Elango 
61326947304SEvan Yan 	bus_p->bus_ari = B_FALSE;
61426947304SEvan Yan 	if ((pcie_ari_is_enabled(ddi_get_parent(cdip))
61526947304SEvan Yan 	    == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip)
61626947304SEvan Yan 	    == PCIE_ARI_DEVICE)) {
61726947304SEvan Yan 		bus_p->bus_ari = B_TRUE;
61826947304SEvan Yan 	}
61926947304SEvan Yan 
620c0da6274SZhi-Jun Robin Fu 	if (pcie_initchild_mps(cdip) == DDI_FAILURE) {
621c0da6274SZhi-Jun Robin Fu 		pcie_fini_cfghdl(cdip);
622d4bc0535SKrishna Elango 		return (DDI_FAILURE);
623c0da6274SZhi-Jun Robin Fu 	}
624d4bc0535SKrishna Elango 
625d4bc0535SKrishna Elango 	return (DDI_SUCCESS);
626d4bc0535SKrishna Elango }
627d4bc0535SKrishna Elango 
628d4bc0535SKrishna Elango static void
629d4bc0535SKrishna Elango pcie_init_pfd(dev_info_t *dip)
630d4bc0535SKrishna Elango {
631d4bc0535SKrishna Elango 	pf_data_t	*pfd_p = PCIE_ZALLOC(pf_data_t);
632d4bc0535SKrishna Elango 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
633d4bc0535SKrishna Elango 
634d4bc0535SKrishna Elango 	PCIE_DIP2PFD(dip) = pfd_p;
635d4bc0535SKrishna Elango 
636d4bc0535SKrishna Elango 	pfd_p->pe_bus_p = bus_p;
637d4bc0535SKrishna Elango 	pfd_p->pe_severity_flags = 0;
638fc256490SJason Beloro 	pfd_p->pe_orig_severity_flags = 0;
639d4bc0535SKrishna Elango 	pfd_p->pe_lock = B_FALSE;
640d4bc0535SKrishna Elango 	pfd_p->pe_valid = B_FALSE;
641d4bc0535SKrishna Elango 
642d4bc0535SKrishna Elango 	/* Allocate the root fault struct for both RC and RP */
643d4bc0535SKrishna Elango 	if (PCIE_IS_ROOT(bus_p)) {
644d4bc0535SKrishna Elango 		PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
645d4bc0535SKrishna Elango 		PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
646fc256490SJason Beloro 		PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t);
647d4bc0535SKrishna Elango 	}
648d4bc0535SKrishna Elango 
649d4bc0535SKrishna Elango 	PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
650fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t);
651fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
652d4bc0535SKrishna Elango 
653d4bc0535SKrishna Elango 	if (PCIE_IS_BDG(bus_p))
654d4bc0535SKrishna Elango 		PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
655d4bc0535SKrishna Elango 
656d4bc0535SKrishna Elango 	if (PCIE_IS_PCIE(bus_p)) {
657d4bc0535SKrishna Elango 		PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
658d4bc0535SKrishna Elango 
659d4bc0535SKrishna Elango 		if (PCIE_IS_RP(bus_p))
660d4bc0535SKrishna Elango 			PCIE_RP_REG(pfd_p) =
661d4bc0535SKrishna Elango 			    PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
662d4bc0535SKrishna Elango 
663d4bc0535SKrishna Elango 		PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
664d4bc0535SKrishna Elango 		PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
665d4bc0535SKrishna Elango 
666d4bc0535SKrishna Elango 		if (PCIE_IS_RP(bus_p)) {
667d4bc0535SKrishna Elango 			PCIE_ADV_RP_REG(pfd_p) =
668d4bc0535SKrishna Elango 			    PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
669d4bc0535SKrishna Elango 			PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id =
670d4bc0535SKrishna Elango 			    PCIE_INVALID_BDF;
671d4bc0535SKrishna Elango 			PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id =
672d4bc0535SKrishna Elango 			    PCIE_INVALID_BDF;
673d4bc0535SKrishna Elango 		} else if (PCIE_IS_PCIE_BDG(bus_p)) {
674d4bc0535SKrishna Elango 			PCIE_ADV_BDG_REG(pfd_p) =
675d4bc0535SKrishna Elango 			    PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t);
676d4bc0535SKrishna Elango 			PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf =
677d4bc0535SKrishna Elango 			    PCIE_INVALID_BDF;
678d4bc0535SKrishna Elango 		}
679d4bc0535SKrishna Elango 
680d4bc0535SKrishna Elango 		if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
681d4bc0535SKrishna Elango 			PCIX_BDG_ERR_REG(pfd_p) =
682d4bc0535SKrishna Elango 			    PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
683d4bc0535SKrishna Elango 
684d4bc0535SKrishna Elango 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
685d4bc0535SKrishna Elango 				PCIX_BDG_ECC_REG(pfd_p, 0) =
686d4bc0535SKrishna Elango 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
687d4bc0535SKrishna Elango 				PCIX_BDG_ECC_REG(pfd_p, 1) =
688d4bc0535SKrishna Elango 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
689d4bc0535SKrishna Elango 			}
690d4bc0535SKrishna Elango 		}
691d4bc0535SKrishna Elango 	} else if (PCIE_IS_PCIX(bus_p)) {
692d4bc0535SKrishna Elango 		if (PCIE_IS_BDG(bus_p)) {
693d4bc0535SKrishna Elango 			PCIX_BDG_ERR_REG(pfd_p) =
694d4bc0535SKrishna Elango 			    PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
695d4bc0535SKrishna Elango 
696d4bc0535SKrishna Elango 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
697d4bc0535SKrishna Elango 				PCIX_BDG_ECC_REG(pfd_p, 0) =
698d4bc0535SKrishna Elango 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
699d4bc0535SKrishna Elango 				PCIX_BDG_ECC_REG(pfd_p, 1) =
700d4bc0535SKrishna Elango 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
701d4bc0535SKrishna Elango 			}
702d4bc0535SKrishna Elango 		} else {
703d4bc0535SKrishna Elango 			PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t);
704d4bc0535SKrishna Elango 
705d4bc0535SKrishna Elango 			if (PCIX_ECC_VERSION_CHECK(bus_p))
706d4bc0535SKrishna Elango 				PCIX_ECC_REG(pfd_p) =
707d4bc0535SKrishna Elango 				    PCIE_ZALLOC(pf_pcix_ecc_regs_t);
708d4bc0535SKrishna Elango 		}
709d4bc0535SKrishna Elango 	}
710d4bc0535SKrishna Elango }
711d4bc0535SKrishna Elango 
712d4bc0535SKrishna Elango static void
713d4bc0535SKrishna Elango pcie_fini_pfd(dev_info_t *dip)
714d4bc0535SKrishna Elango {
715d4bc0535SKrishna Elango 	pf_data_t	*pfd_p = PCIE_DIP2PFD(dip);
716d4bc0535SKrishna Elango 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
717d4bc0535SKrishna Elango 
718d4bc0535SKrishna Elango 	if (PCIE_IS_PCIE(bus_p)) {
719d4bc0535SKrishna Elango 		if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
720d4bc0535SKrishna Elango 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
721d4bc0535SKrishna Elango 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
722d4bc0535SKrishna Elango 				    sizeof (pf_pcix_ecc_regs_t));
723d4bc0535SKrishna Elango 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
724d4bc0535SKrishna Elango 				    sizeof (pf_pcix_ecc_regs_t));
725d4bc0535SKrishna Elango 			}
726d4bc0535SKrishna Elango 
727d4bc0535SKrishna Elango 			kmem_free(PCIX_BDG_ERR_REG(pfd_p),
728d4bc0535SKrishna Elango 			    sizeof (pf_pcix_bdg_err_regs_t));
729d4bc0535SKrishna Elango 		}
730d4bc0535SKrishna Elango 
731d4bc0535SKrishna Elango 		if (PCIE_IS_RP(bus_p))
732d4bc0535SKrishna Elango 			kmem_free(PCIE_ADV_RP_REG(pfd_p),
733d4bc0535SKrishna Elango 			    sizeof (pf_pcie_adv_rp_err_regs_t));
734d4bc0535SKrishna Elango 		else if (PCIE_IS_PCIE_BDG(bus_p))
735d4bc0535SKrishna Elango 			kmem_free(PCIE_ADV_BDG_REG(pfd_p),
736d4bc0535SKrishna Elango 			    sizeof (pf_pcie_adv_bdg_err_regs_t));
737d4bc0535SKrishna Elango 
738d4bc0535SKrishna Elango 		kmem_free(PCIE_ADV_REG(pfd_p),
739d4bc0535SKrishna Elango 		    sizeof (pf_pcie_adv_err_regs_t));
740d4bc0535SKrishna Elango 
741d4bc0535SKrishna Elango 		if (PCIE_IS_RP(bus_p))
742d4bc0535SKrishna Elango 			kmem_free(PCIE_RP_REG(pfd_p),
743d4bc0535SKrishna Elango 			    sizeof (pf_pcie_rp_err_regs_t));
744d4bc0535SKrishna Elango 
745d4bc0535SKrishna Elango 		kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
746d4bc0535SKrishna Elango 	} else if (PCIE_IS_PCIX(bus_p)) {
747d4bc0535SKrishna Elango 		if (PCIE_IS_BDG(bus_p)) {
748d4bc0535SKrishna Elango 			if (PCIX_ECC_VERSION_CHECK(bus_p)) {
749d4bc0535SKrishna Elango 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
750d4bc0535SKrishna Elango 				    sizeof (pf_pcix_ecc_regs_t));
751d4bc0535SKrishna Elango 				kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
752d4bc0535SKrishna Elango 				    sizeof (pf_pcix_ecc_regs_t));
753d4bc0535SKrishna Elango 			}
754d4bc0535SKrishna Elango 
755d4bc0535SKrishna Elango 			kmem_free(PCIX_BDG_ERR_REG(pfd_p),
756d4bc0535SKrishna Elango 			    sizeof (pf_pcix_bdg_err_regs_t));
757d4bc0535SKrishna Elango 		} else {
758d4bc0535SKrishna Elango 			if (PCIX_ECC_VERSION_CHECK(bus_p))
759d4bc0535SKrishna Elango 				kmem_free(PCIX_ECC_REG(pfd_p),
760d4bc0535SKrishna Elango 				    sizeof (pf_pcix_ecc_regs_t));
761d4bc0535SKrishna Elango 
762d4bc0535SKrishna Elango 			kmem_free(PCIX_ERR_REG(pfd_p),
763d4bc0535SKrishna Elango 			    sizeof (pf_pcix_err_regs_t));
764d4bc0535SKrishna Elango 		}
765d4bc0535SKrishna Elango 	}
766d4bc0535SKrishna Elango 
767d4bc0535SKrishna Elango 	if (PCIE_IS_BDG(bus_p))
768d4bc0535SKrishna Elango 		kmem_free(PCI_BDG_ERR_REG(pfd_p),
769d4bc0535SKrishna Elango 		    sizeof (pf_pci_bdg_err_regs_t));
770d4bc0535SKrishna Elango 
771fc256490SJason Beloro 	kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t));
772d4bc0535SKrishna Elango 	kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
773d4bc0535SKrishna Elango 
774fc256490SJason Beloro 	if (PCIE_IS_ROOT(bus_p)) {
775d4bc0535SKrishna Elango 		kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
776fc256490SJason Beloro 		kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t));
777fc256490SJason Beloro 	}
778d4bc0535SKrishna Elango 
779d4bc0535SKrishna Elango 	kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t));
780d4bc0535SKrishna Elango 
781d4bc0535SKrishna Elango 	PCIE_DIP2PFD(dip) = NULL;
782d4bc0535SKrishna Elango }
783d4bc0535SKrishna Elango 
784d4bc0535SKrishna Elango 
785d4bc0535SKrishna Elango /*
786d4bc0535SKrishna Elango  * Special functions to allocate pf_data_t's for PCIe root complexes.
787d4bc0535SKrishna Elango  * Note: Root Complex not Root Port
788d4bc0535SKrishna Elango  */
789d4bc0535SKrishna Elango void
790d4bc0535SKrishna Elango pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p)
791d4bc0535SKrishna Elango {
792d4bc0535SKrishna Elango 	pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip);
793d4bc0535SKrishna Elango 	pfd_p->pe_severity_flags = 0;
794fc256490SJason Beloro 	pfd_p->pe_orig_severity_flags = 0;
795d4bc0535SKrishna Elango 	pfd_p->pe_lock = B_FALSE;
796d4bc0535SKrishna Elango 	pfd_p->pe_valid = B_FALSE;
797d4bc0535SKrishna Elango 
798d4bc0535SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
799d4bc0535SKrishna Elango 	PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
800fc256490SJason Beloro 	PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t);
801d4bc0535SKrishna Elango 	PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
802fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t);
803fc256490SJason Beloro 	PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
804d4bc0535SKrishna Elango 	PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
805d4bc0535SKrishna Elango 	PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
806d4bc0535SKrishna Elango 	PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
807d4bc0535SKrishna Elango 	PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
808d4bc0535SKrishna Elango 	PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
809fc256490SJason Beloro 	PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = PCIE_INVALID_BDF;
810fc256490SJason Beloro 	PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = PCIE_INVALID_BDF;
811d4bc0535SKrishna Elango 
812d4bc0535SKrishna Elango 	PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity;
813d4bc0535SKrishna Elango }
814d4bc0535SKrishna Elango 
815d4bc0535SKrishna Elango void
816d4bc0535SKrishna Elango pcie_rc_fini_pfd(pf_data_t *pfd_p)
817d4bc0535SKrishna Elango {
818d4bc0535SKrishna Elango 	kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t));
819d4bc0535SKrishna Elango 	kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t));
820d4bc0535SKrishna Elango 	kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t));
821d4bc0535SKrishna Elango 	kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
822d4bc0535SKrishna Elango 	kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t));
823fc256490SJason Beloro 	kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t));
824d4bc0535SKrishna Elango 	kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
825d4bc0535SKrishna Elango 	kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
826fc256490SJason Beloro 	kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t));
827d4bc0535SKrishna Elango }
828d4bc0535SKrishna Elango 
829c0da6274SZhi-Jun Robin Fu /*
830c0da6274SZhi-Jun Robin Fu  * init pcie_bus_t for root complex
831c0da6274SZhi-Jun Robin Fu  *
832c0da6274SZhi-Jun Robin Fu  * Only a few of the fields in bus_t is valid for root complex.
833c0da6274SZhi-Jun Robin Fu  * The fields that are bracketed are initialized in this routine:
834c0da6274SZhi-Jun Robin Fu  *
835c0da6274SZhi-Jun Robin Fu  * dev_info_t *		<bus_dip>
836c0da6274SZhi-Jun Robin Fu  * dev_info_t *		bus_rp_dip
837c0da6274SZhi-Jun Robin Fu  * ddi_acc_handle_t	bus_cfg_hdl
838c0da6274SZhi-Jun Robin Fu  * uint_t		<bus_fm_flags>
839c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	bus_bdf
840c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	bus_rp_bdf
841c0da6274SZhi-Jun Robin Fu  * uint32_t		bus_dev_ven_id
842c0da6274SZhi-Jun Robin Fu  * uint8_t		bus_rev_id
843c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_hdr_type>
844c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_dev_type>
845c0da6274SZhi-Jun Robin Fu  * uint8_t		bus_bdg_secbus
846c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_pcie_off
847c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_aer_off>
848c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_pcix_off
849c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_ecc_ver
850c0da6274SZhi-Jun Robin Fu  * pci_bus_range_t	bus_bus_range
851c0da6274SZhi-Jun Robin Fu  * ppb_ranges_t	*	bus_addr_ranges
852c0da6274SZhi-Jun Robin Fu  * int			bus_addr_entries
853c0da6274SZhi-Jun Robin Fu  * pci_regspec_t *	bus_assigned_addr
854c0da6274SZhi-Jun Robin Fu  * int			bus_assigned_entries
855c0da6274SZhi-Jun Robin Fu  * pf_data_t *		bus_pfd
856fc256490SJason Beloro  * pcie_domain_t *	<bus_dom>
857c0da6274SZhi-Jun Robin Fu  * int			bus_mps
858c0da6274SZhi-Jun Robin Fu  * uint64_t		bus_cfgacc_base
859c0da6274SZhi-Jun Robin Fu  * void	*		bus_plat_private
860c0da6274SZhi-Jun Robin Fu  */
861d4bc0535SKrishna Elango void
862d4bc0535SKrishna Elango pcie_rc_init_bus(dev_info_t *dip)
863d4bc0535SKrishna Elango {
864d4bc0535SKrishna Elango 	pcie_bus_t *bus_p;
865d4bc0535SKrishna Elango 
866d4bc0535SKrishna Elango 	bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
867d4bc0535SKrishna Elango 	bus_p->bus_dip = dip;
868d4bc0535SKrishna Elango 	bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO;
869d4bc0535SKrishna Elango 	bus_p->bus_hdr_type = PCI_HEADER_ONE;
870d4bc0535SKrishna Elango 
871d4bc0535SKrishna Elango 	/* Fake that there are AER logs */
872d4bc0535SKrishna Elango 	bus_p->bus_aer_off = (uint16_t)-1;
873d4bc0535SKrishna Elango 
874d4bc0535SKrishna Elango 	/* Needed only for handle lookup */
875d4bc0535SKrishna Elango 	bus_p->bus_fm_flags |= PF_FM_READY;
876d4bc0535SKrishna Elango 
877d4bc0535SKrishna Elango 	ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p);
878fc256490SJason Beloro 
879fc256490SJason Beloro 	PCIE_BUS2DOM(bus_p) = PCIE_ZALLOC(pcie_domain_t);
880d4bc0535SKrishna Elango }
881d4bc0535SKrishna Elango 
882d4bc0535SKrishna Elango void
883d4bc0535SKrishna Elango pcie_rc_fini_bus(dev_info_t *dip)
884d4bc0535SKrishna Elango {
885c0da6274SZhi-Jun Robin Fu 	pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip);
886d4bc0535SKrishna Elango 	ndi_set_bus_private(dip, B_FALSE, NULL, NULL);
887fc256490SJason Beloro 	kmem_free(PCIE_BUS2DOM(bus_p), sizeof (pcie_domain_t));
888d4bc0535SKrishna Elango 	kmem_free(bus_p, sizeof (pcie_bus_t));
889d4bc0535SKrishna Elango }
890d4bc0535SKrishna Elango 
891d4bc0535SKrishna Elango /*
892c0da6274SZhi-Jun Robin Fu  * partially init pcie_bus_t for device (dip,bdf) for accessing pci
893c0da6274SZhi-Jun Robin Fu  * config space
894d4bc0535SKrishna Elango  *
895c0da6274SZhi-Jun Robin Fu  * This routine is invoked during boot, either after creating a devinfo node
896c0da6274SZhi-Jun Robin Fu  * (x86 case) or during px driver attach (sparc case); it is also invoked
897c0da6274SZhi-Jun Robin Fu  * in hotplug context after a devinfo node is created.
898c0da6274SZhi-Jun Robin Fu  *
899c0da6274SZhi-Jun Robin Fu  * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL
900c0da6274SZhi-Jun Robin Fu  * is set:
901c0da6274SZhi-Jun Robin Fu  *
902c0da6274SZhi-Jun Robin Fu  * dev_info_t *		<bus_dip>
903c0da6274SZhi-Jun Robin Fu  * dev_info_t *		<bus_rp_dip>
904c0da6274SZhi-Jun Robin Fu  * ddi_acc_handle_t	bus_cfg_hdl
905c0da6274SZhi-Jun Robin Fu  * uint_t		bus_fm_flags
906c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	<bus_bdf>
907c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	<bus_rp_bdf>
908c0da6274SZhi-Jun Robin Fu  * uint32_t		<bus_dev_ven_id>
909c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_rev_id>
910c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_hdr_type>
911c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_dev_type>
912c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_bdg_secbus
913c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_pcie_off>
914c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_aer_off>
915c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_pcix_off>
916c0da6274SZhi-Jun Robin Fu  * uint16_t		<bus_ecc_ver>
917c0da6274SZhi-Jun Robin Fu  * pci_bus_range_t	bus_bus_range
918c0da6274SZhi-Jun Robin Fu  * ppb_ranges_t	*	bus_addr_ranges
919c0da6274SZhi-Jun Robin Fu  * int			bus_addr_entries
920c0da6274SZhi-Jun Robin Fu  * pci_regspec_t *	bus_assigned_addr
921c0da6274SZhi-Jun Robin Fu  * int			bus_assigned_entries
922c0da6274SZhi-Jun Robin Fu  * pf_data_t *		bus_pfd
923fc256490SJason Beloro  * pcie_domain_t *	bus_dom
924c0da6274SZhi-Jun Robin Fu  * int			bus_mps
925c0da6274SZhi-Jun Robin Fu  * uint64_t		bus_cfgacc_base
926c0da6274SZhi-Jun Robin Fu  * void	*		bus_plat_private
927c0da6274SZhi-Jun Robin Fu  *
928c0da6274SZhi-Jun Robin Fu  * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL
929c0da6274SZhi-Jun Robin Fu  * is set:
930c0da6274SZhi-Jun Robin Fu  *
931c0da6274SZhi-Jun Robin Fu  * dev_info_t *		bus_dip
932c0da6274SZhi-Jun Robin Fu  * dev_info_t *		bus_rp_dip
933c0da6274SZhi-Jun Robin Fu  * ddi_acc_handle_t	bus_cfg_hdl
934c0da6274SZhi-Jun Robin Fu  * uint_t		bus_fm_flags
935c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	bus_bdf
936c0da6274SZhi-Jun Robin Fu  * pcie_req_id_t	bus_rp_bdf
937c0da6274SZhi-Jun Robin Fu  * uint32_t		bus_dev_ven_id
938c0da6274SZhi-Jun Robin Fu  * uint8_t		bus_rev_id
939c0da6274SZhi-Jun Robin Fu  * uint8_t		bus_hdr_type
940c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_dev_type
941c0da6274SZhi-Jun Robin Fu  * uint8_t		<bus_bdg_secbus>
942c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_pcie_off
943c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_aer_off
944c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_pcix_off
945c0da6274SZhi-Jun Robin Fu  * uint16_t		bus_ecc_ver
946c0da6274SZhi-Jun Robin Fu  * pci_bus_range_t	<bus_bus_range>
947c0da6274SZhi-Jun Robin Fu  * ppb_ranges_t	*	<bus_addr_ranges>
948c0da6274SZhi-Jun Robin Fu  * int			<bus_addr_entries>
949c0da6274SZhi-Jun Robin Fu  * pci_regspec_t *	<bus_assigned_addr>
950c0da6274SZhi-Jun Robin Fu  * int			<bus_assigned_entries>
951c0da6274SZhi-Jun Robin Fu  * pf_data_t *		<bus_pfd>
952fc256490SJason Beloro  * pcie_domain_t *	bus_dom
953c0da6274SZhi-Jun Robin Fu  * int			bus_mps
954c0da6274SZhi-Jun Robin Fu  * uint64_t		bus_cfgacc_base
955c0da6274SZhi-Jun Robin Fu  * void	*		<bus_plat_private>
956d4bc0535SKrishna Elango  */
957c0da6274SZhi-Jun Robin Fu 
958d4bc0535SKrishna Elango pcie_bus_t *
959c0da6274SZhi-Jun Robin Fu pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags)
960d4bc0535SKrishna Elango {
961c0da6274SZhi-Jun Robin Fu 	uint16_t	status, base, baseptr, num_cap;
962c0da6274SZhi-Jun Robin Fu 	uint32_t	capid;
963d4bc0535SKrishna Elango 	int		range_size;
964c0da6274SZhi-Jun Robin Fu 	pcie_bus_t	*bus_p;
965c0da6274SZhi-Jun Robin Fu 	dev_info_t	*rcdip;
966d4bc0535SKrishna Elango 	dev_info_t	*pdip;
967d4bc0535SKrishna Elango 	const char	*errstr = NULL;
968d4bc0535SKrishna Elango 
969c0da6274SZhi-Jun Robin Fu 	if (!(flags & PCIE_BUS_INITIAL))
970c0da6274SZhi-Jun Robin Fu 		goto initial_done;
971d4bc0535SKrishna Elango 
972d4bc0535SKrishna Elango 	bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
973d4bc0535SKrishna Elango 
974c0da6274SZhi-Jun Robin Fu 	bus_p->bus_dip = dip;
975c0da6274SZhi-Jun Robin Fu 	bus_p->bus_bdf = bdf;
976d4bc0535SKrishna Elango 
977c0da6274SZhi-Jun Robin Fu 	rcdip = pcie_get_rc_dip(dip);
978c0da6274SZhi-Jun Robin Fu 	ASSERT(rcdip != NULL);
97926947304SEvan Yan 
980c0da6274SZhi-Jun Robin Fu 	/* Save the Vendor ID, Device ID and revision ID */
981c0da6274SZhi-Jun Robin Fu 	bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID);
982c0da6274SZhi-Jun Robin Fu 	bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID);
983d4bc0535SKrishna Elango 	/* Save the Header Type */
984c0da6274SZhi-Jun Robin Fu 	bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER);
985d4bc0535SKrishna Elango 	bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
986d4bc0535SKrishna Elango 
987c0da6274SZhi-Jun Robin Fu 	/*
988c0da6274SZhi-Jun Robin Fu 	 * Figure out the device type and all the relavant capability offsets
989c0da6274SZhi-Jun Robin Fu 	 */
990c0da6274SZhi-Jun Robin Fu 	/* set default value */
991c0da6274SZhi-Jun Robin Fu 	bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
992d4bc0535SKrishna Elango 
993c0da6274SZhi-Jun Robin Fu 	status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT);
994c0da6274SZhi-Jun Robin Fu 	if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP))
995c0da6274SZhi-Jun Robin Fu 		goto caps_done; /* capability not supported */
996c0da6274SZhi-Jun Robin Fu 
997c0da6274SZhi-Jun Robin Fu 	/* Relevant conventional capabilities first */
998c0da6274SZhi-Jun Robin Fu 
999c0da6274SZhi-Jun Robin Fu 	/* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */
1000c0da6274SZhi-Jun Robin Fu 	num_cap = 2;
1001c0da6274SZhi-Jun Robin Fu 
1002c0da6274SZhi-Jun Robin Fu 	switch (bus_p->bus_hdr_type) {
1003c0da6274SZhi-Jun Robin Fu 	case PCI_HEADER_ZERO:
1004c0da6274SZhi-Jun Robin Fu 		baseptr = PCI_CONF_CAP_PTR;
1005c0da6274SZhi-Jun Robin Fu 		break;
1006c0da6274SZhi-Jun Robin Fu 	case PCI_HEADER_PPB:
1007c0da6274SZhi-Jun Robin Fu 		baseptr = PCI_BCNF_CAP_PTR;
1008c0da6274SZhi-Jun Robin Fu 		break;
1009c0da6274SZhi-Jun Robin Fu 	case PCI_HEADER_CARDBUS:
1010c0da6274SZhi-Jun Robin Fu 		baseptr = PCI_CBUS_CAP_PTR;
1011c0da6274SZhi-Jun Robin Fu 		break;
1012c0da6274SZhi-Jun Robin Fu 	default:
1013c0da6274SZhi-Jun Robin Fu 		cmn_err(CE_WARN, "%s: unexpected pci header type:%x",
1014c0da6274SZhi-Jun Robin Fu 		    __func__, bus_p->bus_hdr_type);
1015c0da6274SZhi-Jun Robin Fu 		goto caps_done;
1016c0da6274SZhi-Jun Robin Fu 	}
1017c0da6274SZhi-Jun Robin Fu 
1018c0da6274SZhi-Jun Robin Fu 	base = baseptr;
1019c0da6274SZhi-Jun Robin Fu 	for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap;
1020c0da6274SZhi-Jun Robin Fu 	    base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) {
1021c0da6274SZhi-Jun Robin Fu 		capid = pci_cfgacc_get8(rcdip, bdf, base);
1022c0da6274SZhi-Jun Robin Fu 		switch (capid) {
1023c0da6274SZhi-Jun Robin Fu 		case PCI_CAP_ID_PCI_E:
1024c0da6274SZhi-Jun Robin Fu 			bus_p->bus_pcie_off = base;
1025c0da6274SZhi-Jun Robin Fu 			bus_p->bus_dev_type = pci_cfgacc_get16(rcdip, bdf,
1026c0da6274SZhi-Jun Robin Fu 			    base + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
102726947304SEvan Yan 
102826947304SEvan Yan 			/* Check and save PCIe hotplug capability information */
102926947304SEvan Yan 			if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
1030c0da6274SZhi-Jun Robin Fu 			    (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP)
103126947304SEvan Yan 			    & PCIE_PCIECAP_SLOT_IMPL) &&
1032c0da6274SZhi-Jun Robin Fu 			    (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP)
103326947304SEvan Yan 			    & PCIE_SLOTCAP_HP_CAPABLE))
103426947304SEvan Yan 				bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
1035d4bc0535SKrishna Elango 
1036c0da6274SZhi-Jun Robin Fu 			num_cap--;
1037c0da6274SZhi-Jun Robin Fu 			break;
1038c0da6274SZhi-Jun Robin Fu 		case PCI_CAP_ID_PCIX:
1039c0da6274SZhi-Jun Robin Fu 			bus_p->bus_pcix_off = base;
1040d4bc0535SKrishna Elango 			if (PCIE_IS_BDG(bus_p))
1041c0da6274SZhi-Jun Robin Fu 				bus_p->bus_ecc_ver =
1042c0da6274SZhi-Jun Robin Fu 				    pci_cfgacc_get16(rcdip, bdf, base +
1043d4bc0535SKrishna Elango 				    PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
1044d4bc0535SKrishna Elango 			else
1045c0da6274SZhi-Jun Robin Fu 				bus_p->bus_ecc_ver =
1046c0da6274SZhi-Jun Robin Fu 				    pci_cfgacc_get16(rcdip, bdf, base +
1047d4bc0535SKrishna Elango 				    PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
1048c0da6274SZhi-Jun Robin Fu 			num_cap--;
1049c0da6274SZhi-Jun Robin Fu 			break;
1050c0da6274SZhi-Jun Robin Fu 		default:
1051c0da6274SZhi-Jun Robin Fu 			break;
1052c0da6274SZhi-Jun Robin Fu 		}
1053d4bc0535SKrishna Elango 	}
1054d4bc0535SKrishna Elango 
105526947304SEvan Yan 	/* Check and save PCI hotplug (SHPC) capability information */
1056c0da6274SZhi-Jun Robin Fu 	if (PCIE_IS_BDG(bus_p)) {
1057c0da6274SZhi-Jun Robin Fu 		base = baseptr;
1058c0da6274SZhi-Jun Robin Fu 		for (base = pci_cfgacc_get8(rcdip, bdf, base);
1059c0da6274SZhi-Jun Robin Fu 		    base; base = pci_cfgacc_get8(rcdip, bdf,
1060c0da6274SZhi-Jun Robin Fu 		    base + PCI_CAP_NEXT_PTR)) {
1061c0da6274SZhi-Jun Robin Fu 			capid = pci_cfgacc_get8(rcdip, bdf, base);
1062c0da6274SZhi-Jun Robin Fu 			if (capid == PCI_CAP_ID_PCI_HOTPLUG) {
1063c0da6274SZhi-Jun Robin Fu 				bus_p->bus_pci_hp_off = base;
106426947304SEvan Yan 				bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
1065c0da6274SZhi-Jun Robin Fu 				break;
1066c0da6274SZhi-Jun Robin Fu 			}
1067c0da6274SZhi-Jun Robin Fu 		}
1068d4bc0535SKrishna Elango 	}
1069d4bc0535SKrishna Elango 
1070c0da6274SZhi-Jun Robin Fu 	/* Then, relevant extended capabilities */
1071d4bc0535SKrishna Elango 
1072c0da6274SZhi-Jun Robin Fu 	if (!PCIE_IS_PCIE(bus_p))
1073c0da6274SZhi-Jun Robin Fu 		goto caps_done;
1074c0da6274SZhi-Jun Robin Fu 
1075c0da6274SZhi-Jun Robin Fu 	/* Extended caps: PCIE_EXT_CAP_ID_AER */
1076c0da6274SZhi-Jun Robin Fu 	for (base = PCIE_EXT_CAP; base; base = (capid >>
1077c0da6274SZhi-Jun Robin Fu 	    PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) {
1078c0da6274SZhi-Jun Robin Fu 		capid = pci_cfgacc_get32(rcdip, bdf, base);
1079c0da6274SZhi-Jun Robin Fu 		if (capid == PCI_CAP_EINVAL32)
1080c0da6274SZhi-Jun Robin Fu 			break;
1081c0da6274SZhi-Jun Robin Fu 		if (((capid >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK)
1082c0da6274SZhi-Jun Robin Fu 		    == PCIE_EXT_CAP_ID_AER) {
1083c0da6274SZhi-Jun Robin Fu 			bus_p->bus_aer_off = base;
1084c0da6274SZhi-Jun Robin Fu 			break;
1085c0da6274SZhi-Jun Robin Fu 		}
1086d4bc0535SKrishna Elango 	}
1087d4bc0535SKrishna Elango 
1088c0da6274SZhi-Jun Robin Fu caps_done:
1089d4bc0535SKrishna Elango 	/* save RP dip and RP bdf */
1090d4bc0535SKrishna Elango 	if (PCIE_IS_RP(bus_p)) {
1091c0da6274SZhi-Jun Robin Fu 		bus_p->bus_rp_dip = dip;
1092d4bc0535SKrishna Elango 		bus_p->bus_rp_bdf = bus_p->bus_bdf;
1093d4bc0535SKrishna Elango 	} else {
1094c0da6274SZhi-Jun Robin Fu 		for (pdip = ddi_get_parent(dip); pdip;
1095d4bc0535SKrishna Elango 		    pdip = ddi_get_parent(pdip)) {
1096d4bc0535SKrishna Elango 			pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
1097d4bc0535SKrishna Elango 
1098d4bc0535SKrishna Elango 			/*
1099c0da6274SZhi-Jun Robin Fu 			 * If RP dip and RP bdf in parent's bus_t have
1100c0da6274SZhi-Jun Robin Fu 			 * been initialized, simply use these instead of
1101c0da6274SZhi-Jun Robin Fu 			 * continuing up to the RC.
1102c0da6274SZhi-Jun Robin Fu 			 */
1103c0da6274SZhi-Jun Robin Fu 			if (parent_bus_p->bus_rp_dip != NULL) {
1104c0da6274SZhi-Jun Robin Fu 				bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip;
1105c0da6274SZhi-Jun Robin Fu 				bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf;
1106c0da6274SZhi-Jun Robin Fu 				break;
1107c0da6274SZhi-Jun Robin Fu 			}
1108c0da6274SZhi-Jun Robin Fu 
1109c0da6274SZhi-Jun Robin Fu 			/*
1110d4bc0535SKrishna Elango 			 * When debugging be aware that some NVIDIA x86
1111d4bc0535SKrishna Elango 			 * architectures have 2 nodes for each RP, One at Bus
1112d4bc0535SKrishna Elango 			 * 0x0 and one at Bus 0x80.  The requester is from Bus
1113d4bc0535SKrishna Elango 			 * 0x80
1114d4bc0535SKrishna Elango 			 */
1115d4bc0535SKrishna Elango 			if (PCIE_IS_ROOT(parent_bus_p)) {
1116d4bc0535SKrishna Elango 				bus_p->bus_rp_dip = pdip;
1117d4bc0535SKrishna Elango 				bus_p->bus_rp_bdf = parent_bus_p->bus_bdf;
1118d4bc0535SKrishna Elango 				break;
1119d4bc0535SKrishna Elango 			}
1120d4bc0535SKrishna Elango 		}
1121d4bc0535SKrishna Elango 	}
1122d4bc0535SKrishna Elango 
1123c0da6274SZhi-Jun Robin Fu 	bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
1124c0da6274SZhi-Jun Robin Fu 	bus_p->bus_fm_flags = 0;
1125d4bc0535SKrishna Elango 	bus_p->bus_mps = 0;
1126d4bc0535SKrishna Elango 
1127c0da6274SZhi-Jun Robin Fu 	ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
1128c0da6274SZhi-Jun Robin Fu 
1129c0da6274SZhi-Jun Robin Fu 	if (PCIE_IS_HOTPLUG_CAPABLE(dip))
1130c0da6274SZhi-Jun Robin Fu 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
1131c0da6274SZhi-Jun Robin Fu 		    "hotplug-capable");
1132c0da6274SZhi-Jun Robin Fu 
1133c0da6274SZhi-Jun Robin Fu initial_done:
1134c0da6274SZhi-Jun Robin Fu 	if (!(flags & PCIE_BUS_FINAL))
1135c0da6274SZhi-Jun Robin Fu 		goto final_done;
1136c0da6274SZhi-Jun Robin Fu 
1137c0da6274SZhi-Jun Robin Fu 	/* already initialized? */
1138c0da6274SZhi-Jun Robin Fu 	bus_p = PCIE_DIP2BUS(dip);
1139c0da6274SZhi-Jun Robin Fu 
1140c0da6274SZhi-Jun Robin Fu 	/* Save the Range information if device is a switch/bridge */
1141c0da6274SZhi-Jun Robin Fu 	if (PCIE_IS_BDG(bus_p)) {
1142c0da6274SZhi-Jun Robin Fu 		/* get "bus_range" property */
1143c0da6274SZhi-Jun Robin Fu 		range_size = sizeof (pci_bus_range_t);
1144c0da6274SZhi-Jun Robin Fu 		if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1145c0da6274SZhi-Jun Robin Fu 		    "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
1146c0da6274SZhi-Jun Robin Fu 		    != DDI_PROP_SUCCESS) {
1147c0da6274SZhi-Jun Robin Fu 			errstr = "Cannot find \"bus-range\" property";
1148c0da6274SZhi-Jun Robin Fu 			cmn_err(CE_WARN,
1149c0da6274SZhi-Jun Robin Fu 			    "PCIE init err info failed BDF 0x%x:%s\n",
1150c0da6274SZhi-Jun Robin Fu 			    bus_p->bus_bdf, errstr);
1151c0da6274SZhi-Jun Robin Fu 		}
1152c0da6274SZhi-Jun Robin Fu 
1153c0da6274SZhi-Jun Robin Fu 		/* get secondary bus number */
1154c0da6274SZhi-Jun Robin Fu 		rcdip = pcie_get_rc_dip(dip);
1155c0da6274SZhi-Jun Robin Fu 		ASSERT(rcdip != NULL);
1156c0da6274SZhi-Jun Robin Fu 
1157c0da6274SZhi-Jun Robin Fu 		bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip,
1158c0da6274SZhi-Jun Robin Fu 		    bus_p->bus_bdf, PCI_BCNF_SECBUS);
1159c0da6274SZhi-Jun Robin Fu 
1160c0da6274SZhi-Jun Robin Fu 		/* Get "ranges" property */
1161c0da6274SZhi-Jun Robin Fu 		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1162c0da6274SZhi-Jun Robin Fu 		    "ranges", (caddr_t)&bus_p->bus_addr_ranges,
1163c0da6274SZhi-Jun Robin Fu 		    &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
1164c0da6274SZhi-Jun Robin Fu 			bus_p->bus_addr_entries = 0;
1165c0da6274SZhi-Jun Robin Fu 		bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
1166c0da6274SZhi-Jun Robin Fu 	}
1167c0da6274SZhi-Jun Robin Fu 
1168c0da6274SZhi-Jun Robin Fu 	/* save "assigned-addresses" property array, ignore failues */
1169c0da6274SZhi-Jun Robin Fu 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1170c0da6274SZhi-Jun Robin Fu 	    "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
1171c0da6274SZhi-Jun Robin Fu 	    &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
1172c0da6274SZhi-Jun Robin Fu 		bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
1173c0da6274SZhi-Jun Robin Fu 	else
1174c0da6274SZhi-Jun Robin Fu 		bus_p->bus_assigned_entries = 0;
1175c0da6274SZhi-Jun Robin Fu 
1176c0da6274SZhi-Jun Robin Fu 	pcie_init_pfd(dip);
1177c0da6274SZhi-Jun Robin Fu 
1178c0da6274SZhi-Jun Robin Fu 	pcie_init_plat(dip);
1179c0da6274SZhi-Jun Robin Fu 
1180c0da6274SZhi-Jun Robin Fu final_done:
1181d4bc0535SKrishna Elango 
1182d4bc0535SKrishna Elango 	PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
1183c0da6274SZhi-Jun Robin Fu 	    ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf,
1184d4bc0535SKrishna Elango 	    bus_p->bus_bdg_secbus);
1185d4bc0535SKrishna Elango #ifdef DEBUG
1186d4bc0535SKrishna Elango 	pcie_print_bus(bus_p);
1187d4bc0535SKrishna Elango #endif
1188d4bc0535SKrishna Elango 
1189d4bc0535SKrishna Elango 	return (bus_p);
1190c0da6274SZhi-Jun Robin Fu }
1191c0da6274SZhi-Jun Robin Fu 
1192c0da6274SZhi-Jun Robin Fu /*
1193c0da6274SZhi-Jun Robin Fu  * Invoked before destroying devinfo node, mostly during hotplug
1194c0da6274SZhi-Jun Robin Fu  * operation to free pcie_bus_t data structure
1195c0da6274SZhi-Jun Robin Fu  */
1196c0da6274SZhi-Jun Robin Fu /* ARGSUSED */
1197c0da6274SZhi-Jun Robin Fu void
1198c0da6274SZhi-Jun Robin Fu pcie_fini_bus(dev_info_t *dip, uint8_t flags)
1199c0da6274SZhi-Jun Robin Fu {
1200c0da6274SZhi-Jun Robin Fu 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
1201c0da6274SZhi-Jun Robin Fu 	ASSERT(bus_p);
1202c0da6274SZhi-Jun Robin Fu 
1203c0da6274SZhi-Jun Robin Fu 	if (flags & PCIE_BUS_INITIAL) {
1204c0da6274SZhi-Jun Robin Fu 		pcie_fini_plat(dip);
1205c0da6274SZhi-Jun Robin Fu 		pcie_fini_pfd(dip);
1206c0da6274SZhi-Jun Robin Fu 
1207c0da6274SZhi-Jun Robin Fu 		kmem_free(bus_p->bus_assigned_addr,
1208c0da6274SZhi-Jun Robin Fu 		    (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
1209c0da6274SZhi-Jun Robin Fu 		kmem_free(bus_p->bus_addr_ranges,
1210c0da6274SZhi-Jun Robin Fu 		    (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
1211c0da6274SZhi-Jun Robin Fu 		/* zero out the fields that have been destroyed */
1212c0da6274SZhi-Jun Robin Fu 		bus_p->bus_assigned_addr = NULL;
1213c0da6274SZhi-Jun Robin Fu 		bus_p->bus_addr_ranges = NULL;
1214c0da6274SZhi-Jun Robin Fu 		bus_p->bus_assigned_entries = 0;
1215c0da6274SZhi-Jun Robin Fu 		bus_p->bus_addr_entries = 0;
1216c0da6274SZhi-Jun Robin Fu 	}
1217c0da6274SZhi-Jun Robin Fu 
1218c0da6274SZhi-Jun Robin Fu 	if (flags & PCIE_BUS_FINAL) {
1219c0da6274SZhi-Jun Robin Fu 		if (PCIE_IS_HOTPLUG_CAPABLE(dip)) {
1220c0da6274SZhi-Jun Robin Fu 			(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
1221c0da6274SZhi-Jun Robin Fu 			    "hotplug-capable");
1222c0da6274SZhi-Jun Robin Fu 		}
1223c0da6274SZhi-Jun Robin Fu 
1224c0da6274SZhi-Jun Robin Fu 		ndi_set_bus_private(dip, B_TRUE, NULL, NULL);
1225d4bc0535SKrishna Elango 		kmem_free(bus_p, sizeof (pcie_bus_t));
1226c0da6274SZhi-Jun Robin Fu 	}
1227d4bc0535SKrishna Elango }
1228d4bc0535SKrishna Elango 
1229d4bc0535SKrishna Elango int
1230d4bc0535SKrishna Elango pcie_postattach_child(dev_info_t *cdip)
1231d4bc0535SKrishna Elango {
1232d4bc0535SKrishna Elango 	pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
1233d4bc0535SKrishna Elango 
1234d4bc0535SKrishna Elango 	if (!bus_p)
1235d4bc0535SKrishna Elango 		return (DDI_FAILURE);
1236d4bc0535SKrishna Elango 
1237d4bc0535SKrishna Elango 	return (pcie_enable_ce(cdip));
1238d4bc0535SKrishna Elango }
1239d4bc0535SKrishna Elango 
1240d4bc0535SKrishna Elango /*
1241d4bc0535SKrishna Elango  * PCI-Express child device de-initialization.
1242d4bc0535SKrishna Elango  * This function disables generic pci-express interrupts and error
1243d4bc0535SKrishna Elango  * handling.
1244d4bc0535SKrishna Elango  */
1245d4bc0535SKrishna Elango void
1246d4bc0535SKrishna Elango pcie_uninitchild(dev_info_t *cdip)
1247d4bc0535SKrishna Elango {
1248d4bc0535SKrishna Elango 	pcie_disable_errors(cdip);
1249c0da6274SZhi-Jun Robin Fu 	pcie_fini_cfghdl(cdip);
1250fc256490SJason Beloro 	pcie_fini_dom(cdip);
1251c0da6274SZhi-Jun Robin Fu }
1252c0da6274SZhi-Jun Robin Fu 
1253c0da6274SZhi-Jun Robin Fu /*
1254c0da6274SZhi-Jun Robin Fu  * find the root complex dip
1255c0da6274SZhi-Jun Robin Fu  */
1256c0da6274SZhi-Jun Robin Fu dev_info_t *
1257c0da6274SZhi-Jun Robin Fu pcie_get_rc_dip(dev_info_t *dip)
1258c0da6274SZhi-Jun Robin Fu {
1259c0da6274SZhi-Jun Robin Fu 	dev_info_t *rcdip;
1260c0da6274SZhi-Jun Robin Fu 	pcie_bus_t *rc_bus_p;
1261c0da6274SZhi-Jun Robin Fu 
1262c0da6274SZhi-Jun Robin Fu 	for (rcdip = ddi_get_parent(dip); rcdip;
1263c0da6274SZhi-Jun Robin Fu 	    rcdip = ddi_get_parent(rcdip)) {
1264c0da6274SZhi-Jun Robin Fu 		rc_bus_p = PCIE_DIP2BUS(rcdip);
1265c0da6274SZhi-Jun Robin Fu 		if (rc_bus_p && PCIE_IS_RC(rc_bus_p))
1266c0da6274SZhi-Jun Robin Fu 			break;
1267c0da6274SZhi-Jun Robin Fu 	}
1268c0da6274SZhi-Jun Robin Fu 
1269c0da6274SZhi-Jun Robin Fu 	return (rcdip);
1270c0da6274SZhi-Jun Robin Fu }
1271c0da6274SZhi-Jun Robin Fu 
1272c0da6274SZhi-Jun Robin Fu static boolean_t
1273c0da6274SZhi-Jun Robin Fu pcie_is_pci_device(dev_info_t *dip)
1274c0da6274SZhi-Jun Robin Fu {
1275c0da6274SZhi-Jun Robin Fu 	dev_info_t	*pdip;
1276c0da6274SZhi-Jun Robin Fu 	char		*device_type;
1277c0da6274SZhi-Jun Robin Fu 
1278c0da6274SZhi-Jun Robin Fu 	pdip = ddi_get_parent(dip);
1279c0da6274SZhi-Jun Robin Fu 	ASSERT(pdip);
1280c0da6274SZhi-Jun Robin Fu 
1281c0da6274SZhi-Jun Robin Fu 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
1282c0da6274SZhi-Jun Robin Fu 	    "device_type", &device_type) != DDI_PROP_SUCCESS)
1283c0da6274SZhi-Jun Robin Fu 		return (B_FALSE);
1284c0da6274SZhi-Jun Robin Fu 
1285c0da6274SZhi-Jun Robin Fu 	if (strcmp(device_type, "pciex") != 0 &&
1286c0da6274SZhi-Jun Robin Fu 	    strcmp(device_type, "pci") != 0) {
1287c0da6274SZhi-Jun Robin Fu 		ddi_prop_free(device_type);
1288c0da6274SZhi-Jun Robin Fu 		return (B_FALSE);
1289c0da6274SZhi-Jun Robin Fu 	}
1290c0da6274SZhi-Jun Robin Fu 
1291c0da6274SZhi-Jun Robin Fu 	ddi_prop_free(device_type);
1292c0da6274SZhi-Jun Robin Fu 	return (B_TRUE);
1293c0da6274SZhi-Jun Robin Fu }
1294c0da6274SZhi-Jun Robin Fu 
1295c0da6274SZhi-Jun Robin Fu typedef struct {
1296c0da6274SZhi-Jun Robin Fu 	boolean_t	init;
1297c0da6274SZhi-Jun Robin Fu 	uint8_t		flags;
1298c0da6274SZhi-Jun Robin Fu } pcie_bus_arg_t;
1299c0da6274SZhi-Jun Robin Fu 
1300c0da6274SZhi-Jun Robin Fu /*ARGSUSED*/
1301c0da6274SZhi-Jun Robin Fu static int
1302c0da6274SZhi-Jun Robin Fu pcie_fab_do_init_fini(dev_info_t *dip, void *arg)
1303c0da6274SZhi-Jun Robin Fu {
1304c0da6274SZhi-Jun Robin Fu 	pcie_req_id_t	bdf;
1305c0da6274SZhi-Jun Robin Fu 	pcie_bus_arg_t	*bus_arg = (pcie_bus_arg_t *)arg;
1306c0da6274SZhi-Jun Robin Fu 
1307c0da6274SZhi-Jun Robin Fu 	if (!pcie_is_pci_device(dip))
1308c0da6274SZhi-Jun Robin Fu 		goto out;
1309c0da6274SZhi-Jun Robin Fu 
1310c0da6274SZhi-Jun Robin Fu 	if (bus_arg->init) {
1311c0da6274SZhi-Jun Robin Fu 		if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS)
1312c0da6274SZhi-Jun Robin Fu 			goto out;
1313c0da6274SZhi-Jun Robin Fu 
1314c0da6274SZhi-Jun Robin Fu 		(void) pcie_init_bus(dip, bdf, bus_arg->flags);
1315c0da6274SZhi-Jun Robin Fu 	} else {
1316c0da6274SZhi-Jun Robin Fu 		(void) pcie_fini_bus(dip, bus_arg->flags);
1317c0da6274SZhi-Jun Robin Fu 	}
1318c0da6274SZhi-Jun Robin Fu 
1319c0da6274SZhi-Jun Robin Fu 	return (DDI_WALK_CONTINUE);
1320c0da6274SZhi-Jun Robin Fu 
1321c0da6274SZhi-Jun Robin Fu out:
1322c0da6274SZhi-Jun Robin Fu 	return (DDI_WALK_PRUNECHILD);
1323d4bc0535SKrishna Elango }
1324d4bc0535SKrishna Elango 
1325d4bc0535SKrishna Elango void
1326c0da6274SZhi-Jun Robin Fu pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags)
1327d4bc0535SKrishna Elango {
1328c0da6274SZhi-Jun Robin Fu 	int		circular_count;
1329c0da6274SZhi-Jun Robin Fu 	dev_info_t	*dip = ddi_get_child(rcdip);
1330c0da6274SZhi-Jun Robin Fu 	pcie_bus_arg_t	arg;
1331d4bc0535SKrishna Elango 
1332c0da6274SZhi-Jun Robin Fu 	arg.init = B_TRUE;
1333c0da6274SZhi-Jun Robin Fu 	arg.flags = flags;
1334d4bc0535SKrishna Elango 
1335c0da6274SZhi-Jun Robin Fu 	ndi_devi_enter(rcdip, &circular_count);
1336c0da6274SZhi-Jun Robin Fu 	ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
1337c0da6274SZhi-Jun Robin Fu 	ndi_devi_exit(rcdip, circular_count);
1338c0da6274SZhi-Jun Robin Fu }
133926947304SEvan Yan 
1340c0da6274SZhi-Jun Robin Fu void
1341c0da6274SZhi-Jun Robin Fu pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags)
1342c0da6274SZhi-Jun Robin Fu {
1343c0da6274SZhi-Jun Robin Fu 	int		circular_count;
1344c0da6274SZhi-Jun Robin Fu 	dev_info_t	*dip = ddi_get_child(rcdip);
1345c0da6274SZhi-Jun Robin Fu 	pcie_bus_arg_t	arg;
134626947304SEvan Yan 
1347c0da6274SZhi-Jun Robin Fu 	arg.init = B_FALSE;
1348c0da6274SZhi-Jun Robin Fu 	arg.flags = flags;
1349d4bc0535SKrishna Elango 
1350c0da6274SZhi-Jun Robin Fu 	ndi_devi_enter(rcdip, &circular_count);
1351c0da6274SZhi-Jun Robin Fu 	ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
1352c0da6274SZhi-Jun Robin Fu 	ndi_devi_exit(rcdip, circular_count);
1353d4bc0535SKrishna Elango }
1354d4bc0535SKrishna Elango 
1355d4bc0535SKrishna Elango void
1356d4bc0535SKrishna Elango pcie_enable_errors(dev_info_t *dip)
1357d4bc0535SKrishna Elango {
1358d4bc0535SKrishna Elango 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1359d4bc0535SKrishna Elango 	uint16_t	reg16, tmp16;
1360d4bc0535SKrishna Elango 	uint32_t	reg32, tmp32;
1361d4bc0535SKrishna Elango 
1362d4bc0535SKrishna Elango 	ASSERT(bus_p);
1363d4bc0535SKrishna Elango 
1364d4bc0535SKrishna Elango 	/*
1365d4bc0535SKrishna Elango 	 * Clear any pending errors
1366d4bc0535SKrishna Elango 	 */
1367d4bc0535SKrishna Elango 	pcie_clear_errors(dip);
1368d4bc0535SKrishna Elango 
1369d4bc0535SKrishna Elango 	if (!PCIE_IS_PCIE(bus_p))
1370d4bc0535SKrishna Elango 		return;
1371d4bc0535SKrishna Elango 
1372d4bc0535SKrishna Elango 	/*
1373d4bc0535SKrishna Elango 	 * Enable Baseline Error Handling but leave CE reporting off (poweron
1374d4bc0535SKrishna Elango 	 * default).
1375d4bc0535SKrishna Elango 	 */
1376d4bc0535SKrishna Elango 	if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) !=
1377d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL16) {
1378d4bc0535SKrishna Elango 		tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
1379d4bc0535SKrishna Elango 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
1380d4bc0535SKrishna Elango 		    (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
1381d4bc0535SKrishna Elango 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
1382d4bc0535SKrishna Elango 		    (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN));
1383d4bc0535SKrishna Elango 
1384d4bc0535SKrishna Elango 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
1385d4bc0535SKrishna Elango 		PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
1386d4bc0535SKrishna Elango 	}
1387d4bc0535SKrishna Elango 
1388d4bc0535SKrishna Elango 	/* Enable Root Port Baseline Error Receiving */
1389d4bc0535SKrishna Elango 	if (PCIE_IS_ROOT(bus_p) &&
1390d4bc0535SKrishna Elango 	    (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) !=
1391d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL16) {
1392d4bc0535SKrishna Elango 
1393d4bc0535SKrishna Elango 		tmp16 = pcie_serr_disable_flag ?
1394d4bc0535SKrishna Elango 		    (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) :
1395d4bc0535SKrishna Elango 		    pcie_root_ctrl_default;
1396d4bc0535SKrishna Elango 		PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16);
1397d4bc0535SKrishna Elango 		PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL,
1398d4bc0535SKrishna Elango 		    reg16);
1399d4bc0535SKrishna Elango 	}
1400d4bc0535SKrishna Elango 
1401d4bc0535SKrishna Elango 	/*
1402d4bc0535SKrishna Elango 	 * Enable PCI-Express Advanced Error Handling if Exists
1403d4bc0535SKrishna Elango 	 */
1404d4bc0535SKrishna Elango 	if (!PCIE_HAS_AER(bus_p))
1405d4bc0535SKrishna Elango 		return;
1406d4bc0535SKrishna Elango 
1407d4bc0535SKrishna Elango 	/* Set Uncorrectable Severity */
1408d4bc0535SKrishna Elango 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) !=
1409d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL32) {
1410d4bc0535SKrishna Elango 		tmp32 = pcie_aer_uce_severity;
1411d4bc0535SKrishna Elango 
1412d4bc0535SKrishna Elango 		PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32);
1413d4bc0535SKrishna Elango 		PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV,
1414d4bc0535SKrishna Elango 		    reg32);
1415d4bc0535SKrishna Elango 	}
1416d4bc0535SKrishna Elango 
1417d4bc0535SKrishna Elango 	/* Enable Uncorrectable errors */
1418d4bc0535SKrishna Elango 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) !=
1419d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL32) {
1420d4bc0535SKrishna Elango 		tmp32 = pcie_aer_uce_mask;
1421d4bc0535SKrishna Elango 
1422d4bc0535SKrishna Elango 		PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32);
1423d4bc0535SKrishna Elango 		PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK,
1424d4bc0535SKrishna Elango 		    reg32);
1425d4bc0535SKrishna Elango 	}
1426d4bc0535SKrishna Elango 
1427d4bc0535SKrishna Elango 	/* Enable ECRC generation and checking */
1428d4bc0535SKrishna Elango 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
1429d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL32) {
1430d4bc0535SKrishna Elango 		tmp32 = reg32 | pcie_ecrc_value;
1431d4bc0535SKrishna Elango 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32);
1432d4bc0535SKrishna Elango 		PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32);
1433d4bc0535SKrishna Elango 	}
1434d4bc0535SKrishna Elango 
1435d4bc0535SKrishna Elango 	/* Enable Secondary Uncorrectable errors if this is a bridge */
1436d4bc0535SKrishna Elango 	if (!PCIE_IS_PCIE_BDG(bus_p))
1437d4bc0535SKrishna Elango 		goto root;
1438d4bc0535SKrishna Elango 
1439d4bc0535SKrishna Elango 	/* Set Uncorrectable Severity */
1440d4bc0535SKrishna Elango 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) !=
1441d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL32) {
1442d4bc0535SKrishna Elango 		tmp32 = pcie_aer_suce_severity;
1443d4bc0535SKrishna Elango 
1444d4bc0535SKrishna Elango 		PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32);
1445d4bc0535SKrishna Elango 		PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV,
1446d4bc0535SKrishna Elango 		    reg32);
1447d4bc0535SKrishna Elango 	}
1448d4bc0535SKrishna Elango 
1449d4bc0535SKrishna Elango 	if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) !=
1450d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL32) {
1451d4bc0535SKrishna Elango 		PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask);
1452d4bc0535SKrishna Elango 		PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32,
1453d4bc0535SKrishna Elango 		    PCIE_AER_SUCE_MASK, reg32);
1454d4bc0535SKrishna Elango 	}
1455d4bc0535SKrishna Elango 
1456d4bc0535SKrishna Elango root:
1457d4bc0535SKrishna Elango 	/*
1458d4bc0535SKrishna Elango 	 * Enable Root Control this is a Root device
1459d4bc0535SKrishna Elango 	 */
1460d4bc0535SKrishna Elango 	if (!PCIE_IS_ROOT(bus_p))
1461d4bc0535SKrishna Elango 		return;
1462d4bc0535SKrishna Elango 
1463d4bc0535SKrishna Elango 	if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
1464d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL16) {
1465d4bc0535SKrishna Elango 		PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD,
1466d4bc0535SKrishna Elango 		    pcie_root_error_cmd_default);
1467d4bc0535SKrishna Elango 		PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16,
1468d4bc0535SKrishna Elango 		    PCIE_AER_RE_CMD, reg16);
1469d4bc0535SKrishna Elango 	}
1470d4bc0535SKrishna Elango }
1471d4bc0535SKrishna Elango 
1472d4bc0535SKrishna Elango /*
1473d4bc0535SKrishna Elango  * This function is used for enabling CE reporting and setting the AER CE mask.
1474d4bc0535SKrishna Elango  * When called from outside the pcie module it should always be preceded by
1475d4bc0535SKrishna Elango  * a call to pcie_enable_errors.
1476d4bc0535SKrishna Elango  */
1477d4bc0535SKrishna Elango int
1478d4bc0535SKrishna Elango pcie_enable_ce(dev_info_t *dip)
1479d4bc0535SKrishna Elango {
1480d4bc0535SKrishna Elango 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1481d4bc0535SKrishna Elango 	uint16_t	device_sts, device_ctl;
1482d4bc0535SKrishna Elango 	uint32_t	tmp_pcie_aer_ce_mask;
1483d4bc0535SKrishna Elango 
1484d4bc0535SKrishna Elango 	if (!PCIE_IS_PCIE(bus_p))
1485d4bc0535SKrishna Elango 		return (DDI_SUCCESS);
1486d4bc0535SKrishna Elango 
1487d4bc0535SKrishna Elango 	/*
1488d4bc0535SKrishna Elango 	 * The "pcie_ce_mask" property is used to control both the CE reporting
1489d4bc0535SKrishna Elango 	 * enable field in the device control register and the AER CE mask. We
1490d4bc0535SKrishna Elango 	 * leave CE reporting disabled if pcie_ce_mask is set to -1.
1491d4bc0535SKrishna Elango 	 */
1492d4bc0535SKrishna Elango 
1493d4bc0535SKrishna Elango 	tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
1494d4bc0535SKrishna Elango 	    DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask);
1495d4bc0535SKrishna Elango 
1496d4bc0535SKrishna Elango 	if (tmp_pcie_aer_ce_mask == (uint32_t)-1) {
1497d4bc0535SKrishna Elango 		/*
1498d4bc0535SKrishna Elango 		 * Nothing to do since CE reporting has already been disabled.
1499d4bc0535SKrishna Elango 		 */
1500d4bc0535SKrishna Elango 		return (DDI_SUCCESS);
1501d4bc0535SKrishna Elango 	}
1502d4bc0535SKrishna Elango 
1503d4bc0535SKrishna Elango 	if (PCIE_HAS_AER(bus_p)) {
1504d4bc0535SKrishna Elango 		/* Enable AER CE */
1505d4bc0535SKrishna Elango 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask);
1506d4bc0535SKrishna Elango 		PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK,
1507d4bc0535SKrishna Elango 		    0);
1508d4bc0535SKrishna Elango 
1509d4bc0535SKrishna Elango 		/* Clear any pending AER CE errors */
1510d4bc0535SKrishna Elango 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1);
1511d4bc0535SKrishna Elango 	}
1512d4bc0535SKrishna Elango 
1513d4bc0535SKrishna Elango 	/* clear any pending CE errors */
1514d4bc0535SKrishna Elango 	if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) !=
1515d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL16)
1516d4bc0535SKrishna Elango 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS,
1517d4bc0535SKrishna Elango 		    device_sts & (~PCIE_DEVSTS_CE_DETECTED));
1518d4bc0535SKrishna Elango 
1519d4bc0535SKrishna Elango 	/* Enable CE reporting */
1520d4bc0535SKrishna Elango 	device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
1521d4bc0535SKrishna Elango 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL,
1522d4bc0535SKrishna Elango 	    (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default);
1523d4bc0535SKrishna Elango 	PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl);
1524d4bc0535SKrishna Elango 
1525d4bc0535SKrishna Elango 	return (DDI_SUCCESS);
1526d4bc0535SKrishna Elango }
1527d4bc0535SKrishna Elango 
1528d4bc0535SKrishna Elango /* ARGSUSED */
1529d4bc0535SKrishna Elango void
1530d4bc0535SKrishna Elango pcie_disable_errors(dev_info_t *dip)
1531d4bc0535SKrishna Elango {
1532d4bc0535SKrishna Elango 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1533d4bc0535SKrishna Elango 	uint16_t	device_ctl;
1534d4bc0535SKrishna Elango 	uint32_t	aer_reg;
1535d4bc0535SKrishna Elango 
1536d4bc0535SKrishna Elango 	if (!PCIE_IS_PCIE(bus_p))
1537d4bc0535SKrishna Elango 		return;
1538d4bc0535SKrishna Elango 
1539d4bc0535SKrishna Elango 	/*
1540d4bc0535SKrishna Elango 	 * Disable PCI-Express Baseline Error Handling
1541d4bc0535SKrishna Elango 	 */
1542d4bc0535SKrishna Elango 	device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
1543d4bc0535SKrishna Elango 	device_ctl &= ~PCIE_DEVCTL_ERR_MASK;
1544d4bc0535SKrishna Elango 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl);
1545d4bc0535SKrishna Elango 
1546d4bc0535SKrishna Elango 	/*
1547d4bc0535SKrishna Elango 	 * Disable PCI-Express Advanced Error Handling if Exists
1548d4bc0535SKrishna Elango 	 */
1549d4bc0535SKrishna Elango 	if (!PCIE_HAS_AER(bus_p))
1550d4bc0535SKrishna Elango 		goto root;
1551d4bc0535SKrishna Elango 
1552d4bc0535SKrishna Elango 	/* Disable Uncorrectable errors */
1553d4bc0535SKrishna Elango 	PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS);
1554d4bc0535SKrishna Elango 
1555d4bc0535SKrishna Elango 	/* Disable Correctable errors */
1556d4bc0535SKrishna Elango 	PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS);
1557d4bc0535SKrishna Elango 
1558d4bc0535SKrishna Elango 	/* Disable ECRC generation and checking */
1559d4bc0535SKrishna Elango 	if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
1560d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL32) {
1561d4bc0535SKrishna Elango 		aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA |
1562d4bc0535SKrishna Elango 		    PCIE_AER_CTL_ECRC_CHECK_ENA);
1563d4bc0535SKrishna Elango 
1564d4bc0535SKrishna Elango 		PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg);
1565d4bc0535SKrishna Elango 	}
1566d4bc0535SKrishna Elango 	/*
1567d4bc0535SKrishna Elango 	 * Disable Secondary Uncorrectable errors if this is a bridge
1568d4bc0535SKrishna Elango 	 */
1569d4bc0535SKrishna Elango 	if (!PCIE_IS_PCIE_BDG(bus_p))
1570d4bc0535SKrishna Elango 		goto root;
1571d4bc0535SKrishna Elango 
1572d4bc0535SKrishna Elango 	PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS);
1573d4bc0535SKrishna Elango 
1574d4bc0535SKrishna Elango root:
1575d4bc0535SKrishna Elango 	/*
1576d4bc0535SKrishna Elango 	 * disable Root Control this is a Root device
1577d4bc0535SKrishna Elango 	 */
1578d4bc0535SKrishna Elango 	if (!PCIE_IS_ROOT(bus_p))
1579d4bc0535SKrishna Elango 		return;
1580d4bc0535SKrishna Elango 
1581d4bc0535SKrishna Elango 	if (!pcie_serr_disable_flag) {
1582d4bc0535SKrishna Elango 		device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL);
1583d4bc0535SKrishna Elango 		device_ctl &= ~PCIE_ROOT_SYS_ERR;
1584d4bc0535SKrishna Elango 		PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl);
1585d4bc0535SKrishna Elango 	}
1586d4bc0535SKrishna Elango 
1587d4bc0535SKrishna Elango 	if (!PCIE_HAS_AER(bus_p))
1588d4bc0535SKrishna Elango 		return;
1589d4bc0535SKrishna Elango 
1590d4bc0535SKrishna Elango 	if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
1591d4bc0535SKrishna Elango 	    PCI_CAP_EINVAL16) {
1592d4bc0535SKrishna Elango 		device_ctl &= ~pcie_root_error_cmd_default;
1593d4bc0535SKrishna Elango 		PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl);
1594d4bc0535SKrishna Elango 	}
1595d4bc0535SKrishna Elango }
1596d4bc0535SKrishna Elango 
1597d4bc0535SKrishna Elango /*
1598d4bc0535SKrishna Elango  * Extract bdf from "reg" property.
1599d4bc0535SKrishna Elango  */
1600d4bc0535SKrishna Elango int
1601d4bc0535SKrishna Elango pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf)
1602d4bc0535SKrishna Elango {
1603d4bc0535SKrishna Elango 	pci_regspec_t	*regspec;
1604d4bc0535SKrishna Elango 	int		reglen;
1605d4bc0535SKrishna Elango 
1606d4bc0535SKrishna Elango 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1607d4bc0535SKrishna Elango 	    "reg", (int **)&regspec, (uint_t *)&reglen) != DDI_SUCCESS)
1608d4bc0535SKrishna Elango 		return (DDI_FAILURE);
1609d4bc0535SKrishna Elango 
1610d4bc0535SKrishna Elango 	if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) {
1611d4bc0535SKrishna Elango 		ddi_prop_free(regspec);
1612d4bc0535SKrishna Elango 		return (DDI_FAILURE);
1613d4bc0535SKrishna Elango 	}
1614d4bc0535SKrishna Elango 
1615d4bc0535SKrishna Elango 	/* Get phys_hi from first element.  All have same bdf. */
1616d4bc0535SKrishna Elango 	*bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8;
1617d4bc0535SKrishna Elango 
1618d4bc0535SKrishna Elango 	ddi_prop_free(regspec);
1619d4bc0535SKrishna Elango 	return (DDI_SUCCESS);
1620d4bc0535SKrishna Elango }
1621d4bc0535SKrishna Elango 
1622d4bc0535SKrishna Elango dev_info_t *
1623d4bc0535SKrishna Elango pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip)
1624d4bc0535SKrishna Elango {
1625d4bc0535SKrishna Elango 	dev_info_t *cdip = rdip;
1626d4bc0535SKrishna Elango 
1627d4bc0535SKrishna Elango 	for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip))
1628d4bc0535SKrishna Elango 		;
1629d4bc0535SKrishna Elango 
1630d4bc0535SKrishna Elango 	return (cdip);
1631d4bc0535SKrishna Elango }
1632d4bc0535SKrishna Elango 
1633d4bc0535SKrishna Elango uint32_t
1634d4bc0535SKrishna Elango pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
1635d4bc0535SKrishna Elango {
1636d4bc0535SKrishna Elango 	dev_info_t *cdip;
1637d4bc0535SKrishna Elango 
1638d4bc0535SKrishna Elango 	/*
1639d4bc0535SKrishna Elango 	 * As part of the probing, the PCI fcode interpreter may setup a DMA
1640d4bc0535SKrishna Elango 	 * request if a given card has a fcode on it using dip and rdip of the
164126947304SEvan Yan 	 * hotplug connector i.e, dip and rdip of px/pcieb driver. In this
1642d4bc0535SKrishna Elango 	 * case, return a invalid value for the bdf since we cannot get to the
1643d4bc0535SKrishna Elango 	 * bdf value of the actual device which will be initiating this DMA.
1644d4bc0535SKrishna Elango 	 */
1645d4bc0535SKrishna Elango 	if (rdip == dip)
1646d4bc0535SKrishna Elango 		return (PCIE_INVALID_BDF);
1647d4bc0535SKrishna Elango 
1648d4bc0535SKrishna Elango 	cdip = pcie_get_my_childs_dip(dip, rdip);
1649d4bc0535SKrishna Elango 
1650d4bc0535SKrishna Elango 	/*
1651d4bc0535SKrishna Elango 	 * For a given rdip, return the bdf value of dip's (px or pcieb)
1652d4bc0535SKrishna Elango 	 * immediate child or secondary bus-id if dip is a PCIe2PCI bridge.
1653d4bc0535SKrishna Elango 	 *
1654d4bc0535SKrishna Elango 	 * XXX - For now, return a invalid bdf value for all PCI and PCI-X
1655d4bc0535SKrishna Elango 	 * devices since this needs more work.
1656d4bc0535SKrishna Elango 	 */
1657d4bc0535SKrishna Elango 	return (PCI_GET_PCIE2PCI_SECBUS(cdip) ?
1658d4bc0535SKrishna Elango 	    PCIE_INVALID_BDF : PCI_GET_BDF(cdip));
1659d4bc0535SKrishna Elango }
1660d4bc0535SKrishna Elango 
1661d4bc0535SKrishna Elango uint32_t
1662d4bc0535SKrishna Elango pcie_get_aer_uce_mask() {
1663d4bc0535SKrishna Elango 	return (pcie_aer_uce_mask);
1664d4bc0535SKrishna Elango }
1665d4bc0535SKrishna Elango uint32_t
1666d4bc0535SKrishna Elango pcie_get_aer_ce_mask() {
1667d4bc0535SKrishna Elango 	return (pcie_aer_ce_mask);
1668d4bc0535SKrishna Elango }
1669d4bc0535SKrishna Elango uint32_t
1670d4bc0535SKrishna Elango pcie_get_aer_suce_mask() {
1671d4bc0535SKrishna Elango 	return (pcie_aer_suce_mask);
1672d4bc0535SKrishna Elango }
1673d4bc0535SKrishna Elango uint32_t
1674d4bc0535SKrishna Elango pcie_get_serr_mask() {
1675d4bc0535SKrishna Elango 	return (pcie_serr_disable_flag);
1676d4bc0535SKrishna Elango }
1677d4bc0535SKrishna Elango 
1678d4bc0535SKrishna Elango void
1679d4bc0535SKrishna Elango pcie_set_aer_uce_mask(uint32_t mask) {
1680d4bc0535SKrishna Elango 	pcie_aer_uce_mask = mask;
1681d4bc0535SKrishna Elango 	if (mask & PCIE_AER_UCE_UR)
1682d4bc0535SKrishna Elango 		pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN;
1683d4bc0535SKrishna Elango 	else
1684d4bc0535SKrishna Elango 		pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN;
1685d4bc0535SKrishna Elango 
1686d4bc0535SKrishna Elango 	if (mask & PCIE_AER_UCE_ECRC)
1687d4bc0535SKrishna Elango 		pcie_ecrc_value = 0;
1688d4bc0535SKrishna Elango }
1689d4bc0535SKrishna Elango 
1690d4bc0535SKrishna Elango void
1691d4bc0535SKrishna Elango pcie_set_aer_ce_mask(uint32_t mask) {
1692d4bc0535SKrishna Elango 	pcie_aer_ce_mask = mask;
1693d4bc0535SKrishna Elango }
1694d4bc0535SKrishna Elango void
1695d4bc0535SKrishna Elango pcie_set_aer_suce_mask(uint32_t mask) {
1696d4bc0535SKrishna Elango 	pcie_aer_suce_mask = mask;
1697d4bc0535SKrishna Elango }
1698d4bc0535SKrishna Elango void
1699d4bc0535SKrishna Elango pcie_set_serr_mask(uint32_t mask) {
1700d4bc0535SKrishna Elango 	pcie_serr_disable_flag = mask;
1701d4bc0535SKrishna Elango }
1702d4bc0535SKrishna Elango 
1703d4bc0535SKrishna Elango /*
1704d4bc0535SKrishna Elango  * Is the rdip a child of dip.	Used for checking certain CTLOPS from bubbling
1705d4bc0535SKrishna Elango  * up erronously.  Ex.	ISA ctlops to a PCI-PCI Bridge.
1706d4bc0535SKrishna Elango  */
1707d4bc0535SKrishna Elango boolean_t
1708d4bc0535SKrishna Elango pcie_is_child(dev_info_t *dip, dev_info_t *rdip)
1709d4bc0535SKrishna Elango {
1710d4bc0535SKrishna Elango 	dev_info_t	*cdip = ddi_get_child(dip);
1711d4bc0535SKrishna Elango 	for (; cdip; cdip = ddi_get_next_sibling(cdip))
1712d4bc0535SKrishna Elango 		if (cdip == rdip)
1713d4bc0535SKrishna Elango 			break;
1714d4bc0535SKrishna Elango 	return (cdip != NULL);
1715d4bc0535SKrishna Elango }
1716d4bc0535SKrishna Elango 
1717d4bc0535SKrishna Elango boolean_t
1718d4bc0535SKrishna Elango pcie_is_link_disabled(dev_info_t *dip)
1719d4bc0535SKrishna Elango {
1720d4bc0535SKrishna Elango 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
1721d4bc0535SKrishna Elango 
1722d4bc0535SKrishna Elango 	if (PCIE_IS_PCIE(bus_p)) {
1723d4bc0535SKrishna Elango 		if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) &
1724d4bc0535SKrishna Elango 		    PCIE_LINKCTL_LINK_DISABLE)
1725d4bc0535SKrishna Elango 			return (B_TRUE);
1726d4bc0535SKrishna Elango 	}
1727d4bc0535SKrishna Elango 	return (B_FALSE);
1728d4bc0535SKrishna Elango }
1729d4bc0535SKrishna Elango 
1730d4bc0535SKrishna Elango /*
1731d4bc0535SKrishna Elango  * Initialize the MPS for a root port.
1732d4bc0535SKrishna Elango  *
1733d4bc0535SKrishna Elango  * dip - dip of root port device.
1734d4bc0535SKrishna Elango  */
1735d4bc0535SKrishna Elango void
1736d4bc0535SKrishna Elango pcie_init_root_port_mps(dev_info_t *dip)
1737d4bc0535SKrishna Elango {
1738d4bc0535SKrishna Elango 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1739d4bc0535SKrishna Elango 	int rp_cap, max_supported = pcie_max_mps;
1740d4bc0535SKrishna Elango 
1741d4bc0535SKrishna Elango 	(void) pcie_get_fabric_mps(ddi_get_parent(dip),
1742d4bc0535SKrishna Elango 	    ddi_get_child(dip), &max_supported);
1743d4bc0535SKrishna Elango 
1744d4bc0535SKrishna Elango 	rp_cap = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL,
1745d4bc0535SKrishna Elango 	    bus_p->bus_pcie_off, PCIE_DEVCAP) &
1746d4bc0535SKrishna Elango 	    PCIE_DEVCAP_MAX_PAYLOAD_MASK;
1747d4bc0535SKrishna Elango 
1748d4bc0535SKrishna Elango 	if (rp_cap < max_supported)
1749d4bc0535SKrishna Elango 		max_supported = rp_cap;
1750d4bc0535SKrishna Elango 
1751d4bc0535SKrishna Elango 	bus_p->bus_mps = max_supported;
1752d4bc0535SKrishna Elango 	(void) pcie_initchild_mps(dip);
1753d4bc0535SKrishna Elango }
1754d4bc0535SKrishna Elango 
1755d4bc0535SKrishna Elango /*
1756d4bc0535SKrishna Elango  * Initialize the Maximum Payload Size of a device.
1757d4bc0535SKrishna Elango  *
1758d4bc0535SKrishna Elango  * cdip - dip of device.
1759d4bc0535SKrishna Elango  *
1760d4bc0535SKrishna Elango  * returns - DDI_SUCCESS or DDI_FAILURE
1761d4bc0535SKrishna Elango  */
1762d4bc0535SKrishna Elango int
1763d4bc0535SKrishna Elango pcie_initchild_mps(dev_info_t *cdip)
1764d4bc0535SKrishna Elango {
1765d4bc0535SKrishna Elango 	pcie_bus_t	*bus_p;
1766d4bc0535SKrishna Elango 	dev_info_t	*pdip = ddi_get_parent(cdip);
176726947304SEvan Yan 	uint8_t		dev_type;
1768d4bc0535SKrishna Elango 
1769d4bc0535SKrishna Elango 	bus_p = PCIE_DIP2BUS(cdip);
1770d4bc0535SKrishna Elango 	if (bus_p == NULL) {
1771d4bc0535SKrishna Elango 		PCIE_DBG("%s: BUS not found.\n",
1772d4bc0535SKrishna Elango 		    ddi_driver_name(cdip));
1773d4bc0535SKrishna Elango 		return (DDI_FAILURE);
1774d4bc0535SKrishna Elango 	}
1775d4bc0535SKrishna Elango 
177626947304SEvan Yan 	dev_type = bus_p->bus_dev_type;
177726947304SEvan Yan 
177826947304SEvan Yan 	/*
177926947304SEvan Yan 	 * For ARI Devices, only function zero's MPS needs to be set.
178026947304SEvan Yan 	 */
178126947304SEvan Yan 	if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
178226947304SEvan Yan 	    (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) {
178326947304SEvan Yan 		pcie_req_id_t child_bdf;
178426947304SEvan Yan 
178526947304SEvan Yan 		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
178626947304SEvan Yan 			return (DDI_FAILURE);
178726947304SEvan Yan 		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0)
178826947304SEvan Yan 			return (DDI_SUCCESS);
178926947304SEvan Yan 	}
179026947304SEvan Yan 
17919187c210SAlan Adamson, SD OSSD 	if (PCIE_IS_PCIE(bus_p)) {
17929187c210SAlan Adamson, SD OSSD 		int suggested_mrrs, fabric_mps;
17939187c210SAlan Adamson, SD OSSD 		uint16_t device_mps, device_mps_cap, device_mrrs, dev_ctrl;
1794d4bc0535SKrishna Elango 
17959187c210SAlan Adamson, SD OSSD 		dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
179683e6495bSDaniel Ice 		if ((fabric_mps = (PCIE_IS_RP(bus_p) ? bus_p :
179783e6495bSDaniel Ice 		    PCIE_DIP2BUS(pdip))->bus_mps) < 0) {
179883e6495bSDaniel Ice 			dev_ctrl = (dev_ctrl & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
179983e6495bSDaniel Ice 			    PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
180083e6495bSDaniel Ice 			    (pcie_devctl_default &
180183e6495bSDaniel Ice 			    (PCIE_DEVCTL_MAX_READ_REQ_MASK |
180283e6495bSDaniel Ice 			    PCIE_DEVCTL_MAX_PAYLOAD_MASK));
180383e6495bSDaniel Ice 
180483e6495bSDaniel Ice 			PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl);
180583e6495bSDaniel Ice 			return (DDI_SUCCESS);
180683e6495bSDaniel Ice 		}
18079187c210SAlan Adamson, SD OSSD 
18089187c210SAlan Adamson, SD OSSD 		device_mps_cap = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) &
1809d4bc0535SKrishna Elango 		    PCIE_DEVCAP_MAX_PAYLOAD_MASK;
1810d4bc0535SKrishna Elango 
18119187c210SAlan Adamson, SD OSSD 		device_mrrs = (dev_ctrl & PCIE_DEVCTL_MAX_READ_REQ_MASK) >>
18129187c210SAlan Adamson, SD OSSD 		    PCIE_DEVCTL_MAX_READ_REQ_SHIFT;
18139187c210SAlan Adamson, SD OSSD 
18149187c210SAlan Adamson, SD OSSD 		if (device_mps_cap < fabric_mps)
18159187c210SAlan Adamson, SD OSSD 			device_mrrs = device_mps = device_mps_cap;
18169187c210SAlan Adamson, SD OSSD 		else
18179187c210SAlan Adamson, SD OSSD 			device_mps = (uint16_t)fabric_mps;
18189187c210SAlan Adamson, SD OSSD 
18199187c210SAlan Adamson, SD OSSD 		suggested_mrrs = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY,
18209187c210SAlan Adamson, SD OSSD 		    cdip, DDI_PROP_DONTPASS, "suggested-mrrs", device_mrrs);
18219187c210SAlan Adamson, SD OSSD 
18229187c210SAlan Adamson, SD OSSD 		if ((device_mps == fabric_mps) ||
18239187c210SAlan Adamson, SD OSSD 		    (suggested_mrrs < device_mrrs))
18249187c210SAlan Adamson, SD OSSD 			device_mrrs = (uint16_t)suggested_mrrs;
1825d4bc0535SKrishna Elango 
1826d4bc0535SKrishna Elango 		/*
18279187c210SAlan Adamson, SD OSSD 		 * Replace MPS and MRRS settings.
1828d4bc0535SKrishna Elango 		 */
18299187c210SAlan Adamson, SD OSSD 		dev_ctrl &= ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
18309187c210SAlan Adamson, SD OSSD 		    PCIE_DEVCTL_MAX_PAYLOAD_MASK);
1831d4bc0535SKrishna Elango 
18329187c210SAlan Adamson, SD OSSD 		dev_ctrl |= ((device_mrrs << PCIE_DEVCTL_MAX_READ_REQ_SHIFT) |
18339187c210SAlan Adamson, SD OSSD 		    device_mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT);
1834d4bc0535SKrishna Elango 
1835d4bc0535SKrishna Elango 		PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl);
1836d4bc0535SKrishna Elango 
18379187c210SAlan Adamson, SD OSSD 		bus_p->bus_mps = device_mps;
1838d4bc0535SKrishna Elango 	}
183926947304SEvan Yan 
1840d4bc0535SKrishna Elango 	return (DDI_SUCCESS);
1841d4bc0535SKrishna Elango }
1842d4bc0535SKrishna Elango 
1843d4bc0535SKrishna Elango /*
1844d4bc0535SKrishna Elango  * Scans a device tree/branch for a maximum payload size capabilities.
1845d4bc0535SKrishna Elango  *
1846d4bc0535SKrishna Elango  * rc_dip - dip of Root Complex.
1847d4bc0535SKrishna Elango  * dip - dip of device where scan will begin.
1848d4bc0535SKrishna Elango  * max_supported (IN) - maximum allowable MPS.
1849d4bc0535SKrishna Elango  * max_supported (OUT) - maximum payload size capability of fabric.
1850d4bc0535SKrishna Elango  */
1851d4bc0535SKrishna Elango void
1852d4bc0535SKrishna Elango pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
1853d4bc0535SKrishna Elango {
1854d4bc0535SKrishna Elango 	if (dip == NULL)
1855d4bc0535SKrishna Elango 		return;
1856d4bc0535SKrishna Elango 
1857d4bc0535SKrishna Elango 	/*
1858d4bc0535SKrishna Elango 	 * Perform a fabric scan to obtain Maximum Payload Capabilities
1859d4bc0535SKrishna Elango 	 */
1860d4bc0535SKrishna Elango 	(void) pcie_scan_mps(rc_dip, dip, max_supported);
1861d4bc0535SKrishna Elango 
1862d4bc0535SKrishna Elango 	PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported);
1863d4bc0535SKrishna Elango }
1864d4bc0535SKrishna Elango 
1865d4bc0535SKrishna Elango /*
1866d4bc0535SKrishna Elango  * Scans fabric and determines Maximum Payload Size based on
1867d4bc0535SKrishna Elango  * highest common denominator alogorithm
1868d4bc0535SKrishna Elango  */
1869d4bc0535SKrishna Elango static void
1870d4bc0535SKrishna Elango pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
1871d4bc0535SKrishna Elango {
1872d4bc0535SKrishna Elango 	int circular_count;
1873d4bc0535SKrishna Elango 	pcie_max_supported_t max_pay_load_supported;
1874d4bc0535SKrishna Elango 
1875d4bc0535SKrishna Elango 	max_pay_load_supported.dip = rc_dip;
1876d4bc0535SKrishna Elango 	max_pay_load_supported.highest_common_mps = *max_supported;
1877d4bc0535SKrishna Elango 
1878d4bc0535SKrishna Elango 	ndi_devi_enter(ddi_get_parent(dip), &circular_count);
1879d4bc0535SKrishna Elango 	ddi_walk_devs(dip, pcie_get_max_supported,
1880d4bc0535SKrishna Elango 	    (void *)&max_pay_load_supported);
1881d4bc0535SKrishna Elango 	ndi_devi_exit(ddi_get_parent(dip), circular_count);
188226947304SEvan Yan 
1883d4bc0535SKrishna Elango 	*max_supported = max_pay_load_supported.highest_common_mps;
1884d4bc0535SKrishna Elango }
1885d4bc0535SKrishna Elango 
1886d4bc0535SKrishna Elango /*
1887d4bc0535SKrishna Elango  * Called as part of the Maximum Payload Size scan.
1888d4bc0535SKrishna Elango  */
1889d4bc0535SKrishna Elango static int
1890d4bc0535SKrishna Elango pcie_get_max_supported(dev_info_t *dip, void *arg)
1891d4bc0535SKrishna Elango {
1892d4bc0535SKrishna Elango 	uint32_t max_supported;
1893d4bc0535SKrishna Elango 	uint16_t cap_ptr;
1894d4bc0535SKrishna Elango 	pcie_max_supported_t *current = (pcie_max_supported_t *)arg;
1895d4bc0535SKrishna Elango 	pci_regspec_t *reg;
1896d4bc0535SKrishna Elango 	int rlen;
1897d4bc0535SKrishna Elango 	caddr_t virt;
1898d4bc0535SKrishna Elango 	ddi_acc_handle_t config_handle;
1899d4bc0535SKrishna Elango 
1900d4bc0535SKrishna Elango 	if (ddi_get_child(current->dip) == NULL) {
1901d4bc0535SKrishna Elango 		goto fail1;
1902d4bc0535SKrishna Elango 	}
1903d4bc0535SKrishna Elango 
1904d4bc0535SKrishna Elango 	if (pcie_dev(dip) == DDI_FAILURE) {
1905d4bc0535SKrishna Elango 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  "
1906d4bc0535SKrishna Elango 		    "Not a PCIe dev\n", ddi_driver_name(dip));
1907d4bc0535SKrishna Elango 		goto fail1;
1908d4bc0535SKrishna Elango 	}
1909d4bc0535SKrishna Elango 
19109187c210SAlan Adamson, SD OSSD 	/*
19119187c210SAlan Adamson, SD OSSD 	 * If the suggested-mrrs property exists, then don't include this
19129187c210SAlan Adamson, SD OSSD 	 * device in the MPS capabilities scan.
19139187c210SAlan Adamson, SD OSSD 	 */
19149187c210SAlan Adamson, SD OSSD 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
19159187c210SAlan Adamson, SD OSSD 	    "suggested-mrrs") != 0)
19169187c210SAlan Adamson, SD OSSD 		goto fail1;
19179187c210SAlan Adamson, SD OSSD 
1918d4bc0535SKrishna Elango 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
1919d4bc0535SKrishna Elango 	    (caddr_t)&reg, &rlen) != DDI_PROP_SUCCESS) {
1920d4bc0535SKrishna Elango 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  "
1921d4bc0535SKrishna Elango 		    "Can not read reg\n", ddi_driver_name(dip));
1922d4bc0535SKrishna Elango 		goto fail1;
1923d4bc0535SKrishna Elango 	}
1924d4bc0535SKrishna Elango 
1925d4bc0535SKrishna Elango 	if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt,
1926d4bc0535SKrishna Elango 	    &config_handle) != DDI_SUCCESS) {
1927d4bc0535SKrishna Elango 		PCIE_DBG("MPS: pcie_get_max_supported: %s:  pcie_map_phys "
1928d4bc0535SKrishna Elango 		    "failed\n", ddi_driver_name(dip));
1929d4bc0535SKrishna Elango 		goto fail2;
1930d4bc0535SKrishna Elango 	}
1931d4bc0535SKrishna Elango 
1932d4bc0535SKrishna Elango 	if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
1933d4bc0535SKrishna Elango 	    DDI_FAILURE) {
1934d4bc0535SKrishna Elango 		goto fail3;
1935d4bc0535SKrishna Elango 	}
1936d4bc0535SKrishna Elango 
1937d4bc0535SKrishna Elango 	max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
1938d4bc0535SKrishna Elango 	    PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK;
1939d4bc0535SKrishna Elango 
1940d4bc0535SKrishna Elango 	PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip),
1941d4bc0535SKrishna Elango 	    max_supported);
1942d4bc0535SKrishna Elango 
1943d4bc0535SKrishna Elango 	if (max_supported < current->highest_common_mps)
1944d4bc0535SKrishna Elango 		current->highest_common_mps = max_supported;
1945d4bc0535SKrishna Elango 
1946d4bc0535SKrishna Elango fail3:
1947d4bc0535SKrishna Elango 	pcie_unmap_phys(&config_handle, reg);
1948d4bc0535SKrishna Elango fail2:
1949d4bc0535SKrishna Elango 	kmem_free(reg, rlen);
1950d4bc0535SKrishna Elango fail1:
1951d4bc0535SKrishna Elango 	return (DDI_WALK_CONTINUE);
1952d4bc0535SKrishna Elango }
1953d4bc0535SKrishna Elango 
1954d4bc0535SKrishna Elango /*
1955d4bc0535SKrishna Elango  * Determines if there are any root ports attached to a root complex.
1956d4bc0535SKrishna Elango  *
1957d4bc0535SKrishna Elango  * dip - dip of root complex
1958d4bc0535SKrishna Elango  *
1959d4bc0535SKrishna Elango  * Returns - DDI_SUCCESS if there is at least one root port otherwise
1960d4bc0535SKrishna Elango  *	     DDI_FAILURE.
1961d4bc0535SKrishna Elango  */
1962d4bc0535SKrishna Elango int
1963d4bc0535SKrishna Elango pcie_root_port(dev_info_t *dip)
1964d4bc0535SKrishna Elango {
1965d4bc0535SKrishna Elango 	int port_type;
1966d4bc0535SKrishna Elango 	uint16_t cap_ptr;
1967d4bc0535SKrishna Elango 	ddi_acc_handle_t config_handle;
1968d4bc0535SKrishna Elango 	dev_info_t *cdip = ddi_get_child(dip);
1969d4bc0535SKrishna Elango 
1970d4bc0535SKrishna Elango 	/*
1971d4bc0535SKrishna Elango 	 * Determine if any of the children of the passed in dip
1972d4bc0535SKrishna Elango 	 * are root ports.
1973d4bc0535SKrishna Elango 	 */
1974d4bc0535SKrishna Elango 	for (; cdip; cdip = ddi_get_next_sibling(cdip)) {
1975d4bc0535SKrishna Elango 
1976d4bc0535SKrishna Elango 		if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS)
1977d4bc0535SKrishna Elango 			continue;
1978d4bc0535SKrishna Elango 
1979d4bc0535SKrishna Elango 		if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E,
1980d4bc0535SKrishna Elango 		    &cap_ptr)) == DDI_FAILURE) {
1981d4bc0535SKrishna Elango 			pci_config_teardown(&config_handle);
1982d4bc0535SKrishna Elango 			continue;
1983d4bc0535SKrishna Elango 		}
1984d4bc0535SKrishna Elango 
1985d4bc0535SKrishna Elango 		port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
1986d4bc0535SKrishna Elango 		    PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
1987d4bc0535SKrishna Elango 
1988d4bc0535SKrishna Elango 		pci_config_teardown(&config_handle);
1989d4bc0535SKrishna Elango 
1990d4bc0535SKrishna Elango 		if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT)
1991d4bc0535SKrishna Elango 			return (DDI_SUCCESS);
1992d4bc0535SKrishna Elango 	}
1993d4bc0535SKrishna Elango 
1994d4bc0535SKrishna Elango 	/* No root ports were found */
1995d4bc0535SKrishna Elango 
1996d4bc0535SKrishna Elango 	return (DDI_FAILURE);
1997d4bc0535SKrishna Elango }
1998d4bc0535SKrishna Elango 
1999d4bc0535SKrishna Elango /*
2000d4bc0535SKrishna Elango  * Function that determines if a device a PCIe device.
2001d4bc0535SKrishna Elango  *
2002d4bc0535SKrishna Elango  * dip - dip of device.
2003d4bc0535SKrishna Elango  *
2004d4bc0535SKrishna Elango  * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE.
2005d4bc0535SKrishna Elango  */
2006d4bc0535SKrishna Elango int
2007d4bc0535SKrishna Elango pcie_dev(dev_info_t *dip)
2008d4bc0535SKrishna Elango {
2009d4bc0535SKrishna Elango 	/* get parent device's device_type property */
2010d4bc0535SKrishna Elango 	char *device_type;
2011d4bc0535SKrishna Elango 	int rc = DDI_FAILURE;
2012d4bc0535SKrishna Elango 	dev_info_t *pdip = ddi_get_parent(dip);
2013d4bc0535SKrishna Elango 
2014d4bc0535SKrishna Elango 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
2015d4bc0535SKrishna Elango 	    DDI_PROP_DONTPASS, "device_type", &device_type)
2016d4bc0535SKrishna Elango 	    != DDI_PROP_SUCCESS) {
2017d4bc0535SKrishna Elango 		return (DDI_FAILURE);
2018d4bc0535SKrishna Elango 	}
2019d4bc0535SKrishna Elango 
2020d4bc0535SKrishna Elango 	if (strcmp(device_type, "pciex") == 0)
2021d4bc0535SKrishna Elango 		rc = DDI_SUCCESS;
2022d4bc0535SKrishna Elango 	else
2023d4bc0535SKrishna Elango 		rc = DDI_FAILURE;
2024d4bc0535SKrishna Elango 
2025d4bc0535SKrishna Elango 	ddi_prop_free(device_type);
2026d4bc0535SKrishna Elango 	return (rc);
2027d4bc0535SKrishna Elango }
2028d4bc0535SKrishna Elango 
2029d4bc0535SKrishna Elango /*
2030d4bc0535SKrishna Elango  * Function to map in a device's memory space.
2031d4bc0535SKrishna Elango  */
2032d4bc0535SKrishna Elango static int
2033d4bc0535SKrishna Elango pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
2034d4bc0535SKrishna Elango     caddr_t *addrp, ddi_acc_handle_t *handlep)
2035d4bc0535SKrishna Elango {
2036d4bc0535SKrishna Elango 	ddi_map_req_t mr;
2037d4bc0535SKrishna Elango 	ddi_acc_hdl_t *hp;
2038d4bc0535SKrishna Elango 	int result;
2039d4bc0535SKrishna Elango 	ddi_device_acc_attr_t attr;
2040d4bc0535SKrishna Elango 
2041d4bc0535SKrishna Elango 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2042d4bc0535SKrishna Elango 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
2043d4bc0535SKrishna Elango 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2044d4bc0535SKrishna Elango 	attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
2045d4bc0535SKrishna Elango 
2046d4bc0535SKrishna Elango 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
2047d4bc0535SKrishna Elango 	hp = impl_acc_hdl_get(*handlep);
2048d4bc0535SKrishna Elango 	hp->ah_vers = VERS_ACCHDL;
2049d4bc0535SKrishna Elango 	hp->ah_dip = dip;
2050d4bc0535SKrishna Elango 	hp->ah_rnumber = 0;
2051d4bc0535SKrishna Elango 	hp->ah_offset = 0;
2052d4bc0535SKrishna Elango 	hp->ah_len = 0;
2053d4bc0535SKrishna Elango 	hp->ah_acc = attr;
2054d4bc0535SKrishna Elango 
2055d4bc0535SKrishna Elango 	mr.map_op = DDI_MO_MAP_LOCKED;
2056d4bc0535SKrishna Elango 	mr.map_type = DDI_MT_REGSPEC;
2057d4bc0535SKrishna Elango 	mr.map_obj.rp = (struct regspec *)phys_spec;
2058d4bc0535SKrishna Elango 	mr.map_prot = PROT_READ | PROT_WRITE;
2059d4bc0535SKrishna Elango 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
2060d4bc0535SKrishna Elango 	mr.map_handlep = hp;
2061d4bc0535SKrishna Elango 	mr.map_vers = DDI_MAP_VERSION;
2062d4bc0535SKrishna Elango 
2063d4bc0535SKrishna Elango 	result = ddi_map(dip, &mr, 0, 0, addrp);
2064d4bc0535SKrishna Elango 
2065d4bc0535SKrishna Elango 	if (result != DDI_SUCCESS) {
2066d4bc0535SKrishna Elango 		impl_acc_hdl_free(*handlep);
2067d4bc0535SKrishna Elango 		*handlep = (ddi_acc_handle_t)NULL;
2068d4bc0535SKrishna Elango 	} else {
2069d4bc0535SKrishna Elango 		hp->ah_addr = *addrp;
2070d4bc0535SKrishna Elango 	}
2071d4bc0535SKrishna Elango 
2072d4bc0535SKrishna Elango 	return (result);
2073d4bc0535SKrishna Elango }
2074d4bc0535SKrishna Elango 
2075d4bc0535SKrishna Elango /*
2076d4bc0535SKrishna Elango  * Map out memory that was mapped in with pcie_map_phys();
2077d4bc0535SKrishna Elango  */
2078d4bc0535SKrishna Elango static void
2079d4bc0535SKrishna Elango pcie_unmap_phys(ddi_acc_handle_t *handlep,  pci_regspec_t *ph)
2080d4bc0535SKrishna Elango {
2081d4bc0535SKrishna Elango 	ddi_map_req_t mr;
2082d4bc0535SKrishna Elango 	ddi_acc_hdl_t *hp;
2083d4bc0535SKrishna Elango 
2084d4bc0535SKrishna Elango 	hp = impl_acc_hdl_get(*handlep);
2085d4bc0535SKrishna Elango 	ASSERT(hp);
2086d4bc0535SKrishna Elango 
2087d4bc0535SKrishna Elango 	mr.map_op = DDI_MO_UNMAP;
2088d4bc0535SKrishna Elango 	mr.map_type = DDI_MT_REGSPEC;
2089d4bc0535SKrishna Elango 	mr.map_obj.rp = (struct regspec *)ph;
2090d4bc0535SKrishna Elango 	mr.map_prot = PROT_READ | PROT_WRITE;
2091d4bc0535SKrishna Elango 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
2092d4bc0535SKrishna Elango 	mr.map_handlep = hp;
2093d4bc0535SKrishna Elango 	mr.map_vers = DDI_MAP_VERSION;
2094d4bc0535SKrishna Elango 
2095d4bc0535SKrishna Elango 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
2096d4bc0535SKrishna Elango 	    hp->ah_len, &hp->ah_addr);
2097d4bc0535SKrishna Elango 
2098d4bc0535SKrishna Elango 	impl_acc_hdl_free(*handlep);
2099d4bc0535SKrishna Elango 	*handlep = (ddi_acc_handle_t)NULL;
2100d4bc0535SKrishna Elango }
2101d4bc0535SKrishna Elango 
2102d4bc0535SKrishna Elango void
2103d4bc0535SKrishna Elango pcie_set_rber_fatal(dev_info_t *dip, boolean_t val)
2104d4bc0535SKrishna Elango {
2105d4bc0535SKrishna Elango 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
2106d4bc0535SKrishna Elango 	bus_p->bus_pfd->pe_rber_fatal = val;
2107d4bc0535SKrishna Elango }
2108d4bc0535SKrishna Elango 
2109d4bc0535SKrishna Elango /*
2110d4bc0535SKrishna Elango  * Return parent Root Port's pe_rber_fatal value.
2111d4bc0535SKrishna Elango  */
2112d4bc0535SKrishna Elango boolean_t
2113d4bc0535SKrishna Elango pcie_get_rber_fatal(dev_info_t *dip)
2114d4bc0535SKrishna Elango {
2115d4bc0535SKrishna Elango 	pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
2116d4bc0535SKrishna Elango 	pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip);
2117d4bc0535SKrishna Elango 	return (rp_bus_p->bus_pfd->pe_rber_fatal);
2118d4bc0535SKrishna Elango }
2119d4bc0535SKrishna Elango 
212026947304SEvan Yan int
212126947304SEvan Yan pcie_ari_supported(dev_info_t *dip)
212226947304SEvan Yan {
212326947304SEvan Yan 	uint32_t devcap2;
212426947304SEvan Yan 	uint16_t pciecap;
212526947304SEvan Yan 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
212626947304SEvan Yan 	uint8_t dev_type;
212726947304SEvan Yan 
212826947304SEvan Yan 	PCIE_DBG("pcie_ari_supported: dip=%p\n", dip);
212926947304SEvan Yan 
213026947304SEvan Yan 	if (bus_p == NULL)
213126947304SEvan Yan 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
213226947304SEvan Yan 
213326947304SEvan Yan 	dev_type = bus_p->bus_dev_type;
213426947304SEvan Yan 
213526947304SEvan Yan 	if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) &&
213626947304SEvan Yan 	    (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT))
213726947304SEvan Yan 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
213826947304SEvan Yan 
213926947304SEvan Yan 	if (pcie_disable_ari) {
214026947304SEvan Yan 		PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip);
214126947304SEvan Yan 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
214226947304SEvan Yan 	}
214326947304SEvan Yan 
214426947304SEvan Yan 	pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
214526947304SEvan Yan 
214626947304SEvan Yan 	if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) {
214726947304SEvan Yan 		PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip);
214826947304SEvan Yan 		return (PCIE_ARI_FORW_NOT_SUPPORTED);
214926947304SEvan Yan 	}
215026947304SEvan Yan 
215126947304SEvan Yan 	devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2);
215226947304SEvan Yan 
215326947304SEvan Yan 	PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n",
215426947304SEvan Yan 	    dip, devcap2);
215526947304SEvan Yan 
215626947304SEvan Yan 	if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) {
215726947304SEvan Yan 		PCIE_DBG("pcie_ari_supported: "
215826947304SEvan Yan 		    "dip=%p: ARI Forwarding is supported\n", dip);
215926947304SEvan Yan 		return (PCIE_ARI_FORW_SUPPORTED);
216026947304SEvan Yan 	}
216126947304SEvan Yan 	return (PCIE_ARI_FORW_NOT_SUPPORTED);
216226947304SEvan Yan }
216326947304SEvan Yan 
216426947304SEvan Yan int
216526947304SEvan Yan pcie_ari_enable(dev_info_t *dip)
216626947304SEvan Yan {
216726947304SEvan Yan 	uint16_t devctl2;
216826947304SEvan Yan 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
216926947304SEvan Yan 
217026947304SEvan Yan 	PCIE_DBG("pcie_ari_enable: dip=%p\n", dip);
217126947304SEvan Yan 
217226947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
217326947304SEvan Yan 		return (DDI_FAILURE);
217426947304SEvan Yan 
217526947304SEvan Yan 	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
217626947304SEvan Yan 	devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN;
217726947304SEvan Yan 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
217826947304SEvan Yan 
217926947304SEvan Yan 	PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n",
218026947304SEvan Yan 	    dip, devctl2);
218126947304SEvan Yan 
218226947304SEvan Yan 	return (DDI_SUCCESS);
218326947304SEvan Yan }
218426947304SEvan Yan 
218526947304SEvan Yan int
218626947304SEvan Yan pcie_ari_disable(dev_info_t *dip)
218726947304SEvan Yan {
218826947304SEvan Yan 	uint16_t devctl2;
218926947304SEvan Yan 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
219026947304SEvan Yan 
219126947304SEvan Yan 	PCIE_DBG("pcie_ari_disable: dip=%p\n", dip);
219226947304SEvan Yan 
219326947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
219426947304SEvan Yan 		return (DDI_FAILURE);
219526947304SEvan Yan 
219626947304SEvan Yan 	devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
219726947304SEvan Yan 	devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN;
219826947304SEvan Yan 	PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
219926947304SEvan Yan 
220026947304SEvan Yan 	PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n",
220126947304SEvan Yan 	    dip, devctl2);
220226947304SEvan Yan 
220326947304SEvan Yan 	return (DDI_SUCCESS);
220426947304SEvan Yan }
220526947304SEvan Yan 
220626947304SEvan Yan int
220726947304SEvan Yan pcie_ari_is_enabled(dev_info_t *dip)
220826947304SEvan Yan {
220926947304SEvan Yan 	uint16_t devctl2;
221026947304SEvan Yan 	pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
221126947304SEvan Yan 
221226947304SEvan Yan 	PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip);
221326947304SEvan Yan 
221426947304SEvan Yan 	if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
221526947304SEvan Yan 		return (PCIE_ARI_FORW_DISABLED);
221626947304SEvan Yan 
221726947304SEvan Yan 	devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2);
221826947304SEvan Yan 
221926947304SEvan Yan 	PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n",
222026947304SEvan Yan 	    dip, devctl2);
222126947304SEvan Yan 
222226947304SEvan Yan 	if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) {
222326947304SEvan Yan 		PCIE_DBG("pcie_ari_is_enabled: "
222426947304SEvan Yan 		    "dip=%p: ARI Forwarding is enabled\n", dip);
222526947304SEvan Yan 		return (PCIE_ARI_FORW_ENABLED);
222626947304SEvan Yan 	}
222726947304SEvan Yan 
222826947304SEvan Yan 	return (PCIE_ARI_FORW_DISABLED);
222926947304SEvan Yan }
223026947304SEvan Yan 
223126947304SEvan Yan int
223226947304SEvan Yan pcie_ari_device(dev_info_t *dip)
223326947304SEvan Yan {
223426947304SEvan Yan 	ddi_acc_handle_t handle;
223526947304SEvan Yan 	uint16_t cap_ptr;
223626947304SEvan Yan 
223726947304SEvan Yan 	PCIE_DBG("pcie_ari_device: dip=%p\n", dip);
223826947304SEvan Yan 
223926947304SEvan Yan 	/*
224026947304SEvan Yan 	 * XXX - This function may be called before the bus_p structure
224126947304SEvan Yan 	 * has been populated.  This code can be changed to remove
224226947304SEvan Yan 	 * pci_config_setup()/pci_config_teardown() when the RFE
224326947304SEvan Yan 	 * to populate the bus_p structures early in boot is putback.
224426947304SEvan Yan 	 */
224526947304SEvan Yan 
224626947304SEvan Yan 	/* First make sure it is a PCIe device */
224726947304SEvan Yan 
224826947304SEvan Yan 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
224926947304SEvan Yan 		return (PCIE_NOT_ARI_DEVICE);
225026947304SEvan Yan 
225126947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
225226947304SEvan Yan 	    != DDI_SUCCESS) {
225326947304SEvan Yan 		pci_config_teardown(&handle);
225426947304SEvan Yan 		return (PCIE_NOT_ARI_DEVICE);
225526947304SEvan Yan 	}
225626947304SEvan Yan 
225726947304SEvan Yan 	/* Locate the ARI Capability */
225826947304SEvan Yan 
225926947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI),
226026947304SEvan Yan 	    &cap_ptr)) == DDI_FAILURE) {
226126947304SEvan Yan 		pci_config_teardown(&handle);
226226947304SEvan Yan 		return (PCIE_NOT_ARI_DEVICE);
226326947304SEvan Yan 	}
226426947304SEvan Yan 
226526947304SEvan Yan 	/* ARI Capability was found so it must be a ARI device */
226626947304SEvan Yan 	PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip);
226726947304SEvan Yan 
226826947304SEvan Yan 	pci_config_teardown(&handle);
226926947304SEvan Yan 	return (PCIE_ARI_DEVICE);
227026947304SEvan Yan }
227126947304SEvan Yan 
227226947304SEvan Yan int
227326947304SEvan Yan pcie_ari_get_next_function(dev_info_t *dip, int *func)
227426947304SEvan Yan {
227526947304SEvan Yan 	uint32_t val;
227626947304SEvan Yan 	uint16_t cap_ptr, next_function;
227726947304SEvan Yan 	ddi_acc_handle_t handle;
227826947304SEvan Yan 
227926947304SEvan Yan 	/*
228026947304SEvan Yan 	 * XXX - This function may be called before the bus_p structure
228126947304SEvan Yan 	 * has been populated.  This code can be changed to remove
228226947304SEvan Yan 	 * pci_config_setup()/pci_config_teardown() when the RFE
228326947304SEvan Yan 	 * to populate the bus_p structures early in boot is putback.
228426947304SEvan Yan 	 */
228526947304SEvan Yan 
228626947304SEvan Yan 	if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
228726947304SEvan Yan 		return (DDI_FAILURE);
228826947304SEvan Yan 
228926947304SEvan Yan 	if ((PCI_CAP_LOCATE(handle,
229026947304SEvan Yan 	    PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) {
229126947304SEvan Yan 		pci_config_teardown(&handle);
229226947304SEvan Yan 		return (DDI_FAILURE);
229326947304SEvan Yan 	}
229426947304SEvan Yan 
229526947304SEvan Yan 	val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP);
229626947304SEvan Yan 
229726947304SEvan Yan 	next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) &
229826947304SEvan Yan 	    PCIE_ARI_CAP_NEXT_FUNC_MASK;
229926947304SEvan Yan 
230026947304SEvan Yan 	pci_config_teardown(&handle);
230126947304SEvan Yan 
230226947304SEvan Yan 	*func = next_function;
230326947304SEvan Yan 
230426947304SEvan Yan 	return (DDI_SUCCESS);
230526947304SEvan Yan }
230626947304SEvan Yan 
230726947304SEvan Yan dev_info_t *
230826947304SEvan Yan pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function)
230926947304SEvan Yan {
231026947304SEvan Yan 	pcie_req_id_t child_bdf;
231126947304SEvan Yan 	dev_info_t *cdip;
231226947304SEvan Yan 
231326947304SEvan Yan 	for (cdip = ddi_get_child(dip); cdip;
231426947304SEvan Yan 	    cdip = ddi_get_next_sibling(cdip)) {
231526947304SEvan Yan 
231626947304SEvan Yan 		if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
231726947304SEvan Yan 			return (NULL);
231826947304SEvan Yan 
231926947304SEvan Yan 		if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function)
232026947304SEvan Yan 			return (cdip);
232126947304SEvan Yan 	}
232226947304SEvan Yan 	return (NULL);
232326947304SEvan Yan }
232426947304SEvan Yan 
2325d4bc0535SKrishna Elango #ifdef	DEBUG
2326d4bc0535SKrishna Elango 
2327d4bc0535SKrishna Elango static void
2328d4bc0535SKrishna Elango pcie_print_bus(pcie_bus_t *bus_p)
2329d4bc0535SKrishna Elango {
2330d4bc0535SKrishna Elango 	pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip);
2331d4bc0535SKrishna Elango 	pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags);
2332d4bc0535SKrishna Elango 
2333d4bc0535SKrishna Elango 	pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf);
2334d4bc0535SKrishna Elango 	pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id);
2335d4bc0535SKrishna Elango 	pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id);
2336d4bc0535SKrishna Elango 	pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type);
2337d4bc0535SKrishna Elango 	pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type);
2338d4bc0535SKrishna Elango 	pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus);
2339d4bc0535SKrishna Elango 	pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off);
2340d4bc0535SKrishna Elango 	pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off);
2341d4bc0535SKrishna Elango 	pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off);
2342d4bc0535SKrishna Elango 	pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver);
2343d4bc0535SKrishna Elango }
2344d4bc0535SKrishna Elango 
2345d4bc0535SKrishna Elango /*
2346d4bc0535SKrishna Elango  * For debugging purposes set pcie_dbg_print != 0 to see printf messages
2347d4bc0535SKrishna Elango  * during interrupt.
2348d4bc0535SKrishna Elango  *
2349d4bc0535SKrishna Elango  * When a proper solution is in place this code will disappear.
2350d4bc0535SKrishna Elango  * Potential solutions are:
2351d4bc0535SKrishna Elango  * o circular buffers
2352d4bc0535SKrishna Elango  * o taskq to print at lower pil
2353d4bc0535SKrishna Elango  */
2354d4bc0535SKrishna Elango int pcie_dbg_print = 0;
2355d4bc0535SKrishna Elango void
2356d4bc0535SKrishna Elango pcie_dbg(char *fmt, ...)
2357d4bc0535SKrishna Elango {
2358d4bc0535SKrishna Elango 	va_list ap;
2359d4bc0535SKrishna Elango 
2360d4bc0535SKrishna Elango 	if (!pcie_debug_flags) {
2361d4bc0535SKrishna Elango 		return;
2362d4bc0535SKrishna Elango 	}
2363d4bc0535SKrishna Elango 	va_start(ap, fmt);
2364d4bc0535SKrishna Elango 	if (servicing_interrupt()) {
2365d4bc0535SKrishna Elango 		if (pcie_dbg_print) {
2366d4bc0535SKrishna Elango 			prom_vprintf(fmt, ap);
2367d4bc0535SKrishna Elango 		}
2368d4bc0535SKrishna Elango 	} else {
2369d4bc0535SKrishna Elango 		prom_vprintf(fmt, ap);
2370d4bc0535SKrishna Elango 	}
2371d4bc0535SKrishna Elango 	va_end(ap);
2372d4bc0535SKrishna Elango }
2373d4bc0535SKrishna Elango #endif	/* DEBUG */
2374d4bc0535SKrishna Elango 
2375d4bc0535SKrishna Elango #if defined(__i386) || defined(__amd64)
2376d4bc0535SKrishna Elango static void
2377d4bc0535SKrishna Elango pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range,
2378d4bc0535SKrishna Elango     boolean_t *empty_mem_range)
2379d4bc0535SKrishna Elango {
2380d4bc0535SKrishna Elango 	uint8_t	class, subclass;
2381d4bc0535SKrishna Elango 	uint_t	val;
2382d4bc0535SKrishna Elango 
2383d4bc0535SKrishna Elango 	class = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS);
2384d4bc0535SKrishna Elango 	subclass = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS);
2385d4bc0535SKrishna Elango 
2386d4bc0535SKrishna Elango 	if ((class == PCI_CLASS_BRIDGE) && (subclass == PCI_BRIDGE_PCI)) {
2387d4bc0535SKrishna Elango 		val = (((uint_t)pci_config_get8(cfg_hdl, PCI_BCNF_IO_BASE_LOW) &
2388d4bc0535SKrishna Elango 		    PCI_BCNF_IO_MASK) << 8);
2389d4bc0535SKrishna Elango 		/*
2390d4bc0535SKrishna Elango 		 * Assuming that a zero based io_range[0] implies an
2391d4bc0535SKrishna Elango 		 * invalid I/O range.  Likewise for mem_range[0].
2392d4bc0535SKrishna Elango 		 */
2393d4bc0535SKrishna Elango 		if (val == 0)
2394d4bc0535SKrishna Elango 			*empty_io_range = B_TRUE;
2395d4bc0535SKrishna Elango 		val = (((uint_t)pci_config_get16(cfg_hdl, PCI_BCNF_MEM_BASE) &
2396d4bc0535SKrishna Elango 		    PCI_BCNF_MEM_MASK) << 16);
2397d4bc0535SKrishna Elango 		if (val == 0)
2398d4bc0535SKrishna Elango 			*empty_mem_range = B_TRUE;
2399d4bc0535SKrishna Elango 	}
2400d4bc0535SKrishna Elango }
2401c0da6274SZhi-Jun Robin Fu 
2402d4bc0535SKrishna Elango #endif /* defined(__i386) || defined(__amd64) */
2403