xref: /onnv-gate/usr/src/uts/common/io/pciex/pcieb.c (revision 10187:ad62e2dfbe0c)
1*10187SKrishna.Elango@Sun.COM /*
2*10187SKrishna.Elango@Sun.COM  * CDDL HEADER START
3*10187SKrishna.Elango@Sun.COM  *
4*10187SKrishna.Elango@Sun.COM  * The contents of this file are subject to the terms of the
5*10187SKrishna.Elango@Sun.COM  * Common Development and Distribution License (the "License").
6*10187SKrishna.Elango@Sun.COM  * You may not use this file except in compliance with the License.
7*10187SKrishna.Elango@Sun.COM  *
8*10187SKrishna.Elango@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10187SKrishna.Elango@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10187SKrishna.Elango@Sun.COM  * See the License for the specific language governing permissions
11*10187SKrishna.Elango@Sun.COM  * and limitations under the License.
12*10187SKrishna.Elango@Sun.COM  *
13*10187SKrishna.Elango@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10187SKrishna.Elango@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10187SKrishna.Elango@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10187SKrishna.Elango@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10187SKrishna.Elango@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10187SKrishna.Elango@Sun.COM  *
19*10187SKrishna.Elango@Sun.COM  * CDDL HEADER END
20*10187SKrishna.Elango@Sun.COM  */
21*10187SKrishna.Elango@Sun.COM /*
22*10187SKrishna.Elango@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*10187SKrishna.Elango@Sun.COM  * Use is subject to license terms.
24*10187SKrishna.Elango@Sun.COM  */
25*10187SKrishna.Elango@Sun.COM 
26*10187SKrishna.Elango@Sun.COM /*
27*10187SKrishna.Elango@Sun.COM  * Common x86 and SPARC PCI-E to PCI bus bridge nexus driver
28*10187SKrishna.Elango@Sun.COM  */
29*10187SKrishna.Elango@Sun.COM 
30*10187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h>
31*10187SKrishna.Elango@Sun.COM #include <sys/conf.h>
32*10187SKrishna.Elango@Sun.COM #include <sys/kmem.h>
33*10187SKrishna.Elango@Sun.COM #include <sys/debug.h>
34*10187SKrishna.Elango@Sun.COM #include <sys/modctl.h>
35*10187SKrishna.Elango@Sun.COM #include <sys/autoconf.h>
36*10187SKrishna.Elango@Sun.COM #include <sys/ddi_impldefs.h>
37*10187SKrishna.Elango@Sun.COM #include <sys/pci.h>
38*10187SKrishna.Elango@Sun.COM #include <sys/ddi.h>
39*10187SKrishna.Elango@Sun.COM #include <sys/sunddi.h>
40*10187SKrishna.Elango@Sun.COM #include <sys/sunndi.h>
41*10187SKrishna.Elango@Sun.COM #include <sys/fm/util.h>
42*10187SKrishna.Elango@Sun.COM #include <sys/pcie.h>
43*10187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h>
44*10187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h>
45*10187SKrishna.Elango@Sun.COM #include <sys/hotplug/pci/pcihp.h>
46*10187SKrishna.Elango@Sun.COM #include <sys/hotplug/pci/pciehpc.h>
47*10187SKrishna.Elango@Sun.COM #include <sys/hotplug/pci/pcishpc.h>
48*10187SKrishna.Elango@Sun.COM #include <sys/open.h>
49*10187SKrishna.Elango@Sun.COM #include <sys/stat.h>
50*10187SKrishna.Elango@Sun.COM #include <sys/file.h>
51*10187SKrishna.Elango@Sun.COM #include <sys/promif.h>		/* prom_printf */
52*10187SKrishna.Elango@Sun.COM #include <sys/disp.h>
53*10187SKrishna.Elango@Sun.COM #include <sys/pcie_pwr.h>
54*10187SKrishna.Elango@Sun.COM #include "pcieb.h"
55*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX
56*10187SKrishna.Elango@Sun.COM #include <io/pciex/pcieb_plx.h>
57*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */
58*10187SKrishna.Elango@Sun.COM 
59*10187SKrishna.Elango@Sun.COM /*LINTLIBRARY*/
60*10187SKrishna.Elango@Sun.COM 
61*10187SKrishna.Elango@Sun.COM /* panic flag */
62*10187SKrishna.Elango@Sun.COM int pcieb_die = PF_ERR_FATAL_FLAGS;
63*10187SKrishna.Elango@Sun.COM 
64*10187SKrishna.Elango@Sun.COM /* flag to turn on MSI support */
65*10187SKrishna.Elango@Sun.COM int pcieb_enable_msi = 1;
66*10187SKrishna.Elango@Sun.COM 
67*10187SKrishna.Elango@Sun.COM #if defined(DEBUG)
68*10187SKrishna.Elango@Sun.COM uint_t pcieb_dbg_print = 0;
69*10187SKrishna.Elango@Sun.COM 
70*10187SKrishna.Elango@Sun.COM static char *pcieb_debug_sym [] = {	/* same sequence as pcieb_debug_bit */
71*10187SKrishna.Elango@Sun.COM 	/*  0 */ "attach",
72*10187SKrishna.Elango@Sun.COM 	/*  1 */ "pwr",
73*10187SKrishna.Elango@Sun.COM 	/*  2 */ "intr"
74*10187SKrishna.Elango@Sun.COM };
75*10187SKrishna.Elango@Sun.COM #endif /* DEBUG */
76*10187SKrishna.Elango@Sun.COM 
77*10187SKrishna.Elango@Sun.COM static int pcieb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, off_t,
78*10187SKrishna.Elango@Sun.COM 	off_t, caddr_t *);
79*10187SKrishna.Elango@Sun.COM static int pcieb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
80*10187SKrishna.Elango@Sun.COM 	void *);
81*10187SKrishna.Elango@Sun.COM static int pcieb_fm_init(pcieb_devstate_t *pcieb_p);
82*10187SKrishna.Elango@Sun.COM static void pcieb_fm_fini(pcieb_devstate_t *pcieb_p);
83*10187SKrishna.Elango@Sun.COM static int pcieb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap,
84*10187SKrishna.Elango@Sun.COM     ddi_iblock_cookie_t *ibc_p);
85*10187SKrishna.Elango@Sun.COM static int pcieb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
86*10187SKrishna.Elango@Sun.COM 	ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg,
87*10187SKrishna.Elango@Sun.COM 	ddi_dma_handle_t *handlep);
88*10187SKrishna.Elango@Sun.COM static int pcieb_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
89*10187SKrishna.Elango@Sun.COM 	ddi_dma_handle_t handle, enum ddi_dma_ctlops cmd, off_t *offp,
90*10187SKrishna.Elango@Sun.COM 	size_t *lenp, caddr_t *objp, uint_t cache_flags);
91*10187SKrishna.Elango@Sun.COM static int pcieb_intr_ops(dev_info_t *dip, dev_info_t *rdip,
92*10187SKrishna.Elango@Sun.COM 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
93*10187SKrishna.Elango@Sun.COM 
94*10187SKrishna.Elango@Sun.COM static struct bus_ops pcieb_bus_ops = {
95*10187SKrishna.Elango@Sun.COM 	BUSO_REV,
96*10187SKrishna.Elango@Sun.COM 	pcieb_bus_map,
97*10187SKrishna.Elango@Sun.COM 	0,
98*10187SKrishna.Elango@Sun.COM 	0,
99*10187SKrishna.Elango@Sun.COM 	0,
100*10187SKrishna.Elango@Sun.COM 	i_ddi_map_fault,
101*10187SKrishna.Elango@Sun.COM 	ddi_dma_map,
102*10187SKrishna.Elango@Sun.COM 	pcieb_dma_allochdl,
103*10187SKrishna.Elango@Sun.COM 	ddi_dma_freehdl,
104*10187SKrishna.Elango@Sun.COM 	ddi_dma_bindhdl,
105*10187SKrishna.Elango@Sun.COM 	ddi_dma_unbindhdl,
106*10187SKrishna.Elango@Sun.COM 	ddi_dma_flush,
107*10187SKrishna.Elango@Sun.COM 	ddi_dma_win,
108*10187SKrishna.Elango@Sun.COM 	pcieb_dma_mctl,
109*10187SKrishna.Elango@Sun.COM 	pcieb_ctlops,
110*10187SKrishna.Elango@Sun.COM 	ddi_bus_prop_op,
111*10187SKrishna.Elango@Sun.COM 	ndi_busop_get_eventcookie,	/* (*bus_get_eventcookie)();	*/
112*10187SKrishna.Elango@Sun.COM 	ndi_busop_add_eventcall,	/* (*bus_add_eventcall)();	*/
113*10187SKrishna.Elango@Sun.COM 	ndi_busop_remove_eventcall,	/* (*bus_remove_eventcall)();	*/
114*10187SKrishna.Elango@Sun.COM 	ndi_post_event,			/* (*bus_post_event)();		*/
115*10187SKrishna.Elango@Sun.COM 	NULL,				/* (*bus_intr_ctl)();		*/
116*10187SKrishna.Elango@Sun.COM 	NULL,				/* (*bus_config)(); 		*/
117*10187SKrishna.Elango@Sun.COM 	NULL,				/* (*bus_unconfig)(); 		*/
118*10187SKrishna.Elango@Sun.COM 	pcieb_fm_init_child,		/* (*bus_fm_init)(); 		*/
119*10187SKrishna.Elango@Sun.COM 	NULL,				/* (*bus_fm_fini)(); 		*/
120*10187SKrishna.Elango@Sun.COM 	i_ndi_busop_access_enter,	/* (*bus_fm_access_enter)(); 	*/
121*10187SKrishna.Elango@Sun.COM 	i_ndi_busop_access_exit,	/* (*bus_fm_access_exit)(); 	*/
122*10187SKrishna.Elango@Sun.COM 	pcie_bus_power,			/* (*bus_power)(); 	*/
123*10187SKrishna.Elango@Sun.COM 	pcieb_intr_ops			/* (*bus_intr_op)(); 		*/
124*10187SKrishna.Elango@Sun.COM };
125*10187SKrishna.Elango@Sun.COM 
126*10187SKrishna.Elango@Sun.COM static int	pcieb_open(dev_t *, int, int, cred_t *);
127*10187SKrishna.Elango@Sun.COM static int	pcieb_close(dev_t, int, int, cred_t *);
128*10187SKrishna.Elango@Sun.COM static int	pcieb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
129*10187SKrishna.Elango@Sun.COM static int	pcieb_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
130*10187SKrishna.Elango@Sun.COM 		    caddr_t, int *);
131*10187SKrishna.Elango@Sun.COM static int	pcieb_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
132*10187SKrishna.Elango@Sun.COM static uint_t 	pcieb_intr_handler(caddr_t arg1, caddr_t arg2);
133*10187SKrishna.Elango@Sun.COM 
134*10187SKrishna.Elango@Sun.COM /* PM related functions */
135*10187SKrishna.Elango@Sun.COM static int	pcieb_pwr_setup(dev_info_t *dip);
136*10187SKrishna.Elango@Sun.COM static int	pcieb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p);
137*10187SKrishna.Elango@Sun.COM static void	pcieb_pwr_teardown(dev_info_t *dip);
138*10187SKrishna.Elango@Sun.COM static int	pcieb_pwr_disable(dev_info_t *dip);
139*10187SKrishna.Elango@Sun.COM 
140*10187SKrishna.Elango@Sun.COM /* Hotplug related functions */
141*10187SKrishna.Elango@Sun.COM static int pcieb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle);
142*10187SKrishna.Elango@Sun.COM static int pcieb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle);
143*10187SKrishna.Elango@Sun.COM static int pcieb_init_hotplug(pcieb_devstate_t *pcieb);
144*10187SKrishna.Elango@Sun.COM static void pcieb_id_props(pcieb_devstate_t *pcieb);
145*10187SKrishna.Elango@Sun.COM 
146*10187SKrishna.Elango@Sun.COM /*
147*10187SKrishna.Elango@Sun.COM  * soft state pointer
148*10187SKrishna.Elango@Sun.COM  */
149*10187SKrishna.Elango@Sun.COM void *pcieb_state;
150*10187SKrishna.Elango@Sun.COM 
151*10187SKrishna.Elango@Sun.COM static struct cb_ops pcieb_cb_ops = {
152*10187SKrishna.Elango@Sun.COM 	pcieb_open,			/* open */
153*10187SKrishna.Elango@Sun.COM 	pcieb_close,			/* close */
154*10187SKrishna.Elango@Sun.COM 	nodev,				/* strategy */
155*10187SKrishna.Elango@Sun.COM 	nodev,				/* print */
156*10187SKrishna.Elango@Sun.COM 	nodev,				/* dump */
157*10187SKrishna.Elango@Sun.COM 	nodev,				/* read */
158*10187SKrishna.Elango@Sun.COM 	nodev,				/* write */
159*10187SKrishna.Elango@Sun.COM 	pcieb_ioctl,			/* ioctl */
160*10187SKrishna.Elango@Sun.COM 	nodev,				/* devmap */
161*10187SKrishna.Elango@Sun.COM 	nodev,				/* mmap */
162*10187SKrishna.Elango@Sun.COM 	nodev,				/* segmap */
163*10187SKrishna.Elango@Sun.COM 	nochpoll,			/* poll */
164*10187SKrishna.Elango@Sun.COM 	pcieb_prop_op,			/* cb_prop_op */
165*10187SKrishna.Elango@Sun.COM 	NULL,				/* streamtab */
166*10187SKrishna.Elango@Sun.COM 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
167*10187SKrishna.Elango@Sun.COM 	CB_REV,				/* rev */
168*10187SKrishna.Elango@Sun.COM 	nodev,				/* int (*cb_aread)() */
169*10187SKrishna.Elango@Sun.COM 	nodev				/* int (*cb_awrite)() */
170*10187SKrishna.Elango@Sun.COM };
171*10187SKrishna.Elango@Sun.COM 
172*10187SKrishna.Elango@Sun.COM static int	pcieb_probe(dev_info_t *);
173*10187SKrishna.Elango@Sun.COM static int	pcieb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
174*10187SKrishna.Elango@Sun.COM static int	pcieb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
175*10187SKrishna.Elango@Sun.COM 
176*10187SKrishna.Elango@Sun.COM static struct dev_ops pcieb_ops = {
177*10187SKrishna.Elango@Sun.COM 	DEVO_REV,		/* devo_rev */
178*10187SKrishna.Elango@Sun.COM 	0,			/* refcnt  */
179*10187SKrishna.Elango@Sun.COM 	pcieb_info,		/* info */
180*10187SKrishna.Elango@Sun.COM 	nulldev,		/* identify */
181*10187SKrishna.Elango@Sun.COM 	pcieb_probe,		/* probe */
182*10187SKrishna.Elango@Sun.COM 	pcieb_attach,		/* attach */
183*10187SKrishna.Elango@Sun.COM 	pcieb_detach,		/* detach */
184*10187SKrishna.Elango@Sun.COM 	nulldev,		/* reset */
185*10187SKrishna.Elango@Sun.COM 	&pcieb_cb_ops,		/* driver operations */
186*10187SKrishna.Elango@Sun.COM 	&pcieb_bus_ops,		/* bus operations */
187*10187SKrishna.Elango@Sun.COM 	pcie_power,		/* power */
188*10187SKrishna.Elango@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
189*10187SKrishna.Elango@Sun.COM };
190*10187SKrishna.Elango@Sun.COM 
191*10187SKrishna.Elango@Sun.COM /*
192*10187SKrishna.Elango@Sun.COM  * Module linkage information for the kernel.
193*10187SKrishna.Elango@Sun.COM  */
194*10187SKrishna.Elango@Sun.COM 
195*10187SKrishna.Elango@Sun.COM static struct modldrv modldrv = {
196*10187SKrishna.Elango@Sun.COM 	&mod_driverops, /* Type of module */
197*10187SKrishna.Elango@Sun.COM 	"PCIe to PCI nexus driver",
198*10187SKrishna.Elango@Sun.COM 	&pcieb_ops,	/* driver ops */
199*10187SKrishna.Elango@Sun.COM };
200*10187SKrishna.Elango@Sun.COM 
201*10187SKrishna.Elango@Sun.COM static struct modlinkage modlinkage = {
202*10187SKrishna.Elango@Sun.COM 	MODREV_1,
203*10187SKrishna.Elango@Sun.COM 	(void *)&modldrv,
204*10187SKrishna.Elango@Sun.COM 	NULL
205*10187SKrishna.Elango@Sun.COM };
206*10187SKrishna.Elango@Sun.COM 
207*10187SKrishna.Elango@Sun.COM /*
208*10187SKrishna.Elango@Sun.COM  * forward function declarations:
209*10187SKrishna.Elango@Sun.COM  */
210*10187SKrishna.Elango@Sun.COM static void	pcieb_uninitchild(dev_info_t *);
211*10187SKrishna.Elango@Sun.COM static int 	pcieb_initchild(dev_info_t *child);
212*10187SKrishna.Elango@Sun.COM static void	pcieb_create_ranges_prop(dev_info_t *, ddi_acc_handle_t);
213*10187SKrishna.Elango@Sun.COM static boolean_t pcieb_is_pcie_device_type(dev_info_t *dip);
214*10187SKrishna.Elango@Sun.COM 
215*10187SKrishna.Elango@Sun.COM /* interrupt related declarations */
216*10187SKrishna.Elango@Sun.COM static int	pcieb_msi_supported(dev_info_t *);
217*10187SKrishna.Elango@Sun.COM static int	pcieb_intr_attach(pcieb_devstate_t *pcieb);
218*10187SKrishna.Elango@Sun.COM static int	pcieb_intr_init(pcieb_devstate_t *pcieb_p, int intr_type);
219*10187SKrishna.Elango@Sun.COM static void	pcieb_intr_fini(pcieb_devstate_t *pcieb_p);
220*10187SKrishna.Elango@Sun.COM 
221*10187SKrishna.Elango@Sun.COM int
222*10187SKrishna.Elango@Sun.COM _init(void)
223*10187SKrishna.Elango@Sun.COM {
224*10187SKrishna.Elango@Sun.COM 	int e;
225*10187SKrishna.Elango@Sun.COM 
226*10187SKrishna.Elango@Sun.COM 	if ((e = ddi_soft_state_init(&pcieb_state, sizeof (pcieb_devstate_t),
227*10187SKrishna.Elango@Sun.COM 	    1)) == 0 && (e = mod_install(&modlinkage)) != 0)
228*10187SKrishna.Elango@Sun.COM 		ddi_soft_state_fini(&pcieb_state);
229*10187SKrishna.Elango@Sun.COM 	return (e);
230*10187SKrishna.Elango@Sun.COM }
231*10187SKrishna.Elango@Sun.COM 
232*10187SKrishna.Elango@Sun.COM int
233*10187SKrishna.Elango@Sun.COM _fini(void)
234*10187SKrishna.Elango@Sun.COM {
235*10187SKrishna.Elango@Sun.COM 	int e;
236*10187SKrishna.Elango@Sun.COM 
237*10187SKrishna.Elango@Sun.COM 	if ((e = mod_remove(&modlinkage)) == 0) {
238*10187SKrishna.Elango@Sun.COM 		ddi_soft_state_fini(&pcieb_state);
239*10187SKrishna.Elango@Sun.COM 	}
240*10187SKrishna.Elango@Sun.COM 	return (e);
241*10187SKrishna.Elango@Sun.COM }
242*10187SKrishna.Elango@Sun.COM 
243*10187SKrishna.Elango@Sun.COM int
244*10187SKrishna.Elango@Sun.COM _info(struct modinfo *modinfop)
245*10187SKrishna.Elango@Sun.COM {
246*10187SKrishna.Elango@Sun.COM 	return (mod_info(&modlinkage, modinfop));
247*10187SKrishna.Elango@Sun.COM }
248*10187SKrishna.Elango@Sun.COM 
249*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
250*10187SKrishna.Elango@Sun.COM static int
251*10187SKrishna.Elango@Sun.COM pcieb_probe(dev_info_t *devi)
252*10187SKrishna.Elango@Sun.COM {
253*10187SKrishna.Elango@Sun.COM 	return (DDI_PROBE_SUCCESS);
254*10187SKrishna.Elango@Sun.COM }
255*10187SKrishna.Elango@Sun.COM 
256*10187SKrishna.Elango@Sun.COM static int
257*10187SKrishna.Elango@Sun.COM pcieb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
258*10187SKrishna.Elango@Sun.COM {
259*10187SKrishna.Elango@Sun.COM 	int			instance;
260*10187SKrishna.Elango@Sun.COM 	char			device_type[8];
261*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t	*pcieb;
262*10187SKrishna.Elango@Sun.COM 	pcie_bus_t		*bus_p = PCIE_DIP2UPBUS(devi);
263*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t	config_handle = bus_p->bus_cfg_hdl;
264*10187SKrishna.Elango@Sun.COM 	uint8_t			dev_type = bus_p->bus_dev_type;
265*10187SKrishna.Elango@Sun.COM 
266*10187SKrishna.Elango@Sun.COM 	switch (cmd) {
267*10187SKrishna.Elango@Sun.COM 	case DDI_RESUME:
268*10187SKrishna.Elango@Sun.COM 		(void) pcie_pwr_resume(devi);
269*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
270*10187SKrishna.Elango@Sun.COM 
271*10187SKrishna.Elango@Sun.COM 	default:
272*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
273*10187SKrishna.Elango@Sun.COM 
274*10187SKrishna.Elango@Sun.COM 	case DDI_ATTACH:
275*10187SKrishna.Elango@Sun.COM 		break;
276*10187SKrishna.Elango@Sun.COM 	}
277*10187SKrishna.Elango@Sun.COM 
278*10187SKrishna.Elango@Sun.COM 	if (!(PCIE_IS_BDG(bus_p))) {
279*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_ATTACH, devi, "This is not a switch or"
280*10187SKrishna.Elango@Sun.COM 		" bridge\n");
281*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
282*10187SKrishna.Elango@Sun.COM 	}
283*10187SKrishna.Elango@Sun.COM 
284*10187SKrishna.Elango@Sun.COM 	/*
285*10187SKrishna.Elango@Sun.COM 	 * If PCIE_LINKCTL_LINK_DISABLE bit in the PCIe Config
286*10187SKrishna.Elango@Sun.COM 	 * Space (PCIe Capability Link Control Register) is set,
287*10187SKrishna.Elango@Sun.COM 	 * then do not bind the driver.
288*10187SKrishna.Elango@Sun.COM 	 */
289*10187SKrishna.Elango@Sun.COM 	if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) & PCIE_LINKCTL_LINK_DISABLE)
290*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
291*10187SKrishna.Elango@Sun.COM 
292*10187SKrishna.Elango@Sun.COM 	/*
293*10187SKrishna.Elango@Sun.COM 	 * Allocate and get soft state structure.
294*10187SKrishna.Elango@Sun.COM 	 */
295*10187SKrishna.Elango@Sun.COM 	instance = ddi_get_instance(devi);
296*10187SKrishna.Elango@Sun.COM 	if (ddi_soft_state_zalloc(pcieb_state, instance) != DDI_SUCCESS)
297*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
298*10187SKrishna.Elango@Sun.COM 	pcieb = ddi_get_soft_state(pcieb_state, instance);
299*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_dip = devi;
300*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_soft_state = PCIEB_SOFT_STATE_CLOSED;
301*10187SKrishna.Elango@Sun.COM 
302*10187SKrishna.Elango@Sun.COM 	if ((pcieb_fm_init(pcieb)) != DDI_SUCCESS) {
303*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_ATTACH, devi, "Failed in pcieb_fm_init\n");
304*10187SKrishna.Elango@Sun.COM 		goto fail;
305*10187SKrishna.Elango@Sun.COM 	}
306*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_init_flags |= PCIEB_INIT_FM;
307*10187SKrishna.Elango@Sun.COM 
308*10187SKrishna.Elango@Sun.COM 	mutex_init(&pcieb->pcieb_mutex, NULL, MUTEX_DRIVER, NULL);
309*10187SKrishna.Elango@Sun.COM 	mutex_init(&pcieb->pcieb_err_mutex, NULL, MUTEX_DRIVER,
310*10187SKrishna.Elango@Sun.COM 	    (void *)pcieb->pcieb_fm_ibc);
311*10187SKrishna.Elango@Sun.COM 	mutex_init(&pcieb->pcieb_peek_poke_mutex, NULL, MUTEX_DRIVER,
312*10187SKrishna.Elango@Sun.COM 	    (void *)pcieb->pcieb_fm_ibc);
313*10187SKrishna.Elango@Sun.COM 
314*10187SKrishna.Elango@Sun.COM 	/* create special properties for device identification */
315*10187SKrishna.Elango@Sun.COM 	pcieb_id_props(pcieb);
316*10187SKrishna.Elango@Sun.COM 
317*10187SKrishna.Elango@Sun.COM 	/*
318*10187SKrishna.Elango@Sun.COM 	 * Power management setup. This also makes sure that switch/bridge
319*10187SKrishna.Elango@Sun.COM 	 * is at D0 during attach.
320*10187SKrishna.Elango@Sun.COM 	 */
321*10187SKrishna.Elango@Sun.COM 	if (pwr_common_setup(devi) != DDI_SUCCESS) {
322*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, devi, "pwr_common_setup failed\n");
323*10187SKrishna.Elango@Sun.COM 		goto fail;
324*10187SKrishna.Elango@Sun.COM 	}
325*10187SKrishna.Elango@Sun.COM 
326*10187SKrishna.Elango@Sun.COM 	if (pcieb_pwr_setup(devi) != DDI_SUCCESS) {
327*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, devi, "pxb_pwr_setup failed \n");
328*10187SKrishna.Elango@Sun.COM 		goto fail;
329*10187SKrishna.Elango@Sun.COM 	}
330*10187SKrishna.Elango@Sun.COM 
331*10187SKrishna.Elango@Sun.COM 	/*
332*10187SKrishna.Elango@Sun.COM 	 * Make sure the "device_type" property exists.
333*10187SKrishna.Elango@Sun.COM 	 */
334*10187SKrishna.Elango@Sun.COM 	if (pcieb_is_pcie_device_type(devi))
335*10187SKrishna.Elango@Sun.COM 		(void) strcpy(device_type, "pciex");
336*10187SKrishna.Elango@Sun.COM 	else
337*10187SKrishna.Elango@Sun.COM 		(void) strcpy(device_type, "pci");
338*10187SKrishna.Elango@Sun.COM 
339*10187SKrishna.Elango@Sun.COM 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
340*10187SKrishna.Elango@Sun.COM 	    "device_type", device_type);
341*10187SKrishna.Elango@Sun.COM 
342*10187SKrishna.Elango@Sun.COM 	/*
343*10187SKrishna.Elango@Sun.COM 	 * Check whether the "ranges" property is present.
344*10187SKrishna.Elango@Sun.COM 	 * Otherwise create the ranges property by reading
345*10187SKrishna.Elango@Sun.COM 	 * the configuration registers
346*10187SKrishna.Elango@Sun.COM 	 */
347*10187SKrishna.Elango@Sun.COM 	if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
348*10187SKrishna.Elango@Sun.COM 	    "ranges") == 0) {
349*10187SKrishna.Elango@Sun.COM 		pcieb_create_ranges_prop(devi, config_handle);
350*10187SKrishna.Elango@Sun.COM 	}
351*10187SKrishna.Elango@Sun.COM 
352*10187SKrishna.Elango@Sun.COM 	if (PCIE_IS_PCI_BDG(bus_p))
353*10187SKrishna.Elango@Sun.COM 		pcieb_set_pci_perf_parameters(devi, config_handle);
354*10187SKrishna.Elango@Sun.COM 
355*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX
356*10187SKrishna.Elango@Sun.COM 	pcieb_attach_plx_workarounds(pcieb);
357*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */
358*10187SKrishna.Elango@Sun.COM 
359*10187SKrishna.Elango@Sun.COM 	/* Initialize hotplug */
360*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_hotplug_capable = B_FALSE;
361*10187SKrishna.Elango@Sun.COM 
362*10187SKrishna.Elango@Sun.COM 	if ((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
363*10187SKrishna.Elango@Sun.COM 	    (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
364*10187SKrishna.Elango@Sun.COM 	    (dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ||
365*10187SKrishna.Elango@Sun.COM 	    (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE)) {
366*10187SKrishna.Elango@Sun.COM 		(void) pcieb_init_hotplug(pcieb);
367*10187SKrishna.Elango@Sun.COM 	}
368*10187SKrishna.Elango@Sun.COM 
369*10187SKrishna.Elango@Sun.COM 	/*
370*10187SKrishna.Elango@Sun.COM 	 * Initialize interrupt handlers. Ignore return value.
371*10187SKrishna.Elango@Sun.COM 	 */
372*10187SKrishna.Elango@Sun.COM 	(void) pcieb_intr_attach(pcieb);
373*10187SKrishna.Elango@Sun.COM 
374*10187SKrishna.Elango@Sun.COM 	if (pcieb->pcieb_hotplug_capable == B_FALSE) {
375*10187SKrishna.Elango@Sun.COM 		/*
376*10187SKrishna.Elango@Sun.COM 		 * (for non hotplug bus) this would create ":devctl" minor
377*10187SKrishna.Elango@Sun.COM 		 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
378*10187SKrishna.Elango@Sun.COM 		 * to this bus.
379*10187SKrishna.Elango@Sun.COM 		 */
380*10187SKrishna.Elango@Sun.COM 		if (ddi_create_minor_node(devi, "devctl", S_IFCHR,
381*10187SKrishna.Elango@Sun.COM 		    PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR),
382*10187SKrishna.Elango@Sun.COM 		    DDI_NT_NEXUS, 0) != DDI_SUCCESS)
383*10187SKrishna.Elango@Sun.COM 			goto fail;
384*10187SKrishna.Elango@Sun.COM 	}
385*10187SKrishna.Elango@Sun.COM 
386*10187SKrishna.Elango@Sun.COM 	PCIEB_DEBUG(DBG_ATTACH, devi,
387*10187SKrishna.Elango@Sun.COM 	    "pcieb_attach: this nexus %s hotplug slots\n",
388*10187SKrishna.Elango@Sun.COM 	    pcieb->pcieb_hotplug_capable == B_TRUE ? "has":"has no");
389*10187SKrishna.Elango@Sun.COM 
390*10187SKrishna.Elango@Sun.COM 	/* Do any platform specific workarounds needed at this time */
391*10187SKrishna.Elango@Sun.COM 	pcieb_plat_attach_workaround(devi);
392*10187SKrishna.Elango@Sun.COM 
393*10187SKrishna.Elango@Sun.COM 	/*
394*10187SKrishna.Elango@Sun.COM 	 * If this is a root port, determine and set the max payload size.
395*10187SKrishna.Elango@Sun.COM 	 * Since this will involve scanning the fabric, all error enabling
396*10187SKrishna.Elango@Sun.COM 	 * and sw workarounds should be in place before doing this.
397*10187SKrishna.Elango@Sun.COM 	 */
398*10187SKrishna.Elango@Sun.COM 	if (PCIE_IS_RP(bus_p))
399*10187SKrishna.Elango@Sun.COM 		pcie_init_root_port_mps(devi);
400*10187SKrishna.Elango@Sun.COM 
401*10187SKrishna.Elango@Sun.COM 	ddi_report_dev(devi);
402*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
403*10187SKrishna.Elango@Sun.COM 
404*10187SKrishna.Elango@Sun.COM fail:
405*10187SKrishna.Elango@Sun.COM 	(void) pcieb_detach(devi, DDI_DETACH);
406*10187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
407*10187SKrishna.Elango@Sun.COM }
408*10187SKrishna.Elango@Sun.COM 
409*10187SKrishna.Elango@Sun.COM static int
410*10187SKrishna.Elango@Sun.COM pcieb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
411*10187SKrishna.Elango@Sun.COM {
412*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb;
413*10187SKrishna.Elango@Sun.COM 	int error = DDI_SUCCESS;
414*10187SKrishna.Elango@Sun.COM 
415*10187SKrishna.Elango@Sun.COM 	switch (cmd) {
416*10187SKrishna.Elango@Sun.COM 	case DDI_SUSPEND:
417*10187SKrishna.Elango@Sun.COM 		error = pcie_pwr_suspend(devi);
418*10187SKrishna.Elango@Sun.COM 		return (error);
419*10187SKrishna.Elango@Sun.COM 
420*10187SKrishna.Elango@Sun.COM 	case DDI_DETACH:
421*10187SKrishna.Elango@Sun.COM 		break;
422*10187SKrishna.Elango@Sun.COM 
423*10187SKrishna.Elango@Sun.COM 	default:
424*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
425*10187SKrishna.Elango@Sun.COM 	}
426*10187SKrishna.Elango@Sun.COM 
427*10187SKrishna.Elango@Sun.COM 	pcieb = ddi_get_soft_state(pcieb_state, ddi_get_instance(devi));
428*10187SKrishna.Elango@Sun.COM 
429*10187SKrishna.Elango@Sun.COM 	/* remove interrupt handlers */
430*10187SKrishna.Elango@Sun.COM 	pcieb_intr_fini(pcieb);
431*10187SKrishna.Elango@Sun.COM 
432*10187SKrishna.Elango@Sun.COM 	if (pcieb->pcieb_hotplug_capable == B_TRUE) {
433*10187SKrishna.Elango@Sun.COM 		if (pcihp_uninit(devi) == DDI_FAILURE)
434*10187SKrishna.Elango@Sun.COM 			error = DDI_FAILURE;
435*10187SKrishna.Elango@Sun.COM 
436*10187SKrishna.Elango@Sun.COM 		if (pcieb->pcieb_hpc_type == HPC_PCIE)
437*10187SKrishna.Elango@Sun.COM 			(void) pciehpc_uninit(devi);
438*10187SKrishna.Elango@Sun.COM 		else if (pcieb->pcieb_hpc_type == HPC_SHPC)
439*10187SKrishna.Elango@Sun.COM 			(void) pcishpc_uninit(devi);
440*10187SKrishna.Elango@Sun.COM 	} else {
441*10187SKrishna.Elango@Sun.COM 		ddi_remove_minor_node(devi, "devctl");
442*10187SKrishna.Elango@Sun.COM 	}
443*10187SKrishna.Elango@Sun.COM 
444*10187SKrishna.Elango@Sun.COM 	(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
445*10187SKrishna.Elango@Sun.COM 
446*10187SKrishna.Elango@Sun.COM 	(void) ndi_prop_remove(DDI_DEV_T_NONE, pcieb->pcieb_dip,
447*10187SKrishna.Elango@Sun.COM 	    "pcie_ce_mask");
448*10187SKrishna.Elango@Sun.COM 
449*10187SKrishna.Elango@Sun.COM 	if (pcieb->pcieb_init_flags & PCIEB_INIT_FM)
450*10187SKrishna.Elango@Sun.COM 		pcieb_fm_fini(pcieb);
451*10187SKrishna.Elango@Sun.COM 
452*10187SKrishna.Elango@Sun.COM 	pcieb_pwr_teardown(devi);
453*10187SKrishna.Elango@Sun.COM 	pwr_common_teardown(devi);
454*10187SKrishna.Elango@Sun.COM 
455*10187SKrishna.Elango@Sun.COM 	mutex_destroy(&pcieb->pcieb_peek_poke_mutex);
456*10187SKrishna.Elango@Sun.COM 	mutex_destroy(&pcieb->pcieb_err_mutex);
457*10187SKrishna.Elango@Sun.COM 	mutex_destroy(&pcieb->pcieb_mutex);
458*10187SKrishna.Elango@Sun.COM 
459*10187SKrishna.Elango@Sun.COM 	/*
460*10187SKrishna.Elango@Sun.COM 	 * And finally free the per-pci soft state.
461*10187SKrishna.Elango@Sun.COM 	 */
462*10187SKrishna.Elango@Sun.COM 	ddi_soft_state_free(pcieb_state, ddi_get_instance(devi));
463*10187SKrishna.Elango@Sun.COM 
464*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
465*10187SKrishna.Elango@Sun.COM }
466*10187SKrishna.Elango@Sun.COM 
467*10187SKrishna.Elango@Sun.COM static int
468*10187SKrishna.Elango@Sun.COM pcieb_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
469*10187SKrishna.Elango@Sun.COM     off_t offset, off_t len, caddr_t *vaddrp)
470*10187SKrishna.Elango@Sun.COM {
471*10187SKrishna.Elango@Sun.COM 	dev_info_t *pdip;
472*10187SKrishna.Elango@Sun.COM 
473*10187SKrishna.Elango@Sun.COM 	pdip = (dev_info_t *)DEVI(dip)->devi_parent;
474*10187SKrishna.Elango@Sun.COM 	return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip, rdip, mp,
475*10187SKrishna.Elango@Sun.COM 	    offset, len, vaddrp));
476*10187SKrishna.Elango@Sun.COM }
477*10187SKrishna.Elango@Sun.COM 
478*10187SKrishna.Elango@Sun.COM static int
479*10187SKrishna.Elango@Sun.COM pcieb_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
480*10187SKrishna.Elango@Sun.COM     void *arg, void *result)
481*10187SKrishna.Elango@Sun.COM {
482*10187SKrishna.Elango@Sun.COM 	pci_regspec_t *drv_regp;
483*10187SKrishna.Elango@Sun.COM 	int	reglen;
484*10187SKrishna.Elango@Sun.COM 	int	rn;
485*10187SKrishna.Elango@Sun.COM 	int	totreg;
486*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state,
487*10187SKrishna.Elango@Sun.COM 	    ddi_get_instance(dip));
488*10187SKrishna.Elango@Sun.COM 	struct detachspec *ds;
489*10187SKrishna.Elango@Sun.COM 	struct attachspec *as;
490*10187SKrishna.Elango@Sun.COM 
491*10187SKrishna.Elango@Sun.COM 	switch (ctlop) {
492*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_REPORTDEV:
493*10187SKrishna.Elango@Sun.COM 		if (rdip == (dev_info_t *)0)
494*10187SKrishna.Elango@Sun.COM 			return (DDI_FAILURE);
495*10187SKrishna.Elango@Sun.COM 		cmn_err(CE_CONT, "?PCIE-device: %s@%s, %s%d\n",
496*10187SKrishna.Elango@Sun.COM 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
497*10187SKrishna.Elango@Sun.COM 		    ddi_driver_name(rdip),
498*10187SKrishna.Elango@Sun.COM 		    ddi_get_instance(rdip));
499*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
500*10187SKrishna.Elango@Sun.COM 
501*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_INITCHILD:
502*10187SKrishna.Elango@Sun.COM 		return (pcieb_initchild((dev_info_t *)arg));
503*10187SKrishna.Elango@Sun.COM 
504*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_UNINITCHILD:
505*10187SKrishna.Elango@Sun.COM 		pcieb_uninitchild((dev_info_t *)arg);
506*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
507*10187SKrishna.Elango@Sun.COM 
508*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_SIDDEV:
509*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
510*10187SKrishna.Elango@Sun.COM 
511*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_REGSIZE:
512*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_NREGS:
513*10187SKrishna.Elango@Sun.COM 		if (rdip == (dev_info_t *)0)
514*10187SKrishna.Elango@Sun.COM 			return (DDI_FAILURE);
515*10187SKrishna.Elango@Sun.COM 		break;
516*10187SKrishna.Elango@Sun.COM 
517*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_PEEK:
518*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_POKE:
519*10187SKrishna.Elango@Sun.COM 		return (pcieb_plat_peekpoke(dip, rdip, ctlop, arg, result));
520*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_ATTACH:
521*10187SKrishna.Elango@Sun.COM 		if (!pcie_is_child(dip, rdip))
522*10187SKrishna.Elango@Sun.COM 			return (DDI_SUCCESS);
523*10187SKrishna.Elango@Sun.COM 
524*10187SKrishna.Elango@Sun.COM 		as = (struct attachspec *)arg;
525*10187SKrishna.Elango@Sun.COM 		switch (as->when) {
526*10187SKrishna.Elango@Sun.COM 		case DDI_PRE:
527*10187SKrishna.Elango@Sun.COM 			if (as->cmd == DDI_RESUME) {
528*10187SKrishna.Elango@Sun.COM 				pcie_clear_errors(rdip);
529*10187SKrishna.Elango@Sun.COM 				if (pcieb_plat_ctlops(rdip, ctlop, arg) !=
530*10187SKrishna.Elango@Sun.COM 				    DDI_SUCCESS)
531*10187SKrishna.Elango@Sun.COM 					return (DDI_FAILURE);
532*10187SKrishna.Elango@Sun.COM 			}
533*10187SKrishna.Elango@Sun.COM 
534*10187SKrishna.Elango@Sun.COM 			if (as->cmd == DDI_ATTACH)
535*10187SKrishna.Elango@Sun.COM 				return (pcie_pm_hold(dip));
536*10187SKrishna.Elango@Sun.COM 
537*10187SKrishna.Elango@Sun.COM 			return (DDI_SUCCESS);
538*10187SKrishna.Elango@Sun.COM 
539*10187SKrishna.Elango@Sun.COM 		case DDI_POST:
540*10187SKrishna.Elango@Sun.COM 			if (as->cmd == DDI_ATTACH && as->result != DDI_SUCCESS)
541*10187SKrishna.Elango@Sun.COM 				pcie_pm_release(dip);
542*10187SKrishna.Elango@Sun.COM 
543*10187SKrishna.Elango@Sun.COM 			if (as->result == DDI_SUCCESS) {
544*10187SKrishna.Elango@Sun.COM 				pf_init(rdip, (void *)pcieb->pcieb_fm_ibc,
545*10187SKrishna.Elango@Sun.COM 				    as->cmd);
546*10187SKrishna.Elango@Sun.COM 
547*10187SKrishna.Elango@Sun.COM 				(void) pcieb_plat_ctlops(rdip, ctlop, arg);
548*10187SKrishna.Elango@Sun.COM 			}
549*10187SKrishna.Elango@Sun.COM 
550*10187SKrishna.Elango@Sun.COM 			/*
551*10187SKrishna.Elango@Sun.COM 			 * For empty hotplug-capable slots, we should explicitly
552*10187SKrishna.Elango@Sun.COM 			 * disable the errors, so that we won't panic upon
553*10187SKrishna.Elango@Sun.COM 			 * unsupported hotplug messages.
554*10187SKrishna.Elango@Sun.COM 			 */
555*10187SKrishna.Elango@Sun.COM 			if ((!ddi_prop_exists(DDI_DEV_T_ANY, rdip,
556*10187SKrishna.Elango@Sun.COM 			    DDI_PROP_DONTPASS, "hotplug-capable")) ||
557*10187SKrishna.Elango@Sun.COM 			    ddi_get_child(rdip)) {
558*10187SKrishna.Elango@Sun.COM 				(void) pcie_postattach_child(rdip);
559*10187SKrishna.Elango@Sun.COM 				return (DDI_SUCCESS);
560*10187SKrishna.Elango@Sun.COM 			}
561*10187SKrishna.Elango@Sun.COM 
562*10187SKrishna.Elango@Sun.COM 			pcie_disable_errors(rdip);
563*10187SKrishna.Elango@Sun.COM 
564*10187SKrishna.Elango@Sun.COM 			return (DDI_SUCCESS);
565*10187SKrishna.Elango@Sun.COM 		default:
566*10187SKrishna.Elango@Sun.COM 			break;
567*10187SKrishna.Elango@Sun.COM 		}
568*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
569*10187SKrishna.Elango@Sun.COM 
570*10187SKrishna.Elango@Sun.COM 	case DDI_CTLOPS_DETACH:
571*10187SKrishna.Elango@Sun.COM 		if (!pcie_is_child(dip, rdip))
572*10187SKrishna.Elango@Sun.COM 			return (DDI_SUCCESS);
573*10187SKrishna.Elango@Sun.COM 
574*10187SKrishna.Elango@Sun.COM 		ds = (struct detachspec *)arg;
575*10187SKrishna.Elango@Sun.COM 		switch (ds->when) {
576*10187SKrishna.Elango@Sun.COM 		case DDI_PRE:
577*10187SKrishna.Elango@Sun.COM 			pf_fini(rdip, ds->cmd);
578*10187SKrishna.Elango@Sun.COM 			return (DDI_SUCCESS);
579*10187SKrishna.Elango@Sun.COM 
580*10187SKrishna.Elango@Sun.COM 		case DDI_POST:
581*10187SKrishna.Elango@Sun.COM 			if (pcieb_plat_ctlops(rdip, ctlop, arg) != DDI_SUCCESS)
582*10187SKrishna.Elango@Sun.COM 				return (DDI_FAILURE);
583*10187SKrishna.Elango@Sun.COM 			if (ds->cmd == DDI_DETACH &&
584*10187SKrishna.Elango@Sun.COM 			    ds->result == DDI_SUCCESS) {
585*10187SKrishna.Elango@Sun.COM 				return (pcie_pm_remove_child(dip, rdip));
586*10187SKrishna.Elango@Sun.COM 			}
587*10187SKrishna.Elango@Sun.COM 			return (DDI_SUCCESS);
588*10187SKrishna.Elango@Sun.COM 		default:
589*10187SKrishna.Elango@Sun.COM 			break;
590*10187SKrishna.Elango@Sun.COM 		}
591*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
592*10187SKrishna.Elango@Sun.COM 	default:
593*10187SKrishna.Elango@Sun.COM 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
594*10187SKrishna.Elango@Sun.COM 	}
595*10187SKrishna.Elango@Sun.COM 
596*10187SKrishna.Elango@Sun.COM 	*(int *)result = 0;
597*10187SKrishna.Elango@Sun.COM 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip,
598*10187SKrishna.Elango@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&drv_regp,
599*10187SKrishna.Elango@Sun.COM 	    &reglen) != DDI_SUCCESS)
600*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
601*10187SKrishna.Elango@Sun.COM 
602*10187SKrishna.Elango@Sun.COM 	totreg = reglen / sizeof (pci_regspec_t);
603*10187SKrishna.Elango@Sun.COM 	if (ctlop == DDI_CTLOPS_NREGS)
604*10187SKrishna.Elango@Sun.COM 		*(int *)result = totreg;
605*10187SKrishna.Elango@Sun.COM 	else if (ctlop == DDI_CTLOPS_REGSIZE) {
606*10187SKrishna.Elango@Sun.COM 		rn = *(int *)arg;
607*10187SKrishna.Elango@Sun.COM 		if (rn >= totreg) {
608*10187SKrishna.Elango@Sun.COM 			kmem_free(drv_regp, reglen);
609*10187SKrishna.Elango@Sun.COM 			return (DDI_FAILURE);
610*10187SKrishna.Elango@Sun.COM 		}
611*10187SKrishna.Elango@Sun.COM 
612*10187SKrishna.Elango@Sun.COM 		*(off_t *)result = drv_regp[rn].pci_size_low |
613*10187SKrishna.Elango@Sun.COM 		    ((uint64_t)drv_regp[rn].pci_size_hi << 32);
614*10187SKrishna.Elango@Sun.COM 	}
615*10187SKrishna.Elango@Sun.COM 
616*10187SKrishna.Elango@Sun.COM 	kmem_free(drv_regp, reglen);
617*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
618*10187SKrishna.Elango@Sun.COM }
619*10187SKrishna.Elango@Sun.COM 
620*10187SKrishna.Elango@Sun.COM /*
621*10187SKrishna.Elango@Sun.COM  * name_child
622*10187SKrishna.Elango@Sun.COM  *
623*10187SKrishna.Elango@Sun.COM  * This function is called from init_child to name a node. It is
624*10187SKrishna.Elango@Sun.COM  * also passed as a callback for node merging functions.
625*10187SKrishna.Elango@Sun.COM  *
626*10187SKrishna.Elango@Sun.COM  * return value: DDI_SUCCESS, DDI_FAILURE
627*10187SKrishna.Elango@Sun.COM  */
628*10187SKrishna.Elango@Sun.COM static int
629*10187SKrishna.Elango@Sun.COM pcieb_name_child(dev_info_t *child, char *name, int namelen)
630*10187SKrishna.Elango@Sun.COM {
631*10187SKrishna.Elango@Sun.COM 	pci_regspec_t *pci_rp;
632*10187SKrishna.Elango@Sun.COM 	uint_t slot, func;
633*10187SKrishna.Elango@Sun.COM 	char **unit_addr;
634*10187SKrishna.Elango@Sun.COM 	uint_t n;
635*10187SKrishna.Elango@Sun.COM 
636*10187SKrishna.Elango@Sun.COM 	/*
637*10187SKrishna.Elango@Sun.COM 	 * For .conf nodes, use unit-address property as name
638*10187SKrishna.Elango@Sun.COM 	 */
639*10187SKrishna.Elango@Sun.COM 	if (ndi_dev_is_persistent_node(child) == 0) {
640*10187SKrishna.Elango@Sun.COM 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
641*10187SKrishna.Elango@Sun.COM 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
642*10187SKrishna.Elango@Sun.COM 		    DDI_PROP_SUCCESS) {
643*10187SKrishna.Elango@Sun.COM 			cmn_err(CE_WARN,
644*10187SKrishna.Elango@Sun.COM 			    "cannot find unit-address in %s.conf",
645*10187SKrishna.Elango@Sun.COM 			    ddi_driver_name(child));
646*10187SKrishna.Elango@Sun.COM 			return (DDI_FAILURE);
647*10187SKrishna.Elango@Sun.COM 		}
648*10187SKrishna.Elango@Sun.COM 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
649*10187SKrishna.Elango@Sun.COM 			cmn_err(CE_WARN, "unit-address property in %s.conf"
650*10187SKrishna.Elango@Sun.COM 			    " not well-formed", ddi_driver_name(child));
651*10187SKrishna.Elango@Sun.COM 			ddi_prop_free(unit_addr);
652*10187SKrishna.Elango@Sun.COM 			return (DDI_FAILURE);
653*10187SKrishna.Elango@Sun.COM 		}
654*10187SKrishna.Elango@Sun.COM 		(void) snprintf(name, namelen, "%s", *unit_addr);
655*10187SKrishna.Elango@Sun.COM 		ddi_prop_free(unit_addr);
656*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
657*10187SKrishna.Elango@Sun.COM 	}
658*10187SKrishna.Elango@Sun.COM 
659*10187SKrishna.Elango@Sun.COM 	/*
660*10187SKrishna.Elango@Sun.COM 	 * Get the address portion of the node name based on
661*10187SKrishna.Elango@Sun.COM 	 * the function and device number.
662*10187SKrishna.Elango@Sun.COM 	 */
663*10187SKrishna.Elango@Sun.COM 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
664*10187SKrishna.Elango@Sun.COM 	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
665*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
666*10187SKrishna.Elango@Sun.COM 	}
667*10187SKrishna.Elango@Sun.COM 
668*10187SKrishna.Elango@Sun.COM 	/* copy the device identifications */
669*10187SKrishna.Elango@Sun.COM 	slot = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
670*10187SKrishna.Elango@Sun.COM 	func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi);
671*10187SKrishna.Elango@Sun.COM 
672*10187SKrishna.Elango@Sun.COM 	if (func != 0)
673*10187SKrishna.Elango@Sun.COM 		(void) snprintf(name, namelen, "%x,%x", slot, func);
674*10187SKrishna.Elango@Sun.COM 	else
675*10187SKrishna.Elango@Sun.COM 		(void) snprintf(name, namelen, "%x", slot);
676*10187SKrishna.Elango@Sun.COM 
677*10187SKrishna.Elango@Sun.COM 	ddi_prop_free(pci_rp);
678*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
679*10187SKrishna.Elango@Sun.COM }
680*10187SKrishna.Elango@Sun.COM 
681*10187SKrishna.Elango@Sun.COM static int
682*10187SKrishna.Elango@Sun.COM pcieb_initchild(dev_info_t *child)
683*10187SKrishna.Elango@Sun.COM {
684*10187SKrishna.Elango@Sun.COM 	char name[MAXNAMELEN];
685*10187SKrishna.Elango@Sun.COM 	int result = DDI_FAILURE;
686*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb =
687*10187SKrishna.Elango@Sun.COM 	    (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
688*10187SKrishna.Elango@Sun.COM 	    ddi_get_instance(ddi_get_parent(child)));
689*10187SKrishna.Elango@Sun.COM 
690*10187SKrishna.Elango@Sun.COM 	/*
691*10187SKrishna.Elango@Sun.COM 	 * Name the child
692*10187SKrishna.Elango@Sun.COM 	 */
693*10187SKrishna.Elango@Sun.COM 	if (pcieb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) {
694*10187SKrishna.Elango@Sun.COM 		result = DDI_FAILURE;
695*10187SKrishna.Elango@Sun.COM 		goto done;
696*10187SKrishna.Elango@Sun.COM 	}
697*10187SKrishna.Elango@Sun.COM 	ddi_set_name_addr(child, name);
698*10187SKrishna.Elango@Sun.COM 
699*10187SKrishna.Elango@Sun.COM 	/*
700*10187SKrishna.Elango@Sun.COM 	 * Pseudo nodes indicate a prototype node with per-instance
701*10187SKrishna.Elango@Sun.COM 	 * properties to be merged into the real h/w device node.
702*10187SKrishna.Elango@Sun.COM 	 * The interpretation of the unit-address is DD[,F]
703*10187SKrishna.Elango@Sun.COM 	 * where DD is the device id and F is the function.
704*10187SKrishna.Elango@Sun.COM 	 */
705*10187SKrishna.Elango@Sun.COM 	if (ndi_dev_is_persistent_node(child) == 0) {
706*10187SKrishna.Elango@Sun.COM 		extern int pci_allow_pseudo_children;
707*10187SKrishna.Elango@Sun.COM 
708*10187SKrishna.Elango@Sun.COM 		/*
709*10187SKrishna.Elango@Sun.COM 		 * Try to merge the properties from this prototype
710*10187SKrishna.Elango@Sun.COM 		 * node into real h/w nodes.
711*10187SKrishna.Elango@Sun.COM 		 */
712*10187SKrishna.Elango@Sun.COM 		if (ndi_merge_node(child, pcieb_name_child) != DDI_SUCCESS) {
713*10187SKrishna.Elango@Sun.COM 			/*
714*10187SKrishna.Elango@Sun.COM 			 * Merged ok - return failure to remove the node.
715*10187SKrishna.Elango@Sun.COM 			 */
716*10187SKrishna.Elango@Sun.COM 			ddi_set_name_addr(child, NULL);
717*10187SKrishna.Elango@Sun.COM 			result = DDI_FAILURE;
718*10187SKrishna.Elango@Sun.COM 			goto done;
719*10187SKrishna.Elango@Sun.COM 		}
720*10187SKrishna.Elango@Sun.COM 
721*10187SKrishna.Elango@Sun.COM 		/* workaround for ddivs to run under PCI-E */
722*10187SKrishna.Elango@Sun.COM 		if (pci_allow_pseudo_children) {
723*10187SKrishna.Elango@Sun.COM 			result = DDI_SUCCESS;
724*10187SKrishna.Elango@Sun.COM 			goto done;
725*10187SKrishna.Elango@Sun.COM 		}
726*10187SKrishna.Elango@Sun.COM 
727*10187SKrishna.Elango@Sun.COM 		/*
728*10187SKrishna.Elango@Sun.COM 		 * The child was not merged into a h/w node,
729*10187SKrishna.Elango@Sun.COM 		 * but there's not much we can do with it other
730*10187SKrishna.Elango@Sun.COM 		 * than return failure to cause the node to be removed.
731*10187SKrishna.Elango@Sun.COM 		 */
732*10187SKrishna.Elango@Sun.COM 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
733*10187SKrishna.Elango@Sun.COM 		    ddi_driver_name(child), ddi_get_name_addr(child),
734*10187SKrishna.Elango@Sun.COM 		    ddi_driver_name(child));
735*10187SKrishna.Elango@Sun.COM 		ddi_set_name_addr(child, NULL);
736*10187SKrishna.Elango@Sun.COM 		result = DDI_NOT_WELL_FORMED;
737*10187SKrishna.Elango@Sun.COM 		goto done;
738*10187SKrishna.Elango@Sun.COM 	}
739*10187SKrishna.Elango@Sun.COM 
740*10187SKrishna.Elango@Sun.COM 	/* platform specific initchild */
741*10187SKrishna.Elango@Sun.COM 	pcieb_plat_initchild(child);
742*10187SKrishna.Elango@Sun.COM 
743*10187SKrishna.Elango@Sun.COM 	if (pcie_pm_hold(pcieb->pcieb_dip) != DDI_SUCCESS) {
744*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, pcieb->pcieb_dip,
745*10187SKrishna.Elango@Sun.COM 		    "INITCHILD: px_pm_hold failed\n");
746*10187SKrishna.Elango@Sun.COM 		result = DDI_FAILURE;
747*10187SKrishna.Elango@Sun.COM 		goto done;
748*10187SKrishna.Elango@Sun.COM 	}
749*10187SKrishna.Elango@Sun.COM 	/* Any return from here must call pcie_pm_release */
750*10187SKrishna.Elango@Sun.COM 
751*10187SKrishna.Elango@Sun.COM 	/*
752*10187SKrishna.Elango@Sun.COM 	 * If configuration registers were previously saved by
753*10187SKrishna.Elango@Sun.COM 	 * child (before it entered D3), then let the child do the
754*10187SKrishna.Elango@Sun.COM 	 * restore to set up the config regs as it'll first need to
755*10187SKrishna.Elango@Sun.COM 	 * power the device out of D3.
756*10187SKrishna.Elango@Sun.COM 	 */
757*10187SKrishna.Elango@Sun.COM 	if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
758*10187SKrishna.Elango@Sun.COM 	    "config-regs-saved-by-child") == 1) {
759*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, ddi_get_parent(child),
760*10187SKrishna.Elango@Sun.COM 		    "INITCHILD: config regs to be restored by child"
761*10187SKrishna.Elango@Sun.COM 		    " for %s@%s\n", ddi_node_name(child),
762*10187SKrishna.Elango@Sun.COM 		    ddi_get_name_addr(child));
763*10187SKrishna.Elango@Sun.COM 
764*10187SKrishna.Elango@Sun.COM 		result = DDI_SUCCESS;
765*10187SKrishna.Elango@Sun.COM 		goto cleanup;
766*10187SKrishna.Elango@Sun.COM 	}
767*10187SKrishna.Elango@Sun.COM 
768*10187SKrishna.Elango@Sun.COM 	PCIEB_DEBUG(DBG_PWR, ddi_get_parent(child),
769*10187SKrishna.Elango@Sun.COM 	    "INITCHILD: config regs setup for %s@%s\n",
770*10187SKrishna.Elango@Sun.COM 	    ddi_node_name(child), ddi_get_name_addr(child));
771*10187SKrishna.Elango@Sun.COM 
772*10187SKrishna.Elango@Sun.COM 	if (!pcie_init_bus(child) || pcie_initchild(child) != DDI_SUCCESS) {
773*10187SKrishna.Elango@Sun.COM 		result = DDI_FAILURE;
774*10187SKrishna.Elango@Sun.COM 		goto cleanup;
775*10187SKrishna.Elango@Sun.COM 	}
776*10187SKrishna.Elango@Sun.COM 
777*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX
778*10187SKrishna.Elango@Sun.COM 	if (pcieb_init_plx_workarounds(pcieb, child) == DDI_FAILURE) {
779*10187SKrishna.Elango@Sun.COM 		result = DDI_FAILURE;
780*10187SKrishna.Elango@Sun.COM 		goto cleanup;
781*10187SKrishna.Elango@Sun.COM 	}
782*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */
783*10187SKrishna.Elango@Sun.COM 
784*10187SKrishna.Elango@Sun.COM 	result = DDI_SUCCESS;
785*10187SKrishna.Elango@Sun.COM cleanup:
786*10187SKrishna.Elango@Sun.COM 	pcie_pm_release(pcieb->pcieb_dip);
787*10187SKrishna.Elango@Sun.COM done:
788*10187SKrishna.Elango@Sun.COM 	return (result);
789*10187SKrishna.Elango@Sun.COM }
790*10187SKrishna.Elango@Sun.COM 
791*10187SKrishna.Elango@Sun.COM static void
792*10187SKrishna.Elango@Sun.COM pcieb_uninitchild(dev_info_t *dip)
793*10187SKrishna.Elango@Sun.COM {
794*10187SKrishna.Elango@Sun.COM 
795*10187SKrishna.Elango@Sun.COM 	pcie_uninitchild(dip);
796*10187SKrishna.Elango@Sun.COM 
797*10187SKrishna.Elango@Sun.COM 	pcieb_plat_uninitchild(dip);
798*10187SKrishna.Elango@Sun.COM 
799*10187SKrishna.Elango@Sun.COM 	ddi_set_name_addr(dip, NULL);
800*10187SKrishna.Elango@Sun.COM 
801*10187SKrishna.Elango@Sun.COM 	/*
802*10187SKrishna.Elango@Sun.COM 	 * Strip the node to properly convert it back to prototype form
803*10187SKrishna.Elango@Sun.COM 	 */
804*10187SKrishna.Elango@Sun.COM 	ddi_remove_minor_node(dip, NULL);
805*10187SKrishna.Elango@Sun.COM 
806*10187SKrishna.Elango@Sun.COM 	ddi_prop_remove_all(dip);
807*10187SKrishna.Elango@Sun.COM }
808*10187SKrishna.Elango@Sun.COM 
809*10187SKrishna.Elango@Sun.COM static boolean_t
810*10187SKrishna.Elango@Sun.COM pcieb_is_pcie_device_type(dev_info_t *dip)
811*10187SKrishna.Elango@Sun.COM {
812*10187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
813*10187SKrishna.Elango@Sun.COM 
814*10187SKrishna.Elango@Sun.COM 	if (PCIE_IS_SW(bus_p) || PCIE_IS_RP(bus_p) || PCIE_IS_PCI2PCIE(bus_p))
815*10187SKrishna.Elango@Sun.COM 		return (B_TRUE);
816*10187SKrishna.Elango@Sun.COM 
817*10187SKrishna.Elango@Sun.COM 	return (B_FALSE);
818*10187SKrishna.Elango@Sun.COM }
819*10187SKrishna.Elango@Sun.COM 
820*10187SKrishna.Elango@Sun.COM static int
821*10187SKrishna.Elango@Sun.COM pcieb_intr_attach(pcieb_devstate_t *pcieb)
822*10187SKrishna.Elango@Sun.COM {
823*10187SKrishna.Elango@Sun.COM 	int			intr_types;
824*10187SKrishna.Elango@Sun.COM 	dev_info_t		*dip = pcieb->pcieb_dip;
825*10187SKrishna.Elango@Sun.COM 
826*10187SKrishna.Elango@Sun.COM 	/* Allow platform specific code to do any initialization first */
827*10187SKrishna.Elango@Sun.COM 	pcieb_plat_intr_attach(pcieb);
828*10187SKrishna.Elango@Sun.COM 
829*10187SKrishna.Elango@Sun.COM 	/*
830*10187SKrishna.Elango@Sun.COM 	 * Initialize interrupt handlers.
831*10187SKrishna.Elango@Sun.COM 	 * If both MSI and FIXED are supported, try to attach MSI first.
832*10187SKrishna.Elango@Sun.COM 	 * If MSI fails for any reason, then try FIXED, but only allow one
833*10187SKrishna.Elango@Sun.COM 	 * type to be attached.
834*10187SKrishna.Elango@Sun.COM 	 */
835*10187SKrishna.Elango@Sun.COM 	if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
836*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_supported_types"
837*10187SKrishna.Elango@Sun.COM 		    " failed\n");
838*10187SKrishna.Elango@Sun.COM 		goto FAIL;
839*10187SKrishna.Elango@Sun.COM 	}
840*10187SKrishna.Elango@Sun.COM 
841*10187SKrishna.Elango@Sun.COM 	if ((intr_types & DDI_INTR_TYPE_MSI) &&
842*10187SKrishna.Elango@Sun.COM 	    (pcieb_msi_supported(dip) == DDI_SUCCESS)) {
843*10187SKrishna.Elango@Sun.COM 		if (pcieb_intr_init(pcieb, DDI_INTR_TYPE_MSI) == DDI_SUCCESS)
844*10187SKrishna.Elango@Sun.COM 			intr_types = DDI_INTR_TYPE_MSI;
845*10187SKrishna.Elango@Sun.COM 		else {
846*10187SKrishna.Elango@Sun.COM 			PCIEB_DEBUG(DBG_ATTACH, dip, "Unable to attach MSI"
847*10187SKrishna.Elango@Sun.COM 			    " handler\n");
848*10187SKrishna.Elango@Sun.COM 		}
849*10187SKrishna.Elango@Sun.COM 	}
850*10187SKrishna.Elango@Sun.COM 
851*10187SKrishna.Elango@Sun.COM 	if (intr_types != DDI_INTR_TYPE_MSI) {
852*10187SKrishna.Elango@Sun.COM 		/*
853*10187SKrishna.Elango@Sun.COM 		 * MSIs are not supported or MSI initialization failed. For Root
854*10187SKrishna.Elango@Sun.COM 		 * Ports mark this so error handling might try to fallback to
855*10187SKrishna.Elango@Sun.COM 		 * some other mechanism if available (machinecheck etc.).
856*10187SKrishna.Elango@Sun.COM 		 */
857*10187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(PCIE_DIP2UPBUS(dip)))
858*10187SKrishna.Elango@Sun.COM 			pcieb->pcieb_no_aer_msi = B_TRUE;
859*10187SKrishna.Elango@Sun.COM 	}
860*10187SKrishna.Elango@Sun.COM 
861*10187SKrishna.Elango@Sun.COM 	if (intr_types & DDI_INTR_TYPE_FIXED) {
862*10187SKrishna.Elango@Sun.COM 		if (pcieb_intr_init(pcieb, DDI_INTR_TYPE_FIXED) !=
863*10187SKrishna.Elango@Sun.COM 		    DDI_SUCCESS) {
864*10187SKrishna.Elango@Sun.COM 			PCIEB_DEBUG(DBG_ATTACH, dip,
865*10187SKrishna.Elango@Sun.COM 			    "Unable to attach INTx handler\n");
866*10187SKrishna.Elango@Sun.COM 			goto FAIL;
867*10187SKrishna.Elango@Sun.COM 		}
868*10187SKrishna.Elango@Sun.COM 	}
869*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
870*10187SKrishna.Elango@Sun.COM 
871*10187SKrishna.Elango@Sun.COM FAIL:
872*10187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
873*10187SKrishna.Elango@Sun.COM }
874*10187SKrishna.Elango@Sun.COM 
875*10187SKrishna.Elango@Sun.COM /*
876*10187SKrishna.Elango@Sun.COM  * This function initializes internally generated interrupts only.
877*10187SKrishna.Elango@Sun.COM  * It does not affect any interrupts generated by downstream devices
878*10187SKrishna.Elango@Sun.COM  * or the forwarding of them.
879*10187SKrishna.Elango@Sun.COM  *
880*10187SKrishna.Elango@Sun.COM  * Enable Device Specific Interrupts or Hotplug features here.
881*10187SKrishna.Elango@Sun.COM  * Enabling features may change how many interrupts are requested
882*10187SKrishna.Elango@Sun.COM  * by the device.  If features are not enabled first, the
883*10187SKrishna.Elango@Sun.COM  * device might not ask for any interrupts.
884*10187SKrishna.Elango@Sun.COM  */
885*10187SKrishna.Elango@Sun.COM static int
886*10187SKrishna.Elango@Sun.COM pcieb_intr_init(pcieb_devstate_t *pcieb, int intr_type)
887*10187SKrishna.Elango@Sun.COM {
888*10187SKrishna.Elango@Sun.COM 	dev_info_t	*dip = pcieb->pcieb_dip;
889*10187SKrishna.Elango@Sun.COM 	int		nintrs, request, count, x;
890*10187SKrishna.Elango@Sun.COM 	int		intr_cap = 0;
891*10187SKrishna.Elango@Sun.COM 	int		inum = 0;
892*10187SKrishna.Elango@Sun.COM 	int		ret, hp_msi_off;
893*10187SKrishna.Elango@Sun.COM 	pcie_bus_t	*bus_p = PCIE_DIP2UPBUS(dip);
894*10187SKrishna.Elango@Sun.COM 	uint16_t	vendorid = bus_p->bus_dev_ven_id & 0xFFFF;
895*10187SKrishna.Elango@Sun.COM 	boolean_t	is_hp = B_FALSE;
896*10187SKrishna.Elango@Sun.COM 	boolean_t	is_pme = B_FALSE;
897*10187SKrishna.Elango@Sun.COM 
898*10187SKrishna.Elango@Sun.COM 	PCIEB_DEBUG(DBG_ATTACH, dip, "pcieb_intr_init: Attaching %s handler\n",
899*10187SKrishna.Elango@Sun.COM 	    (intr_type == DDI_INTR_TYPE_MSI) ? "MSI" : "INTx");
900*10187SKrishna.Elango@Sun.COM 
901*10187SKrishna.Elango@Sun.COM 	request = 0;
902*10187SKrishna.Elango@Sun.COM 	if (pcieb->pcieb_hotplug_capable) {
903*10187SKrishna.Elango@Sun.COM 		request++;
904*10187SKrishna.Elango@Sun.COM 		is_hp = B_TRUE;
905*10187SKrishna.Elango@Sun.COM 	}
906*10187SKrishna.Elango@Sun.COM 
907*10187SKrishna.Elango@Sun.COM 	/*
908*10187SKrishna.Elango@Sun.COM 	 * Hotplug and PME share the same MSI vector. If hotplug is not
909*10187SKrishna.Elango@Sun.COM 	 * supported check if MSI is needed for PME.
910*10187SKrishna.Elango@Sun.COM 	 */
911*10187SKrishna.Elango@Sun.COM 	if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p) &&
912*10187SKrishna.Elango@Sun.COM 	    (vendorid == NVIDIA_VENDOR_ID)) {
913*10187SKrishna.Elango@Sun.COM 		is_pme = B_TRUE;
914*10187SKrishna.Elango@Sun.COM 		if (!is_hp)
915*10187SKrishna.Elango@Sun.COM 			request++;
916*10187SKrishna.Elango@Sun.COM 	}
917*10187SKrishna.Elango@Sun.COM 
918*10187SKrishna.Elango@Sun.COM 	/*
919*10187SKrishna.Elango@Sun.COM 	 * Setup MSI if this device is a Rootport and has AER. Currently no
920*10187SKrishna.Elango@Sun.COM 	 * SPARC Root Port supports fabric errors being reported through it.
921*10187SKrishna.Elango@Sun.COM 	 */
922*10187SKrishna.Elango@Sun.COM 	if (intr_type == DDI_INTR_TYPE_MSI) {
923*10187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p))
924*10187SKrishna.Elango@Sun.COM 			request++;
925*10187SKrishna.Elango@Sun.COM 	}
926*10187SKrishna.Elango@Sun.COM 
927*10187SKrishna.Elango@Sun.COM 	if (request == 0)
928*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
929*10187SKrishna.Elango@Sun.COM 
930*10187SKrishna.Elango@Sun.COM 	/*
931*10187SKrishna.Elango@Sun.COM 	 * Get number of supported interrupts.
932*10187SKrishna.Elango@Sun.COM 	 *
933*10187SKrishna.Elango@Sun.COM 	 * Several Bridges/Switches will not have this property set, resulting
934*10187SKrishna.Elango@Sun.COM 	 * in a FAILURE, if the device is not configured in a way that
935*10187SKrishna.Elango@Sun.COM 	 * interrupts are needed. (eg. hotplugging)
936*10187SKrishna.Elango@Sun.COM 	 */
937*10187SKrishna.Elango@Sun.COM 	ret = ddi_intr_get_nintrs(dip, intr_type, &nintrs);
938*10187SKrishna.Elango@Sun.COM 	if ((ret != DDI_SUCCESS) || (nintrs == 0)) {
939*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_nintrs ret:%d"
940*10187SKrishna.Elango@Sun.COM 		    " req:%d\n", ret, nintrs);
941*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
942*10187SKrishna.Elango@Sun.COM 	}
943*10187SKrishna.Elango@Sun.COM 
944*10187SKrishna.Elango@Sun.COM 	PCIEB_DEBUG(DBG_ATTACH, dip, "bdf 0x%x: ddi_intr_get_nintrs: nintrs %d",
945*10187SKrishna.Elango@Sun.COM 	    " request %d\n", bus_p->bus_bdf, nintrs, request);
946*10187SKrishna.Elango@Sun.COM 
947*10187SKrishna.Elango@Sun.COM 	if (request > nintrs)
948*10187SKrishna.Elango@Sun.COM 		request = nintrs;
949*10187SKrishna.Elango@Sun.COM 
950*10187SKrishna.Elango@Sun.COM 	/* Allocate an array of interrupt handlers */
951*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_htable_size = sizeof (ddi_intr_handle_t) * request;
952*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_htable = kmem_zalloc(pcieb->pcieb_htable_size,
953*10187SKrishna.Elango@Sun.COM 	    KM_SLEEP);
954*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_init_flags |= PCIEB_INIT_HTABLE;
955*10187SKrishna.Elango@Sun.COM 
956*10187SKrishna.Elango@Sun.COM 	ret = ddi_intr_alloc(dip, pcieb->pcieb_htable, intr_type, inum,
957*10187SKrishna.Elango@Sun.COM 	    request, &count, DDI_INTR_ALLOC_NORMAL);
958*10187SKrishna.Elango@Sun.COM 	if ((ret != DDI_SUCCESS) || (count == 0)) {
959*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_alloc() ret: %d ask: %d"
960*10187SKrishna.Elango@Sun.COM 		    " actual: %d\n", ret, request, count);
961*10187SKrishna.Elango@Sun.COM 		goto FAIL;
962*10187SKrishna.Elango@Sun.COM 	}
963*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_init_flags |= PCIEB_INIT_ALLOC;
964*10187SKrishna.Elango@Sun.COM 
965*10187SKrishna.Elango@Sun.COM 	/* Save the actual number of interrupts allocated */
966*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_intr_count = count;
967*10187SKrishna.Elango@Sun.COM 	if (count < request) {
968*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_ATTACH, dip, "bdf 0%x: Requested Intr: %d"
969*10187SKrishna.Elango@Sun.COM 		    " Received: %d\n", bus_p->bus_bdf, request, count);
970*10187SKrishna.Elango@Sun.COM 	}
971*10187SKrishna.Elango@Sun.COM 
972*10187SKrishna.Elango@Sun.COM 	/*
973*10187SKrishna.Elango@Sun.COM 	 * NVidia (MCP55 and other) chipsets have a errata that if the number
974*10187SKrishna.Elango@Sun.COM 	 * of requested MSI intrs is not allocated we have to fall back to INTx.
975*10187SKrishna.Elango@Sun.COM 	 */
976*10187SKrishna.Elango@Sun.COM 	if (intr_type == DDI_INTR_TYPE_MSI) {
977*10187SKrishna.Elango@Sun.COM 		if (PCIE_IS_RP(bus_p) && (vendorid == NVIDIA_VENDOR_ID)) {
978*10187SKrishna.Elango@Sun.COM 			if (request != count)
979*10187SKrishna.Elango@Sun.COM 				goto FAIL;
980*10187SKrishna.Elango@Sun.COM 		}
981*10187SKrishna.Elango@Sun.COM 	}
982*10187SKrishna.Elango@Sun.COM 
983*10187SKrishna.Elango@Sun.COM 	/* Get interrupt priority */
984*10187SKrishna.Elango@Sun.COM 	ret = ddi_intr_get_pri(pcieb->pcieb_htable[0],
985*10187SKrishna.Elango@Sun.COM 	    &pcieb->pcieb_intr_priority);
986*10187SKrishna.Elango@Sun.COM 	if (ret != DDI_SUCCESS) {
987*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_pri() ret: %d\n",
988*10187SKrishna.Elango@Sun.COM 		    ret);
989*10187SKrishna.Elango@Sun.COM 		goto FAIL;
990*10187SKrishna.Elango@Sun.COM 	}
991*10187SKrishna.Elango@Sun.COM 
992*10187SKrishna.Elango@Sun.COM 	if (pcieb->pcieb_intr_priority >= LOCK_LEVEL) {
993*10187SKrishna.Elango@Sun.COM 		pcieb->pcieb_intr_priority = LOCK_LEVEL - 1;
994*10187SKrishna.Elango@Sun.COM 		ret = ddi_intr_set_pri(pcieb->pcieb_htable[0],
995*10187SKrishna.Elango@Sun.COM 		    pcieb->pcieb_intr_priority);
996*10187SKrishna.Elango@Sun.COM 		if (ret != DDI_SUCCESS) {
997*10187SKrishna.Elango@Sun.COM 			PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_set_pri() ret:"
998*10187SKrishna.Elango@Sun.COM 			" %d\n", ret);
999*10187SKrishna.Elango@Sun.COM 
1000*10187SKrishna.Elango@Sun.COM 			goto FAIL;
1001*10187SKrishna.Elango@Sun.COM 		}
1002*10187SKrishna.Elango@Sun.COM 	}
1003*10187SKrishna.Elango@Sun.COM 
1004*10187SKrishna.Elango@Sun.COM 	mutex_init(&pcieb->pcieb_intr_mutex, NULL, MUTEX_DRIVER, NULL);
1005*10187SKrishna.Elango@Sun.COM 
1006*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_init_flags |= PCIEB_INIT_MUTEX;
1007*10187SKrishna.Elango@Sun.COM 
1008*10187SKrishna.Elango@Sun.COM 	for (count = 0; count < pcieb->pcieb_intr_count; count++) {
1009*10187SKrishna.Elango@Sun.COM 		ret = ddi_intr_add_handler(pcieb->pcieb_htable[count],
1010*10187SKrishna.Elango@Sun.COM 		    pcieb_intr_handler, (caddr_t)pcieb,
1011*10187SKrishna.Elango@Sun.COM 		    (caddr_t)(uintptr_t)(inum + count));
1012*10187SKrishna.Elango@Sun.COM 
1013*10187SKrishna.Elango@Sun.COM 		if (ret != DDI_SUCCESS) {
1014*10187SKrishna.Elango@Sun.COM 			PCIEB_DEBUG(DBG_ATTACH, dip, "Cannot add "
1015*10187SKrishna.Elango@Sun.COM 			    "interrupt(%d)\n", ret);
1016*10187SKrishna.Elango@Sun.COM 			break;
1017*10187SKrishna.Elango@Sun.COM 		}
1018*10187SKrishna.Elango@Sun.COM 	}
1019*10187SKrishna.Elango@Sun.COM 
1020*10187SKrishna.Elango@Sun.COM 	/* If unsucessful, remove the added handlers */
1021*10187SKrishna.Elango@Sun.COM 	if (ret != DDI_SUCCESS) {
1022*10187SKrishna.Elango@Sun.COM 		for (x = 0; x < count; x++) {
1023*10187SKrishna.Elango@Sun.COM 			(void) ddi_intr_remove_handler(pcieb->pcieb_htable[x]);
1024*10187SKrishna.Elango@Sun.COM 		}
1025*10187SKrishna.Elango@Sun.COM 		goto FAIL;
1026*10187SKrishna.Elango@Sun.COM 	}
1027*10187SKrishna.Elango@Sun.COM 
1028*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_init_flags |= PCIEB_INIT_HANDLER;
1029*10187SKrishna.Elango@Sun.COM 
1030*10187SKrishna.Elango@Sun.COM 	(void) ddi_intr_get_cap(pcieb->pcieb_htable[0], &intr_cap);
1031*10187SKrishna.Elango@Sun.COM 
1032*10187SKrishna.Elango@Sun.COM 	/*
1033*10187SKrishna.Elango@Sun.COM 	 * Get this intr lock because we are not quite ready to handle
1034*10187SKrishna.Elango@Sun.COM 	 * interrupts immediately after enabling it. The MSI multi register
1035*10187SKrishna.Elango@Sun.COM 	 * gets programmed in ddi_intr_enable after which we need to get the
1036*10187SKrishna.Elango@Sun.COM 	 * MSI offsets for Hotplug/AER.
1037*10187SKrishna.Elango@Sun.COM 	 */
1038*10187SKrishna.Elango@Sun.COM 	mutex_enter(&pcieb->pcieb_intr_mutex);
1039*10187SKrishna.Elango@Sun.COM 
1040*10187SKrishna.Elango@Sun.COM 	if (intr_cap & DDI_INTR_FLAG_BLOCK) {
1041*10187SKrishna.Elango@Sun.COM 		(void) ddi_intr_block_enable(pcieb->pcieb_htable,
1042*10187SKrishna.Elango@Sun.COM 		    pcieb->pcieb_intr_count);
1043*10187SKrishna.Elango@Sun.COM 		pcieb->pcieb_init_flags |= PCIEB_INIT_BLOCK;
1044*10187SKrishna.Elango@Sun.COM 	} else {
1045*10187SKrishna.Elango@Sun.COM 		for (count = 0; count < pcieb->pcieb_intr_count; count++) {
1046*10187SKrishna.Elango@Sun.COM 			(void) ddi_intr_enable(pcieb->pcieb_htable[count]);
1047*10187SKrishna.Elango@Sun.COM 		}
1048*10187SKrishna.Elango@Sun.COM 	}
1049*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_init_flags |= PCIEB_INIT_ENABLE;
1050*10187SKrishna.Elango@Sun.COM 
1051*10187SKrishna.Elango@Sun.COM 	/* Save the interrupt type */
1052*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_intr_type = intr_type;
1053*10187SKrishna.Elango@Sun.COM 
1054*10187SKrishna.Elango@Sun.COM 	/* Get the MSI offset for hotplug/PME from the PCIe cap reg */
1055*10187SKrishna.Elango@Sun.COM 	if (intr_type == DDI_INTR_TYPE_MSI) {
1056*10187SKrishna.Elango@Sun.COM 		hp_msi_off = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL,
1057*10187SKrishna.Elango@Sun.COM 		    bus_p->bus_pcie_off, PCIE_PCIECAP) &
1058*10187SKrishna.Elango@Sun.COM 		    PCIE_PCIECAP_INT_MSG_NUM;
1059*10187SKrishna.Elango@Sun.COM 
1060*10187SKrishna.Elango@Sun.COM 		if (hp_msi_off >= count) {
1061*10187SKrishna.Elango@Sun.COM 			PCIEB_DEBUG(DBG_ATTACH, dip, "MSI number %d in PCIe "
1062*10187SKrishna.Elango@Sun.COM 			    "cap > max allocated %d\n", hp_msi_off, count);
1063*10187SKrishna.Elango@Sun.COM 			mutex_exit(&pcieb->pcieb_intr_mutex);
1064*10187SKrishna.Elango@Sun.COM 			goto FAIL;
1065*10187SKrishna.Elango@Sun.COM 		}
1066*10187SKrishna.Elango@Sun.COM 
1067*10187SKrishna.Elango@Sun.COM 		if (is_hp)
1068*10187SKrishna.Elango@Sun.COM 			pcieb->pcieb_isr_tab[hp_msi_off] |= PCIEB_INTR_SRC_HP;
1069*10187SKrishna.Elango@Sun.COM 
1070*10187SKrishna.Elango@Sun.COM 		if (is_pme)
1071*10187SKrishna.Elango@Sun.COM 			pcieb->pcieb_isr_tab[hp_msi_off] |= PCIEB_INTR_SRC_PME;
1072*10187SKrishna.Elango@Sun.COM 	} else {
1073*10187SKrishna.Elango@Sun.COM 		/* INTx handles only Hotplug interrupts */
1074*10187SKrishna.Elango@Sun.COM 		if (is_hp)
1075*10187SKrishna.Elango@Sun.COM 			pcieb->pcieb_isr_tab[0] |= PCIEB_INTR_SRC_HP;
1076*10187SKrishna.Elango@Sun.COM 	}
1077*10187SKrishna.Elango@Sun.COM 
1078*10187SKrishna.Elango@Sun.COM 
1079*10187SKrishna.Elango@Sun.COM 	/*
1080*10187SKrishna.Elango@Sun.COM 	 * Get the MSI offset for errors from the AER Root Error status
1081*10187SKrishna.Elango@Sun.COM 	 * register.
1082*10187SKrishna.Elango@Sun.COM 	 */
1083*10187SKrishna.Elango@Sun.COM 	if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p)) {
1084*10187SKrishna.Elango@Sun.COM 		if (PCIE_HAS_AER(bus_p)) {
1085*10187SKrishna.Elango@Sun.COM 			int aer_msi_off;
1086*10187SKrishna.Elango@Sun.COM 			aer_msi_off = (PCI_XCAP_GET32(bus_p->bus_cfg_hdl, NULL,
1087*10187SKrishna.Elango@Sun.COM 			    bus_p->bus_aer_off, PCIE_AER_RE_STS) >>
1088*10187SKrishna.Elango@Sun.COM 			    PCIE_AER_RE_STS_MSG_NUM_SHIFT) &
1089*10187SKrishna.Elango@Sun.COM 			    PCIE_AER_RE_STS_MSG_NUM_MASK;
1090*10187SKrishna.Elango@Sun.COM 
1091*10187SKrishna.Elango@Sun.COM 			if (aer_msi_off >= count) {
1092*10187SKrishna.Elango@Sun.COM 				PCIEB_DEBUG(DBG_ATTACH, dip, "MSI number %d in"
1093*10187SKrishna.Elango@Sun.COM 				    " AER cap > max allocated %d\n",
1094*10187SKrishna.Elango@Sun.COM 				    aer_msi_off, count);
1095*10187SKrishna.Elango@Sun.COM 				mutex_exit(&pcieb->pcieb_intr_mutex);
1096*10187SKrishna.Elango@Sun.COM 				goto FAIL;
1097*10187SKrishna.Elango@Sun.COM 			}
1098*10187SKrishna.Elango@Sun.COM 			pcieb->pcieb_isr_tab[aer_msi_off] |= PCIEB_INTR_SRC_AER;
1099*10187SKrishna.Elango@Sun.COM 		} else {
1100*10187SKrishna.Elango@Sun.COM 			/*
1101*10187SKrishna.Elango@Sun.COM 			 * This RP does not have AER. Fallback to the
1102*10187SKrishna.Elango@Sun.COM 			 * SERR+Machinecheck approach if available.
1103*10187SKrishna.Elango@Sun.COM 			 */
1104*10187SKrishna.Elango@Sun.COM 			pcieb->pcieb_no_aer_msi = B_TRUE;
1105*10187SKrishna.Elango@Sun.COM 		}
1106*10187SKrishna.Elango@Sun.COM 	}
1107*10187SKrishna.Elango@Sun.COM 
1108*10187SKrishna.Elango@Sun.COM 	mutex_exit(&pcieb->pcieb_intr_mutex);
1109*10187SKrishna.Elango@Sun.COM 
1110*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
1111*10187SKrishna.Elango@Sun.COM 
1112*10187SKrishna.Elango@Sun.COM FAIL:
1113*10187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
1114*10187SKrishna.Elango@Sun.COM }
1115*10187SKrishna.Elango@Sun.COM 
1116*10187SKrishna.Elango@Sun.COM static void
1117*10187SKrishna.Elango@Sun.COM pcieb_intr_fini(pcieb_devstate_t *pcieb)
1118*10187SKrishna.Elango@Sun.COM {
1119*10187SKrishna.Elango@Sun.COM 	int x;
1120*10187SKrishna.Elango@Sun.COM 	int count = pcieb->pcieb_intr_count;
1121*10187SKrishna.Elango@Sun.COM 	int flags = pcieb->pcieb_init_flags;
1122*10187SKrishna.Elango@Sun.COM 
1123*10187SKrishna.Elango@Sun.COM 	if ((flags & PCIEB_INIT_ENABLE) &&
1124*10187SKrishna.Elango@Sun.COM 	    (flags & PCIEB_INIT_BLOCK)) {
1125*10187SKrishna.Elango@Sun.COM 		(void) ddi_intr_block_disable(pcieb->pcieb_htable, count);
1126*10187SKrishna.Elango@Sun.COM 		flags &= ~(PCIEB_INIT_ENABLE |
1127*10187SKrishna.Elango@Sun.COM 		    PCIEB_INIT_BLOCK);
1128*10187SKrishna.Elango@Sun.COM 	}
1129*10187SKrishna.Elango@Sun.COM 
1130*10187SKrishna.Elango@Sun.COM 	if (flags & PCIEB_INIT_MUTEX)
1131*10187SKrishna.Elango@Sun.COM 		mutex_destroy(&pcieb->pcieb_intr_mutex);
1132*10187SKrishna.Elango@Sun.COM 
1133*10187SKrishna.Elango@Sun.COM 	for (x = 0; x < count; x++) {
1134*10187SKrishna.Elango@Sun.COM 		if (flags & PCIEB_INIT_ENABLE)
1135*10187SKrishna.Elango@Sun.COM 			(void) ddi_intr_disable(pcieb->pcieb_htable[x]);
1136*10187SKrishna.Elango@Sun.COM 
1137*10187SKrishna.Elango@Sun.COM 		if (flags & PCIEB_INIT_HANDLER)
1138*10187SKrishna.Elango@Sun.COM 			(void) ddi_intr_remove_handler(pcieb->pcieb_htable[x]);
1139*10187SKrishna.Elango@Sun.COM 
1140*10187SKrishna.Elango@Sun.COM 		if (flags & PCIEB_INIT_ALLOC)
1141*10187SKrishna.Elango@Sun.COM 			(void) ddi_intr_free(pcieb->pcieb_htable[x]);
1142*10187SKrishna.Elango@Sun.COM 	}
1143*10187SKrishna.Elango@Sun.COM 
1144*10187SKrishna.Elango@Sun.COM 	flags &= ~(PCIEB_INIT_ENABLE | PCIEB_INIT_HANDLER | PCIEB_INIT_ALLOC |
1145*10187SKrishna.Elango@Sun.COM 	    PCIEB_INIT_MUTEX);
1146*10187SKrishna.Elango@Sun.COM 
1147*10187SKrishna.Elango@Sun.COM 	if (flags & PCIEB_INIT_HTABLE)
1148*10187SKrishna.Elango@Sun.COM 		kmem_free(pcieb->pcieb_htable, pcieb->pcieb_htable_size);
1149*10187SKrishna.Elango@Sun.COM 
1150*10187SKrishna.Elango@Sun.COM 	flags &= ~PCIEB_INIT_HTABLE;
1151*10187SKrishna.Elango@Sun.COM 
1152*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_init_flags &= flags;
1153*10187SKrishna.Elango@Sun.COM }
1154*10187SKrishna.Elango@Sun.COM 
1155*10187SKrishna.Elango@Sun.COM /*
1156*10187SKrishna.Elango@Sun.COM  * Checks if this device needs MSIs enabled or not.
1157*10187SKrishna.Elango@Sun.COM  */
1158*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
1159*10187SKrishna.Elango@Sun.COM static int
1160*10187SKrishna.Elango@Sun.COM pcieb_msi_supported(dev_info_t *dip)
1161*10187SKrishna.Elango@Sun.COM {
1162*10187SKrishna.Elango@Sun.COM 	return ((pcieb_enable_msi && pcieb_plat_msi_supported(dip)) ?
1163*10187SKrishna.Elango@Sun.COM 	    DDI_SUCCESS: DDI_FAILURE);
1164*10187SKrishna.Elango@Sun.COM }
1165*10187SKrishna.Elango@Sun.COM 
1166*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
1167*10187SKrishna.Elango@Sun.COM int
1168*10187SKrishna.Elango@Sun.COM pcieb_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
1169*10187SKrishna.Elango@Sun.COM     ddi_iblock_cookie_t *ibc)
1170*10187SKrishna.Elango@Sun.COM {
1171*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t  *pcieb = ddi_get_soft_state(pcieb_state,
1172*10187SKrishna.Elango@Sun.COM 	    ddi_get_instance(dip));
1173*10187SKrishna.Elango@Sun.COM 
1174*10187SKrishna.Elango@Sun.COM 	ASSERT(ibc != NULL);
1175*10187SKrishna.Elango@Sun.COM 	*ibc = pcieb->pcieb_fm_ibc;
1176*10187SKrishna.Elango@Sun.COM 
1177*10187SKrishna.Elango@Sun.COM 	return (DEVI(dip)->devi_fmhdl->fh_cap | DDI_FM_ACCCHK_CAPABLE |
1178*10187SKrishna.Elango@Sun.COM 	    DDI_FM_DMACHK_CAPABLE);
1179*10187SKrishna.Elango@Sun.COM }
1180*10187SKrishna.Elango@Sun.COM 
1181*10187SKrishna.Elango@Sun.COM static int
1182*10187SKrishna.Elango@Sun.COM pcieb_fm_init(pcieb_devstate_t *pcieb_p)
1183*10187SKrishna.Elango@Sun.COM {
1184*10187SKrishna.Elango@Sun.COM 	dev_info_t	*dip = pcieb_p->pcieb_dip;
1185*10187SKrishna.Elango@Sun.COM 	int		fm_cap = DDI_FM_EREPORT_CAPABLE;
1186*10187SKrishna.Elango@Sun.COM 
1187*10187SKrishna.Elango@Sun.COM 	/*
1188*10187SKrishna.Elango@Sun.COM 	 * Request our capability level and get our parents capability
1189*10187SKrishna.Elango@Sun.COM 	 * and ibc.
1190*10187SKrishna.Elango@Sun.COM 	 */
1191*10187SKrishna.Elango@Sun.COM 	ddi_fm_init(dip, &fm_cap, &pcieb_p->pcieb_fm_ibc);
1192*10187SKrishna.Elango@Sun.COM 
1193*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
1194*10187SKrishna.Elango@Sun.COM }
1195*10187SKrishna.Elango@Sun.COM 
1196*10187SKrishna.Elango@Sun.COM /*
1197*10187SKrishna.Elango@Sun.COM  * Breakdown our FMA resources
1198*10187SKrishna.Elango@Sun.COM  */
1199*10187SKrishna.Elango@Sun.COM static void
1200*10187SKrishna.Elango@Sun.COM pcieb_fm_fini(pcieb_devstate_t *pcieb_p)
1201*10187SKrishna.Elango@Sun.COM {
1202*10187SKrishna.Elango@Sun.COM 	/*
1203*10187SKrishna.Elango@Sun.COM 	 * Clean up allocated fm structures
1204*10187SKrishna.Elango@Sun.COM 	 */
1205*10187SKrishna.Elango@Sun.COM 	ddi_fm_fini(pcieb_p->pcieb_dip);
1206*10187SKrishna.Elango@Sun.COM }
1207*10187SKrishna.Elango@Sun.COM 
1208*10187SKrishna.Elango@Sun.COM static int
1209*10187SKrishna.Elango@Sun.COM pcieb_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1210*10187SKrishna.Elango@Sun.COM {
1211*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb_p;
1212*10187SKrishna.Elango@Sun.COM 	minor_t		minor = getminor(*devp);
1213*10187SKrishna.Elango@Sun.COM 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
1214*10187SKrishna.Elango@Sun.COM 
1215*10187SKrishna.Elango@Sun.COM 	/*
1216*10187SKrishna.Elango@Sun.COM 	 * Make sure the open is for the right file type.
1217*10187SKrishna.Elango@Sun.COM 	 */
1218*10187SKrishna.Elango@Sun.COM 	if (otyp != OTYP_CHR)
1219*10187SKrishna.Elango@Sun.COM 		return (EINVAL);
1220*10187SKrishna.Elango@Sun.COM 
1221*10187SKrishna.Elango@Sun.COM 	/*
1222*10187SKrishna.Elango@Sun.COM 	 * Get the soft state structure for the device.
1223*10187SKrishna.Elango@Sun.COM 	 */
1224*10187SKrishna.Elango@Sun.COM 	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
1225*10187SKrishna.Elango@Sun.COM 	    instance);
1226*10187SKrishna.Elango@Sun.COM 
1227*10187SKrishna.Elango@Sun.COM 	if (pcieb_p == NULL)
1228*10187SKrishna.Elango@Sun.COM 		return (ENXIO);
1229*10187SKrishna.Elango@Sun.COM 
1230*10187SKrishna.Elango@Sun.COM 	if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
1231*10187SKrishna.Elango@Sun.COM 		return ((pcihp_get_cb_ops())->cb_open(devp, flags,
1232*10187SKrishna.Elango@Sun.COM 		    otyp, credp));
1233*10187SKrishna.Elango@Sun.COM 
1234*10187SKrishna.Elango@Sun.COM 	/*
1235*10187SKrishna.Elango@Sun.COM 	 * Handle the open by tracking the device state.
1236*10187SKrishna.Elango@Sun.COM 	 */
1237*10187SKrishna.Elango@Sun.COM 	mutex_enter(&pcieb_p->pcieb_mutex);
1238*10187SKrishna.Elango@Sun.COM 	if (flags & FEXCL) {
1239*10187SKrishna.Elango@Sun.COM 		if (pcieb_p->pcieb_soft_state != PCIEB_SOFT_STATE_CLOSED) {
1240*10187SKrishna.Elango@Sun.COM 			mutex_exit(&pcieb_p->pcieb_mutex);
1241*10187SKrishna.Elango@Sun.COM 			return (EBUSY);
1242*10187SKrishna.Elango@Sun.COM 		}
1243*10187SKrishna.Elango@Sun.COM 		pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_OPEN_EXCL;
1244*10187SKrishna.Elango@Sun.COM 	} else {
1245*10187SKrishna.Elango@Sun.COM 		if (pcieb_p->pcieb_soft_state == PCIEB_SOFT_STATE_OPEN_EXCL) {
1246*10187SKrishna.Elango@Sun.COM 			mutex_exit(&pcieb_p->pcieb_mutex);
1247*10187SKrishna.Elango@Sun.COM 			return (EBUSY);
1248*10187SKrishna.Elango@Sun.COM 		}
1249*10187SKrishna.Elango@Sun.COM 		pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_OPEN;
1250*10187SKrishna.Elango@Sun.COM 	}
1251*10187SKrishna.Elango@Sun.COM 	mutex_exit(&pcieb_p->pcieb_mutex);
1252*10187SKrishna.Elango@Sun.COM 	return (0);
1253*10187SKrishna.Elango@Sun.COM }
1254*10187SKrishna.Elango@Sun.COM 
1255*10187SKrishna.Elango@Sun.COM static int
1256*10187SKrishna.Elango@Sun.COM pcieb_close(dev_t dev, int flags, int otyp, cred_t *credp)
1257*10187SKrishna.Elango@Sun.COM {
1258*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb_p;
1259*10187SKrishna.Elango@Sun.COM 	minor_t		minor = getminor(dev);
1260*10187SKrishna.Elango@Sun.COM 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
1261*10187SKrishna.Elango@Sun.COM 
1262*10187SKrishna.Elango@Sun.COM 	if (otyp != OTYP_CHR)
1263*10187SKrishna.Elango@Sun.COM 		return (EINVAL);
1264*10187SKrishna.Elango@Sun.COM 
1265*10187SKrishna.Elango@Sun.COM 	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
1266*10187SKrishna.Elango@Sun.COM 	    instance);
1267*10187SKrishna.Elango@Sun.COM 
1268*10187SKrishna.Elango@Sun.COM 	if (pcieb_p == NULL)
1269*10187SKrishna.Elango@Sun.COM 		return (ENXIO);
1270*10187SKrishna.Elango@Sun.COM 
1271*10187SKrishna.Elango@Sun.COM 	if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
1272*10187SKrishna.Elango@Sun.COM 		return ((pcihp_get_cb_ops())->cb_close(dev, flags,
1273*10187SKrishna.Elango@Sun.COM 		    otyp, credp));
1274*10187SKrishna.Elango@Sun.COM 
1275*10187SKrishna.Elango@Sun.COM 	mutex_enter(&pcieb_p->pcieb_mutex);
1276*10187SKrishna.Elango@Sun.COM 	pcieb_p->pcieb_soft_state = PCIEB_SOFT_STATE_CLOSED;
1277*10187SKrishna.Elango@Sun.COM 	mutex_exit(&pcieb_p->pcieb_mutex);
1278*10187SKrishna.Elango@Sun.COM 	return (0);
1279*10187SKrishna.Elango@Sun.COM }
1280*10187SKrishna.Elango@Sun.COM 
1281*10187SKrishna.Elango@Sun.COM static int
1282*10187SKrishna.Elango@Sun.COM pcieb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1283*10187SKrishna.Elango@Sun.COM 	int *rvalp)
1284*10187SKrishna.Elango@Sun.COM {
1285*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb_p;
1286*10187SKrishna.Elango@Sun.COM 	dev_info_t *self;
1287*10187SKrishna.Elango@Sun.COM 	struct devctl_iocdata *dcp;
1288*10187SKrishna.Elango@Sun.COM 	uint_t bus_state;
1289*10187SKrishna.Elango@Sun.COM 	int rv = 0;
1290*10187SKrishna.Elango@Sun.COM 	minor_t		minor = getminor(dev);
1291*10187SKrishna.Elango@Sun.COM 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
1292*10187SKrishna.Elango@Sun.COM 
1293*10187SKrishna.Elango@Sun.COM 	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
1294*10187SKrishna.Elango@Sun.COM 	    instance);
1295*10187SKrishna.Elango@Sun.COM 
1296*10187SKrishna.Elango@Sun.COM 	if (pcieb_p == NULL)
1297*10187SKrishna.Elango@Sun.COM 		return (ENXIO);
1298*10187SKrishna.Elango@Sun.COM 
1299*10187SKrishna.Elango@Sun.COM 	self = pcieb_p->pcieb_dip;
1300*10187SKrishna.Elango@Sun.COM 	if (pcieb_p->pcieb_hotplug_capable == B_TRUE) {
1301*10187SKrishna.Elango@Sun.COM 		rv = ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd,
1302*10187SKrishna.Elango@Sun.COM 		    arg, mode, credp, rvalp));
1303*10187SKrishna.Elango@Sun.COM 
1304*10187SKrishna.Elango@Sun.COM 		pcieb_plat_ioctl_hotplug(self, rv, cmd);
1305*10187SKrishna.Elango@Sun.COM 		return (rv);
1306*10187SKrishna.Elango@Sun.COM 	}
1307*10187SKrishna.Elango@Sun.COM 
1308*10187SKrishna.Elango@Sun.COM 	/*
1309*10187SKrishna.Elango@Sun.COM 	 * We can use the generic implementation for these ioctls
1310*10187SKrishna.Elango@Sun.COM 	 */
1311*10187SKrishna.Elango@Sun.COM 	switch (cmd) {
1312*10187SKrishna.Elango@Sun.COM 	case DEVCTL_DEVICE_GETSTATE:
1313*10187SKrishna.Elango@Sun.COM 	case DEVCTL_DEVICE_ONLINE:
1314*10187SKrishna.Elango@Sun.COM 	case DEVCTL_DEVICE_OFFLINE:
1315*10187SKrishna.Elango@Sun.COM 	case DEVCTL_BUS_GETSTATE:
1316*10187SKrishna.Elango@Sun.COM 		return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
1317*10187SKrishna.Elango@Sun.COM 	}
1318*10187SKrishna.Elango@Sun.COM 
1319*10187SKrishna.Elango@Sun.COM 	/*
1320*10187SKrishna.Elango@Sun.COM 	 * read devctl ioctl data
1321*10187SKrishna.Elango@Sun.COM 	 */
1322*10187SKrishna.Elango@Sun.COM 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1323*10187SKrishna.Elango@Sun.COM 		return (EFAULT);
1324*10187SKrishna.Elango@Sun.COM 
1325*10187SKrishna.Elango@Sun.COM 	switch (cmd) {
1326*10187SKrishna.Elango@Sun.COM 
1327*10187SKrishna.Elango@Sun.COM 	case DEVCTL_DEVICE_RESET:
1328*10187SKrishna.Elango@Sun.COM 		rv = ENOTSUP;
1329*10187SKrishna.Elango@Sun.COM 		break;
1330*10187SKrishna.Elango@Sun.COM 
1331*10187SKrishna.Elango@Sun.COM 	case DEVCTL_BUS_QUIESCE:
1332*10187SKrishna.Elango@Sun.COM 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1333*10187SKrishna.Elango@Sun.COM 			if (bus_state == BUS_QUIESCED)
1334*10187SKrishna.Elango@Sun.COM 				break;
1335*10187SKrishna.Elango@Sun.COM 		(void) ndi_set_bus_state(self, BUS_QUIESCED);
1336*10187SKrishna.Elango@Sun.COM 		break;
1337*10187SKrishna.Elango@Sun.COM 
1338*10187SKrishna.Elango@Sun.COM 	case DEVCTL_BUS_UNQUIESCE:
1339*10187SKrishna.Elango@Sun.COM 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1340*10187SKrishna.Elango@Sun.COM 			if (bus_state == BUS_ACTIVE)
1341*10187SKrishna.Elango@Sun.COM 				break;
1342*10187SKrishna.Elango@Sun.COM 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
1343*10187SKrishna.Elango@Sun.COM 		break;
1344*10187SKrishna.Elango@Sun.COM 
1345*10187SKrishna.Elango@Sun.COM 	case DEVCTL_BUS_RESET:
1346*10187SKrishna.Elango@Sun.COM 		rv = ENOTSUP;
1347*10187SKrishna.Elango@Sun.COM 		break;
1348*10187SKrishna.Elango@Sun.COM 
1349*10187SKrishna.Elango@Sun.COM 	case DEVCTL_BUS_RESETALL:
1350*10187SKrishna.Elango@Sun.COM 		rv = ENOTSUP;
1351*10187SKrishna.Elango@Sun.COM 		break;
1352*10187SKrishna.Elango@Sun.COM 
1353*10187SKrishna.Elango@Sun.COM 	default:
1354*10187SKrishna.Elango@Sun.COM 		rv = ENOTTY;
1355*10187SKrishna.Elango@Sun.COM 	}
1356*10187SKrishna.Elango@Sun.COM 
1357*10187SKrishna.Elango@Sun.COM 	ndi_dc_freehdl(dcp);
1358*10187SKrishna.Elango@Sun.COM 	return (rv);
1359*10187SKrishna.Elango@Sun.COM }
1360*10187SKrishna.Elango@Sun.COM 
1361*10187SKrishna.Elango@Sun.COM static int
1362*10187SKrishna.Elango@Sun.COM pcieb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1363*10187SKrishna.Elango@Sun.COM 	int flags, char *name, caddr_t valuep, int *lengthp)
1364*10187SKrishna.Elango@Sun.COM {
1365*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb_p;
1366*10187SKrishna.Elango@Sun.COM 	minor_t		minor = getminor(dev);
1367*10187SKrishna.Elango@Sun.COM 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
1368*10187SKrishna.Elango@Sun.COM 
1369*10187SKrishna.Elango@Sun.COM 	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
1370*10187SKrishna.Elango@Sun.COM 	    instance);
1371*10187SKrishna.Elango@Sun.COM 
1372*10187SKrishna.Elango@Sun.COM 	if (pcieb_p == NULL)
1373*10187SKrishna.Elango@Sun.COM 		return (ENXIO);
1374*10187SKrishna.Elango@Sun.COM 
1375*10187SKrishna.Elango@Sun.COM 	if (pcieb_p->pcieb_hotplug_capable == B_TRUE)
1376*10187SKrishna.Elango@Sun.COM 		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op,
1377*10187SKrishna.Elango@Sun.COM 		    flags, name, valuep, lengthp));
1378*10187SKrishna.Elango@Sun.COM 
1379*10187SKrishna.Elango@Sun.COM 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
1380*10187SKrishna.Elango@Sun.COM }
1381*10187SKrishna.Elango@Sun.COM 
1382*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
1383*10187SKrishna.Elango@Sun.COM static int
1384*10187SKrishna.Elango@Sun.COM pcieb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1385*10187SKrishna.Elango@Sun.COM {
1386*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb_p;	/* per pcieb state pointer */
1387*10187SKrishna.Elango@Sun.COM 	minor_t		minor = getminor((dev_t)arg);
1388*10187SKrishna.Elango@Sun.COM 	int		instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
1389*10187SKrishna.Elango@Sun.COM 
1390*10187SKrishna.Elango@Sun.COM 	pcieb_p = (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state,
1391*10187SKrishna.Elango@Sun.COM 	    instance);
1392*10187SKrishna.Elango@Sun.COM 
1393*10187SKrishna.Elango@Sun.COM 	switch (infocmd) {
1394*10187SKrishna.Elango@Sun.COM 	default:
1395*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
1396*10187SKrishna.Elango@Sun.COM 
1397*10187SKrishna.Elango@Sun.COM 	case DDI_INFO_DEVT2INSTANCE:
1398*10187SKrishna.Elango@Sun.COM 		*result = (void *)(intptr_t)instance;
1399*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
1400*10187SKrishna.Elango@Sun.COM 
1401*10187SKrishna.Elango@Sun.COM 	case DDI_INFO_DEVT2DEVINFO:
1402*10187SKrishna.Elango@Sun.COM 		if (pcieb_p == NULL)
1403*10187SKrishna.Elango@Sun.COM 			return (DDI_FAILURE);
1404*10187SKrishna.Elango@Sun.COM 		*result = (void *)pcieb_p->pcieb_dip;
1405*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
1406*10187SKrishna.Elango@Sun.COM 	}
1407*10187SKrishna.Elango@Sun.COM }
1408*10187SKrishna.Elango@Sun.COM 
1409*10187SKrishna.Elango@Sun.COM /*
1410*10187SKrishna.Elango@Sun.COM  * Common interrupt handler for hotplug, PME and errors.
1411*10187SKrishna.Elango@Sun.COM  */
1412*10187SKrishna.Elango@Sun.COM static uint_t
1413*10187SKrishna.Elango@Sun.COM pcieb_intr_handler(caddr_t arg1, caddr_t arg2)
1414*10187SKrishna.Elango@Sun.COM {
1415*10187SKrishna.Elango@Sun.COM 	pcieb_devstate_t *pcieb_p = (pcieb_devstate_t *)arg1;
1416*10187SKrishna.Elango@Sun.COM 	dev_info_t	*dip = pcieb_p->pcieb_dip;
1417*10187SKrishna.Elango@Sun.COM 	ddi_fm_error_t	derr;
1418*10187SKrishna.Elango@Sun.COM 	int		sts = 0;
1419*10187SKrishna.Elango@Sun.COM 	int		ret = DDI_INTR_UNCLAIMED;
1420*10187SKrishna.Elango@Sun.COM 	int		isrc;
1421*10187SKrishna.Elango@Sun.COM 
1422*10187SKrishna.Elango@Sun.COM 	if (!(pcieb_p->pcieb_init_flags & PCIEB_INIT_ENABLE))
1423*10187SKrishna.Elango@Sun.COM 		goto FAIL;
1424*10187SKrishna.Elango@Sun.COM 
1425*10187SKrishna.Elango@Sun.COM 	mutex_enter(&pcieb_p->pcieb_intr_mutex);
1426*10187SKrishna.Elango@Sun.COM 	isrc = pcieb_p->pcieb_isr_tab[(int)(uintptr_t)arg2];
1427*10187SKrishna.Elango@Sun.COM 	mutex_exit(&pcieb_p->pcieb_intr_mutex);
1428*10187SKrishna.Elango@Sun.COM 
1429*10187SKrishna.Elango@Sun.COM 	PCIEB_DEBUG(DBG_INTR, dip, "Received intr number %d\n",
1430*10187SKrishna.Elango@Sun.COM 	    (int)(uintptr_t)arg2);
1431*10187SKrishna.Elango@Sun.COM 
1432*10187SKrishna.Elango@Sun.COM 	if (isrc == PCIEB_INTR_SRC_UNKNOWN)
1433*10187SKrishna.Elango@Sun.COM 		goto FAIL;
1434*10187SKrishna.Elango@Sun.COM 
1435*10187SKrishna.Elango@Sun.COM 	if (isrc & PCIEB_INTR_SRC_HP) {
1436*10187SKrishna.Elango@Sun.COM 		if (pcieb_p->pcieb_hpc_type == HPC_PCIE)
1437*10187SKrishna.Elango@Sun.COM 			ret = pciehpc_intr(dip);
1438*10187SKrishna.Elango@Sun.COM 		else if (pcieb_p->pcieb_hpc_type == HPC_SHPC)
1439*10187SKrishna.Elango@Sun.COM 			ret = pcishpc_intr(dip);
1440*10187SKrishna.Elango@Sun.COM 	}
1441*10187SKrishna.Elango@Sun.COM 
1442*10187SKrishna.Elango@Sun.COM 	if (isrc & PCIEB_INTR_SRC_PME)
1443*10187SKrishna.Elango@Sun.COM 		ret = DDI_INTR_CLAIMED;
1444*10187SKrishna.Elango@Sun.COM 
1445*10187SKrishna.Elango@Sun.COM 	/* AER Error */
1446*10187SKrishna.Elango@Sun.COM 	if (isrc & PCIEB_INTR_SRC_AER) {
1447*10187SKrishna.Elango@Sun.COM 		/*
1448*10187SKrishna.Elango@Sun.COM 		 *  If MSI is shared with PME/hotplug then check Root Error
1449*10187SKrishna.Elango@Sun.COM 		 *  Status Reg before claiming it. For now it's ok since
1450*10187SKrishna.Elango@Sun.COM 		 *  we know we get 2 MSIs.
1451*10187SKrishna.Elango@Sun.COM 		 */
1452*10187SKrishna.Elango@Sun.COM 		ret = DDI_INTR_CLAIMED;
1453*10187SKrishna.Elango@Sun.COM 		bzero(&derr, sizeof (ddi_fm_error_t));
1454*10187SKrishna.Elango@Sun.COM 		derr.fme_version = DDI_FME_VERSION;
1455*10187SKrishna.Elango@Sun.COM 		mutex_enter(&pcieb_p->pcieb_peek_poke_mutex);
1456*10187SKrishna.Elango@Sun.COM 		mutex_enter(&pcieb_p->pcieb_err_mutex);
1457*10187SKrishna.Elango@Sun.COM 
1458*10187SKrishna.Elango@Sun.COM 		if ((DEVI(dip)->devi_fmhdl->fh_cap) & DDI_FM_EREPORT_CAPABLE)
1459*10187SKrishna.Elango@Sun.COM 			sts = pf_scan_fabric(dip, &derr, NULL);
1460*10187SKrishna.Elango@Sun.COM 
1461*10187SKrishna.Elango@Sun.COM 		mutex_exit(&pcieb_p->pcieb_err_mutex);
1462*10187SKrishna.Elango@Sun.COM 		mutex_exit(&pcieb_p->pcieb_peek_poke_mutex);
1463*10187SKrishna.Elango@Sun.COM 		if (pcieb_die & sts)
1464*10187SKrishna.Elango@Sun.COM 			fm_panic("%s-%d: PCI(-X) Express Fatal Error. (0x%x)",
1465*10187SKrishna.Elango@Sun.COM 			    ddi_driver_name(dip), ddi_get_instance(dip), sts);
1466*10187SKrishna.Elango@Sun.COM 	}
1467*10187SKrishna.Elango@Sun.COM FAIL:
1468*10187SKrishna.Elango@Sun.COM 	return (ret);
1469*10187SKrishna.Elango@Sun.COM }
1470*10187SKrishna.Elango@Sun.COM 
1471*10187SKrishna.Elango@Sun.COM /*
1472*10187SKrishna.Elango@Sun.COM  * Some PCI-X to PCI-E bridges do not support full 64-bit addressing on the
1473*10187SKrishna.Elango@Sun.COM  * PCI-X side of the bridge.  We build a special version of this driver for
1474*10187SKrishna.Elango@Sun.COM  * those bridges, which uses PCIEB_ADDR_LIMIT_LO and/or PCIEB_ADDR_LIMIT_HI
1475*10187SKrishna.Elango@Sun.COM  * to define the range of values which the chip can handle.  The code below
1476*10187SKrishna.Elango@Sun.COM  * then clamps the DMA address range supplied by the driver, preventing the
1477*10187SKrishna.Elango@Sun.COM  * PCI-E nexus driver from allocating any memory the bridge can't deal
1478*10187SKrishna.Elango@Sun.COM  * with.
1479*10187SKrishna.Elango@Sun.COM  */
1480*10187SKrishna.Elango@Sun.COM static int
1481*10187SKrishna.Elango@Sun.COM pcieb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
1482*10187SKrishna.Elango@Sun.COM 	ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg,
1483*10187SKrishna.Elango@Sun.COM 	ddi_dma_handle_t *handlep)
1484*10187SKrishna.Elango@Sun.COM {
1485*10187SKrishna.Elango@Sun.COM 	int		ret;
1486*10187SKrishna.Elango@Sun.COM #ifdef	BCM_SW_WORKAROUNDS
1487*10187SKrishna.Elango@Sun.COM 	uint64_t	lim;
1488*10187SKrishna.Elango@Sun.COM 
1489*10187SKrishna.Elango@Sun.COM 	/*
1490*10187SKrishna.Elango@Sun.COM 	 * If the leaf device's limits are outside than what the Broadcom
1491*10187SKrishna.Elango@Sun.COM 	 * bridge can handle, we need to clip the values passed up the chain.
1492*10187SKrishna.Elango@Sun.COM 	 */
1493*10187SKrishna.Elango@Sun.COM 	lim = attr_p->dma_attr_addr_lo;
1494*10187SKrishna.Elango@Sun.COM 	attr_p->dma_attr_addr_lo = MAX(lim, PCIEB_ADDR_LIMIT_LO);
1495*10187SKrishna.Elango@Sun.COM 
1496*10187SKrishna.Elango@Sun.COM 	lim = attr_p->dma_attr_addr_hi;
1497*10187SKrishna.Elango@Sun.COM 	attr_p->dma_attr_addr_hi = MIN(lim, PCIEB_ADDR_LIMIT_HI);
1498*10187SKrishna.Elango@Sun.COM 
1499*10187SKrishna.Elango@Sun.COM #endif	/* BCM_SW_WORKAROUNDS */
1500*10187SKrishna.Elango@Sun.COM 
1501*10187SKrishna.Elango@Sun.COM 	/*
1502*10187SKrishna.Elango@Sun.COM 	 * This is a software workaround to fix the Broadcom 5714/5715 PCIe-PCI
1503*10187SKrishna.Elango@Sun.COM 	 * bridge prefetch bug. Intercept the DMA alloc handle request and set
1504*10187SKrishna.Elango@Sun.COM 	 * PX_DMAI_FLAGS_MAP_BUFZONE flag in the handle. If this flag is set,
1505*10187SKrishna.Elango@Sun.COM 	 * the px nexus driver will allocate an extra page & make it valid one,
1506*10187SKrishna.Elango@Sun.COM 	 * for any DVMA request that comes from any of the Broadcom bridge child
1507*10187SKrishna.Elango@Sun.COM 	 * devices.
1508*10187SKrishna.Elango@Sun.COM 	 */
1509*10187SKrishna.Elango@Sun.COM 	if ((ret = ddi_dma_allochdl(dip, rdip, attr_p, waitfp, arg,
1510*10187SKrishna.Elango@Sun.COM 	    handlep)) == DDI_SUCCESS) {
1511*10187SKrishna.Elango@Sun.COM 		ddi_dma_impl_t	*mp = (ddi_dma_impl_t *)*handlep;
1512*10187SKrishna.Elango@Sun.COM #ifdef	BCM_SW_WORKAROUNDS
1513*10187SKrishna.Elango@Sun.COM 		mp->dmai_inuse |= PX_DMAI_FLAGS_MAP_BUFZONE;
1514*10187SKrishna.Elango@Sun.COM #endif	/* BCM_SW_WORKAROUNDS */
1515*10187SKrishna.Elango@Sun.COM 		/*
1516*10187SKrishna.Elango@Sun.COM 		 * For a given rdip, update mp->dmai_bdf with the bdf value
1517*10187SKrishna.Elango@Sun.COM 		 * of pcieb's immediate child or secondary bus-id of the
1518*10187SKrishna.Elango@Sun.COM 		 * PCIe2PCI bridge.
1519*10187SKrishna.Elango@Sun.COM 		 */
1520*10187SKrishna.Elango@Sun.COM 		mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip);
1521*10187SKrishna.Elango@Sun.COM 	}
1522*10187SKrishna.Elango@Sun.COM 
1523*10187SKrishna.Elango@Sun.COM 	return (ret);
1524*10187SKrishna.Elango@Sun.COM }
1525*10187SKrishna.Elango@Sun.COM 
1526*10187SKrishna.Elango@Sun.COM /*
1527*10187SKrishna.Elango@Sun.COM  * FDVMA feature is not supported for any child device of Broadcom 5714/5715
1528*10187SKrishna.Elango@Sun.COM  * PCIe-PCI bridge due to prefetch bug. Return failure immediately, so that
1529*10187SKrishna.Elango@Sun.COM  * these drivers will switch to regular DVMA path.
1530*10187SKrishna.Elango@Sun.COM  */
1531*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
1532*10187SKrishna.Elango@Sun.COM static int
1533*10187SKrishna.Elango@Sun.COM pcieb_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle,
1534*10187SKrishna.Elango@Sun.COM 	enum ddi_dma_ctlops cmd, off_t *offp, size_t *lenp, caddr_t *objp,
1535*10187SKrishna.Elango@Sun.COM 	uint_t cache_flags)
1536*10187SKrishna.Elango@Sun.COM {
1537*10187SKrishna.Elango@Sun.COM 	int	ret;
1538*10187SKrishna.Elango@Sun.COM 
1539*10187SKrishna.Elango@Sun.COM #ifdef	BCM_SW_WORKAROUNDS
1540*10187SKrishna.Elango@Sun.COM 	if (cmd == DDI_DMA_RESERVE)
1541*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
1542*10187SKrishna.Elango@Sun.COM #endif	/* BCM_SW_WORKAROUNDS */
1543*10187SKrishna.Elango@Sun.COM 
1544*10187SKrishna.Elango@Sun.COM 	if (((ret = ddi_dma_mctl(dip, rdip, handle, cmd, offp, lenp, objp,
1545*10187SKrishna.Elango@Sun.COM 	    cache_flags)) == DDI_SUCCESS) && (cmd == DDI_DMA_RESERVE)) {
1546*10187SKrishna.Elango@Sun.COM 		ddi_dma_impl_t	*mp = (ddi_dma_impl_t *)*objp;
1547*10187SKrishna.Elango@Sun.COM 
1548*10187SKrishna.Elango@Sun.COM 		/*
1549*10187SKrishna.Elango@Sun.COM 		 * For a given rdip, update mp->dmai_bdf with the bdf value
1550*10187SKrishna.Elango@Sun.COM 		 * of pcieb's immediate child or secondary bus-id of the
1551*10187SKrishna.Elango@Sun.COM 		 * PCIe2PCI bridge.
1552*10187SKrishna.Elango@Sun.COM 		 */
1553*10187SKrishna.Elango@Sun.COM 		mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip);
1554*10187SKrishna.Elango@Sun.COM 	}
1555*10187SKrishna.Elango@Sun.COM 
1556*10187SKrishna.Elango@Sun.COM 	return (ret);
1557*10187SKrishna.Elango@Sun.COM }
1558*10187SKrishna.Elango@Sun.COM 
1559*10187SKrishna.Elango@Sun.COM static int
1560*10187SKrishna.Elango@Sun.COM pcieb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
1561*10187SKrishna.Elango@Sun.COM     ddi_intr_handle_impl_t *hdlp, void *result)
1562*10187SKrishna.Elango@Sun.COM {
1563*10187SKrishna.Elango@Sun.COM 	return (pcieb_plat_intr_ops(dip, rdip, intr_op, hdlp, result));
1564*10187SKrishna.Elango@Sun.COM 
1565*10187SKrishna.Elango@Sun.COM }
1566*10187SKrishna.Elango@Sun.COM 
1567*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
1568*10187SKrishna.Elango@Sun.COM static int pcieb_pciehpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
1569*10187SKrishna.Elango@Sun.COM {
1570*10187SKrishna.Elango@Sun.COM 	uint16_t cap_ptr;
1571*10187SKrishna.Elango@Sun.COM 
1572*10187SKrishna.Elango@Sun.COM 	if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) !=
1573*10187SKrishna.Elango@Sun.COM 	    DDI_FAILURE) {
1574*10187SKrishna.Elango@Sun.COM 		uint16_t slotimpl = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
1575*10187SKrishna.Elango@Sun.COM 		    PCIE_PCIECAP) & PCIE_PCIECAP_SLOT_IMPL;
1576*10187SKrishna.Elango@Sun.COM 		if (slotimpl)
1577*10187SKrishna.Elango@Sun.COM 			if (PCI_CAP_GET32(config_handle, NULL, cap_ptr,
1578*10187SKrishna.Elango@Sun.COM 			    PCIE_SLOTCAP) & PCIE_SLOTCAP_HP_CAPABLE)
1579*10187SKrishna.Elango@Sun.COM 				return (DDI_SUCCESS);
1580*10187SKrishna.Elango@Sun.COM 	}
1581*10187SKrishna.Elango@Sun.COM 
1582*10187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
1583*10187SKrishna.Elango@Sun.COM }
1584*10187SKrishna.Elango@Sun.COM 
1585*10187SKrishna.Elango@Sun.COM static int pcieb_pcishpc_probe(dev_info_t *dip, ddi_acc_handle_t config_handle)
1586*10187SKrishna.Elango@Sun.COM {
1587*10187SKrishna.Elango@Sun.COM 	return (pcieb_plat_pcishpc_probe(dip, config_handle));
1588*10187SKrishna.Elango@Sun.COM }
1589*10187SKrishna.Elango@Sun.COM 
1590*10187SKrishna.Elango@Sun.COM /*
1591*10187SKrishna.Elango@Sun.COM  * Initialize hotplug framework if we are hotpluggable.
1592*10187SKrishna.Elango@Sun.COM  * Sets flag in the soft state if Hot Plug is supported and initialized
1593*10187SKrishna.Elango@Sun.COM  * properly.
1594*10187SKrishna.Elango@Sun.COM  */
1595*10187SKrishna.Elango@Sun.COM /*ARGSUSED*/
1596*10187SKrishna.Elango@Sun.COM static int
1597*10187SKrishna.Elango@Sun.COM pcieb_init_hotplug(pcieb_devstate_t *pcieb)
1598*10187SKrishna.Elango@Sun.COM {
1599*10187SKrishna.Elango@Sun.COM 	int rv = DDI_FAILURE;
1600*10187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip);
1601*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl;
1602*10187SKrishna.Elango@Sun.COM 	uint8_t dev_type = bus_p->bus_dev_type;
1603*10187SKrishna.Elango@Sun.COM 
1604*10187SKrishna.Elango@Sun.COM #ifdef PX_PLX
1605*10187SKrishna.Elango@Sun.COM 	uint16_t vid = bus_p->bus_dev_ven_id & 0xFFFF;
1606*10187SKrishna.Elango@Sun.COM 	uint16_t did = bus_p->bus_dev_ven_id >> 16;
1607*10187SKrishna.Elango@Sun.COM 	if ((vid == PXB_VENDOR_PLX) && (did == PXB_DEVICE_PLX_8532) &&
1608*10187SKrishna.Elango@Sun.COM 	    (bus_p->bus_rev_id <= PXB_DEVICE_PLX_AA_REV))
1609*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
1610*10187SKrishna.Elango@Sun.COM #endif /* PX_PLX */
1611*10187SKrishna.Elango@Sun.COM 
1612*10187SKrishna.Elango@Sun.COM 	if (((dev_type == PCIE_PCIECAP_DEV_TYPE_DOWN) ||
1613*10187SKrishna.Elango@Sun.COM 	    (dev_type == PCIE_PCIECAP_DEV_TYPE_PCI2PCIE) ||
1614*10187SKrishna.Elango@Sun.COM 	    (dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT)) &&
1615*10187SKrishna.Elango@Sun.COM 	    (pcieb_pciehpc_probe(pcieb->pcieb_dip,
1616*10187SKrishna.Elango@Sun.COM 	    config_handle) == DDI_SUCCESS)) {
1617*10187SKrishna.Elango@Sun.COM 		pcieb->pcieb_hpc_type = HPC_PCIE;
1618*10187SKrishna.Elango@Sun.COM 	} else if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) &&
1619*10187SKrishna.Elango@Sun.COM 	    (pcieb_pcishpc_probe(pcieb->pcieb_dip,
1620*10187SKrishna.Elango@Sun.COM 	    config_handle) == DDI_SUCCESS)) {
1621*10187SKrishna.Elango@Sun.COM 		pcieb->pcieb_hpc_type = HPC_SHPC;
1622*10187SKrishna.Elango@Sun.COM 	} else {
1623*10187SKrishna.Elango@Sun.COM 		pcieb->pcieb_hpc_type = HPC_NONE;
1624*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
1625*10187SKrishna.Elango@Sun.COM 	}
1626*10187SKrishna.Elango@Sun.COM 
1627*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_hotplug_capable = B_TRUE;
1628*10187SKrishna.Elango@Sun.COM 
1629*10187SKrishna.Elango@Sun.COM 	if (pcieb->pcieb_hpc_type == HPC_PCIE)
1630*10187SKrishna.Elango@Sun.COM 		rv = pciehpc_init(pcieb->pcieb_dip, NULL);
1631*10187SKrishna.Elango@Sun.COM 	else if (pcieb->pcieb_hpc_type == HPC_SHPC)
1632*10187SKrishna.Elango@Sun.COM 		rv = pcishpc_init(pcieb->pcieb_dip);
1633*10187SKrishna.Elango@Sun.COM 
1634*10187SKrishna.Elango@Sun.COM 	if (rv != DDI_SUCCESS)
1635*10187SKrishna.Elango@Sun.COM 		goto fail;
1636*10187SKrishna.Elango@Sun.COM 
1637*10187SKrishna.Elango@Sun.COM 	if (pcihp_init(pcieb->pcieb_dip) != DDI_SUCCESS) {
1638*10187SKrishna.Elango@Sun.COM 		if (pcieb->pcieb_hpc_type == HPC_PCIE)
1639*10187SKrishna.Elango@Sun.COM 			(void) pciehpc_uninit(pcieb->pcieb_dip);
1640*10187SKrishna.Elango@Sun.COM 		else if (pcieb->pcieb_hpc_type == HPC_SHPC)
1641*10187SKrishna.Elango@Sun.COM 			(void) pcishpc_uninit(pcieb->pcieb_dip);
1642*10187SKrishna.Elango@Sun.COM 
1643*10187SKrishna.Elango@Sun.COM 		goto fail;
1644*10187SKrishna.Elango@Sun.COM 	}
1645*10187SKrishna.Elango@Sun.COM 
1646*10187SKrishna.Elango@Sun.COM 	(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pcieb->pcieb_dip,
1647*10187SKrishna.Elango@Sun.COM 	    "hotplug-capable");
1648*10187SKrishna.Elango@Sun.COM 
1649*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
1650*10187SKrishna.Elango@Sun.COM 
1651*10187SKrishna.Elango@Sun.COM fail:
1652*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_hpc_type = HPC_NONE;
1653*10187SKrishna.Elango@Sun.COM 	pcieb->pcieb_hotplug_capable = B_FALSE;
1654*10187SKrishna.Elango@Sun.COM 	cmn_err(CE_WARN, "%s%d: Failed setting hotplug framework",
1655*10187SKrishna.Elango@Sun.COM 	    ddi_driver_name(pcieb->pcieb_dip),
1656*10187SKrishna.Elango@Sun.COM 	    ddi_get_instance(pcieb->pcieb_dip));
1657*10187SKrishna.Elango@Sun.COM 
1658*10187SKrishna.Elango@Sun.COM 	return (DDI_FAILURE);
1659*10187SKrishna.Elango@Sun.COM }
1660*10187SKrishna.Elango@Sun.COM 
1661*10187SKrishna.Elango@Sun.COM /*
1662*10187SKrishna.Elango@Sun.COM  * Power management related initialization specific to pcieb.
1663*10187SKrishna.Elango@Sun.COM  * Called by pcieb_attach()
1664*10187SKrishna.Elango@Sun.COM  */
1665*10187SKrishna.Elango@Sun.COM static int
1666*10187SKrishna.Elango@Sun.COM pcieb_pwr_setup(dev_info_t *dip)
1667*10187SKrishna.Elango@Sun.COM {
1668*10187SKrishna.Elango@Sun.COM 	char *comp_array[5];
1669*10187SKrishna.Elango@Sun.COM 	int i;
1670*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t conf_hdl;
1671*10187SKrishna.Elango@Sun.COM 	uint16_t pmcap, cap_ptr;
1672*10187SKrishna.Elango@Sun.COM 	pcie_pwr_t *pwr_p;
1673*10187SKrishna.Elango@Sun.COM 
1674*10187SKrishna.Elango@Sun.COM 	/* Some platforms/devices may choose to disable PM */
1675*10187SKrishna.Elango@Sun.COM 	if (pcieb_plat_pwr_disable(dip)) {
1676*10187SKrishna.Elango@Sun.COM 		(void) pcieb_pwr_disable(dip);
1677*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
1678*10187SKrishna.Elango@Sun.COM 	}
1679*10187SKrishna.Elango@Sun.COM 
1680*10187SKrishna.Elango@Sun.COM 	ASSERT(PCIE_PMINFO(dip));
1681*10187SKrishna.Elango@Sun.COM 	pwr_p = PCIE_NEXUS_PMINFO(dip);
1682*10187SKrishna.Elango@Sun.COM 	ASSERT(pwr_p);
1683*10187SKrishna.Elango@Sun.COM 
1684*10187SKrishna.Elango@Sun.COM 	/* Code taken from pci_pci driver */
1685*10187SKrishna.Elango@Sun.COM 	if (pci_config_setup(dip, &pwr_p->pwr_conf_hdl) != DDI_SUCCESS) {
1686*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_setup: pci_config_setup "
1687*10187SKrishna.Elango@Sun.COM 		    "failed\n");
1688*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
1689*10187SKrishna.Elango@Sun.COM 	}
1690*10187SKrishna.Elango@Sun.COM 	conf_hdl = pwr_p->pwr_conf_hdl;
1691*10187SKrishna.Elango@Sun.COM 
1692*10187SKrishna.Elango@Sun.COM 	/*
1693*10187SKrishna.Elango@Sun.COM 	 * Walk the capabilities searching for a PM entry.
1694*10187SKrishna.Elango@Sun.COM 	 */
1695*10187SKrishna.Elango@Sun.COM 	if ((PCI_CAP_LOCATE(conf_hdl, PCI_CAP_ID_PM, &cap_ptr)) ==
1696*10187SKrishna.Elango@Sun.COM 	    DDI_FAILURE) {
1697*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, dip, "switch/bridge does not support PM. "
1698*10187SKrishna.Elango@Sun.COM 		    " PCI PM data structure not found in config header\n");
1699*10187SKrishna.Elango@Sun.COM 		pci_config_teardown(&conf_hdl);
1700*10187SKrishna.Elango@Sun.COM 		return (DDI_SUCCESS);
1701*10187SKrishna.Elango@Sun.COM 	}
1702*10187SKrishna.Elango@Sun.COM 	/*
1703*10187SKrishna.Elango@Sun.COM 	 * Save offset to pmcsr for future references.
1704*10187SKrishna.Elango@Sun.COM 	 */
1705*10187SKrishna.Elango@Sun.COM 	pwr_p->pwr_pmcsr_offset = cap_ptr + PCI_PMCSR;
1706*10187SKrishna.Elango@Sun.COM 	pmcap = PCI_CAP_GET16(conf_hdl, NULL, cap_ptr, PCI_PMCAP);
1707*10187SKrishna.Elango@Sun.COM 	if (pmcap & PCI_PMCAP_D1) {
1708*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, dip, "D1 state supported\n");
1709*10187SKrishna.Elango@Sun.COM 		pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D1;
1710*10187SKrishna.Elango@Sun.COM 	}
1711*10187SKrishna.Elango@Sun.COM 	if (pmcap & PCI_PMCAP_D2) {
1712*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, dip, "D2 state supported\n");
1713*10187SKrishna.Elango@Sun.COM 		pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D2;
1714*10187SKrishna.Elango@Sun.COM 	}
1715*10187SKrishna.Elango@Sun.COM 
1716*10187SKrishna.Elango@Sun.COM 	i = 0;
1717*10187SKrishna.Elango@Sun.COM 	comp_array[i++] = "NAME=PCIe switch/bridge PM";
1718*10187SKrishna.Elango@Sun.COM 	comp_array[i++] = "0=Power Off (D3)";
1719*10187SKrishna.Elango@Sun.COM 	if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D2)
1720*10187SKrishna.Elango@Sun.COM 		comp_array[i++] = "1=D2";
1721*10187SKrishna.Elango@Sun.COM 	if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D1)
1722*10187SKrishna.Elango@Sun.COM 		comp_array[i++] = "2=D1";
1723*10187SKrishna.Elango@Sun.COM 	comp_array[i++] = "3=Full Power D0";
1724*10187SKrishna.Elango@Sun.COM 
1725*10187SKrishna.Elango@Sun.COM 	/*
1726*10187SKrishna.Elango@Sun.COM 	 * Create pm-components property, if it does not exist already.
1727*10187SKrishna.Elango@Sun.COM 	 */
1728*10187SKrishna.Elango@Sun.COM 	if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
1729*10187SKrishna.Elango@Sun.COM 	    "pm-components", comp_array, i) != DDI_PROP_SUCCESS) {
1730*10187SKrishna.Elango@Sun.COM 		PCIEB_DEBUG(DBG_PWR, dip, "could not create pm-components "
1731*10187SKrishna.Elango@Sun.COM 		    " prop\n");
1732*10187SKrishna.Elango@Sun.COM 		pci_config_teardown(&conf_hdl);
1733*10187SKrishna.Elango@Sun.COM 		return (DDI_FAILURE);
1734*10187SKrishna.Elango@Sun.COM 	}
1735*10187SKrishna.Elango@Sun.COM 	return (pcieb_pwr_init_and_raise(dip, pwr_p));
1736*10187SKrishna.Elango@Sun.COM }
1737*10187SKrishna.Elango@Sun.COM 
1738*10187SKrishna.Elango@Sun.COM /*
1739*10187SKrishna.Elango@Sun.COM  * undo whatever is done in pcieb_pwr_setup. called by pcieb_detach()
1740*10187SKrishna.Elango@Sun.COM  */
1741*10187SKrishna.Elango@Sun.COM static void
1742*10187SKrishna.Elango@Sun.COM pcieb_pwr_teardown(dev_info_t *dip)
1743*10187SKrishna.Elango@Sun.COM {
1744*10187SKrishna.Elango@Sun.COM 	pcie_pwr_t	*pwr_p;
1745*10187SKrishna.Elango@Sun.COM 
1746*10187SKrishna.Elango@Sun.COM 	if (!PCIE_PMINFO(dip) || !(pwr_p = PCIE_NEXUS_PMINFO(dip)))
1747*10187SKrishna.Elango@Sun.COM 		return;
1748*10187SKrishna.Elango@Sun.COM 
1749*10187SKrishna.Elango@Sun.COM 	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components");
1750*10187SKrishna.Elango@Sun.COM 	if (pwr_p->pwr_conf_hdl)
1751*10187SKrishna.Elango@Sun.COM 		pci_config_teardown(&pwr_p->pwr_conf_hdl);
1752*10187SKrishna.Elango@Sun.COM }
1753*10187SKrishna.Elango@Sun.COM 
1754*10187SKrishna.Elango@Sun.COM /*
1755*10187SKrishna.Elango@Sun.COM  * Initializes the power level and raise the power to D0, if it is
1756*10187SKrishna.Elango@Sun.COM  * not at D0.
1757*10187SKrishna.Elango@Sun.COM  */
1758*10187SKrishna.Elango@Sun.COM static int
1759*10187SKrishna.Elango@Sun.COM pcieb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p)
1760*10187SKrishna.Elango@Sun.COM {
1761*10187SKrishna.Elango@Sun.COM 	uint16_t pmcsr;
1762*10187SKrishna.Elango@Sun.COM 	int ret = DDI_SUCCESS;
1763*10187SKrishna.Elango@Sun.COM 
1764*10187SKrishna.Elango@Sun.COM 	/*
1765*10187SKrishna.Elango@Sun.COM 	 * Intialize our power level from PMCSR. The common code initializes
1766*10187SKrishna.Elango@Sun.COM 	 * this to UNKNOWN. There is no guarantee that we will be at full
1767*10187SKrishna.Elango@Sun.COM 	 * power at attach. If we are not at D0, raise the power.
1768*10187SKrishna.Elango@Sun.COM 	 */
1769*10187SKrishna.Elango@Sun.COM 	pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl, pwr_p->pwr_pmcsr_offset);
1770*10187SKrishna.Elango@Sun.COM 	pmcsr &= PCI_PMCSR_STATE_MASK;
1771*10187SKrishna.Elango@Sun.COM 	switch (pmcsr) {
1772*10187SKrishna.Elango@Sun.COM 	case PCI_PMCSR_D0:
1773*10187SKrishna.Elango@Sun.COM 		pwr_p->pwr_func_lvl = PM_LEVEL_D0;
1774*10187SKrishna.Elango@Sun.COM 		break;
1775*10187SKrishna.Elango@Sun.COM 
1776*10187SKrishna.Elango@Sun.COM 	case PCI_PMCSR_D1:
1777*10187SKrishna.Elango@Sun.COM 		pwr_p->pwr_func_lvl = PM_LEVEL_D1;
1778*10187SKrishna.Elango@Sun.COM 		break;
1779*10187SKrishna.Elango@Sun.COM 
1780*10187SKrishna.Elango@Sun.COM 	case PCI_PMCSR_D2:
1781*10187SKrishna.Elango@Sun.COM 		pwr_p->pwr_func_lvl = PM_LEVEL_D2;
1782*10187SKrishna.Elango@Sun.COM 		break;
1783*10187SKrishna.Elango@Sun.COM 
1784*10187SKrishna.Elango@Sun.COM 	case PCI_PMCSR_D3HOT:
1785*10187SKrishna.Elango@Sun.COM 		pwr_p->pwr_func_lvl = PM_LEVEL_D3;
1786*10187SKrishna.Elango@Sun.COM 		break;
1787*10187SKrishna.Elango@Sun.COM 
1788*10187SKrishna.Elango@Sun.COM 	default:
1789*10187SKrishna.Elango@Sun.COM 		break;
1790*10187SKrishna.Elango@Sun.COM 	}
1791*10187SKrishna.Elango@Sun.COM 
1792*10187SKrishna.Elango@Sun.COM 	/* Raise the power to D0. */
1793*10187SKrishna.Elango@Sun.COM 	if (pwr_p->pwr_func_lvl != PM_LEVEL_D0 &&
1794*10187SKrishna.Elango@Sun.COM 	    ((ret = pm_raise_power(dip, 0, PM_LEVEL_D0)) != DDI_SUCCESS)) {
1795*10187SKrishna.Elango@Sun.COM 		/*
1796*10187SKrishna.Elango@Sun.COM 		 * Read PMCSR again. If it is at D0, ignore the return
1797*10187SKrishna.Elango@Sun.COM 		 * value from pm_raise_power.
1798*10187SKrishna.Elango@Sun.COM 		 */
1799*10187SKrishna.Elango@Sun.COM 		pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl,
1800*10187SKrishna.Elango@Sun.COM 		    pwr_p->pwr_pmcsr_offset);
1801*10187SKrishna.Elango@Sun.COM 		if ((pmcsr & PCI_PMCSR_STATE_MASK) == PCI_PMCSR_D0)
1802*10187SKrishna.Elango@Sun.COM 			ret = DDI_SUCCESS;
1803*10187SKrishna.Elango@Sun.COM 		else {
1804*10187SKrishna.Elango@Sun.COM 			PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_setup: could not "
1805*10187SKrishna.Elango@Sun.COM 			    "raise power to D0 \n");
1806*10187SKrishna.Elango@Sun.COM 		}
1807*10187SKrishna.Elango@Sun.COM 	}
1808*10187SKrishna.Elango@Sun.COM 	if (ret == DDI_SUCCESS)
1809*10187SKrishna.Elango@Sun.COM 		pwr_p->pwr_func_lvl = PM_LEVEL_D0;
1810*10187SKrishna.Elango@Sun.COM 	return (ret);
1811*10187SKrishna.Elango@Sun.COM }
1812*10187SKrishna.Elango@Sun.COM 
1813*10187SKrishna.Elango@Sun.COM /*
1814*10187SKrishna.Elango@Sun.COM  * Disable PM for x86 and PLX 8532 switch.
1815*10187SKrishna.Elango@Sun.COM  * For PLX Transitioning one port on this switch to low power causes links
1816*10187SKrishna.Elango@Sun.COM  * on other ports on the same station to die. Due to PLX erratum #34, we
1817*10187SKrishna.Elango@Sun.COM  * can't allow the downstream device go to non-D0 state.
1818*10187SKrishna.Elango@Sun.COM  */
1819*10187SKrishna.Elango@Sun.COM static int
1820*10187SKrishna.Elango@Sun.COM pcieb_pwr_disable(dev_info_t *dip)
1821*10187SKrishna.Elango@Sun.COM {
1822*10187SKrishna.Elango@Sun.COM 	pcie_pwr_t *pwr_p;
1823*10187SKrishna.Elango@Sun.COM 
1824*10187SKrishna.Elango@Sun.COM 	ASSERT(PCIE_PMINFO(dip));
1825*10187SKrishna.Elango@Sun.COM 	pwr_p = PCIE_NEXUS_PMINFO(dip);
1826*10187SKrishna.Elango@Sun.COM 	ASSERT(pwr_p);
1827*10187SKrishna.Elango@Sun.COM 	PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_disable: disabling PM\n");
1828*10187SKrishna.Elango@Sun.COM 	pwr_p->pwr_func_lvl = PM_LEVEL_D0;
1829*10187SKrishna.Elango@Sun.COM 	pwr_p->pwr_flags = PCIE_NO_CHILD_PM;
1830*10187SKrishna.Elango@Sun.COM 	return (DDI_SUCCESS);
1831*10187SKrishna.Elango@Sun.COM }
1832*10187SKrishna.Elango@Sun.COM 
1833*10187SKrishna.Elango@Sun.COM #ifdef DEBUG
1834*10187SKrishna.Elango@Sun.COM int pcieb_dbg_intr_print = 0;
1835*10187SKrishna.Elango@Sun.COM void
1836*10187SKrishna.Elango@Sun.COM pcieb_dbg(uint_t bit, dev_info_t *dip, char *fmt, ...)
1837*10187SKrishna.Elango@Sun.COM {
1838*10187SKrishna.Elango@Sun.COM 	va_list ap;
1839*10187SKrishna.Elango@Sun.COM 
1840*10187SKrishna.Elango@Sun.COM 	if (!pcieb_dbg_print)
1841*10187SKrishna.Elango@Sun.COM 		return;
1842*10187SKrishna.Elango@Sun.COM 
1843*10187SKrishna.Elango@Sun.COM 	if (dip)
1844*10187SKrishna.Elango@Sun.COM 		prom_printf("%s(%d): %s", ddi_driver_name(dip),
1845*10187SKrishna.Elango@Sun.COM 		    ddi_get_instance(dip), pcieb_debug_sym[bit]);
1846*10187SKrishna.Elango@Sun.COM 
1847*10187SKrishna.Elango@Sun.COM 	va_start(ap, fmt);
1848*10187SKrishna.Elango@Sun.COM 	if (servicing_interrupt()) {
1849*10187SKrishna.Elango@Sun.COM 		if (pcieb_dbg_intr_print)
1850*10187SKrishna.Elango@Sun.COM 			prom_vprintf(fmt, ap);
1851*10187SKrishna.Elango@Sun.COM 	} else {
1852*10187SKrishna.Elango@Sun.COM 		prom_vprintf(fmt, ap);
1853*10187SKrishna.Elango@Sun.COM 	}
1854*10187SKrishna.Elango@Sun.COM 
1855*10187SKrishna.Elango@Sun.COM 	va_end(ap);
1856*10187SKrishna.Elango@Sun.COM }
1857*10187SKrishna.Elango@Sun.COM #endif
1858*10187SKrishna.Elango@Sun.COM 
1859*10187SKrishna.Elango@Sun.COM static void
1860*10187SKrishna.Elango@Sun.COM pcieb_id_props(pcieb_devstate_t *pcieb)
1861*10187SKrishna.Elango@Sun.COM {
1862*10187SKrishna.Elango@Sun.COM 	uint64_t serialid = 0;	/* 40b field of EUI-64 serial no. register */
1863*10187SKrishna.Elango@Sun.COM 	uint16_t cap_ptr;
1864*10187SKrishna.Elango@Sun.COM 	uint8_t fic = 0;	/* 1 = first in chassis device */
1865*10187SKrishna.Elango@Sun.COM 	pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip);
1866*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl;
1867*10187SKrishna.Elango@Sun.COM 
1868*10187SKrishna.Elango@Sun.COM 	/*
1869*10187SKrishna.Elango@Sun.COM 	 * Identify first in chassis.  In the special case of a Sun branded
1870*10187SKrishna.Elango@Sun.COM 	 * PLX device, it obviously is first in chassis.  Otherwise, in the
1871*10187SKrishna.Elango@Sun.COM 	 * general case, look for an Expansion Slot Register and check its
1872*10187SKrishna.Elango@Sun.COM 	 * first-in-chassis bit.
1873*10187SKrishna.Elango@Sun.COM 	 */
1874*10187SKrishna.Elango@Sun.COM #ifdef	PX_PLX
1875*10187SKrishna.Elango@Sun.COM 	uint16_t vendor_id = bus_p->bus_dev_ven_id & 0xFFFF;
1876*10187SKrishna.Elango@Sun.COM 	uint16_t device_id = bus_p->bus_dev_ven_id >> 16;
1877*10187SKrishna.Elango@Sun.COM 	if ((vendor_id == PXB_VENDOR_SUN) &&
1878*10187SKrishna.Elango@Sun.COM 	    ((device_id == PXB_DEVICE_PLX_PCIX) ||
1879*10187SKrishna.Elango@Sun.COM 	    (device_id == PXB_DEVICE_PLX_PCIE))) {
1880*10187SKrishna.Elango@Sun.COM 		fic = 1;
1881*10187SKrishna.Elango@Sun.COM 	}
1882*10187SKrishna.Elango@Sun.COM #endif	/* PX_PLX */
1883*10187SKrishna.Elango@Sun.COM 	if ((fic == 0) && ((PCI_CAP_LOCATE(config_handle,
1884*10187SKrishna.Elango@Sun.COM 	    PCI_CAP_ID_SLOT_ID, &cap_ptr)) != DDI_FAILURE)) {
1885*10187SKrishna.Elango@Sun.COM 		uint8_t esr = PCI_CAP_GET8(config_handle, NULL,
1886*10187SKrishna.Elango@Sun.COM 		    cap_ptr, PCI_CAP_ID_REGS_OFF);
1887*10187SKrishna.Elango@Sun.COM 		if (PCI_CAPSLOT_FIC(esr))
1888*10187SKrishna.Elango@Sun.COM 			fic = 1;
1889*10187SKrishna.Elango@Sun.COM 	}
1890*10187SKrishna.Elango@Sun.COM 
1891*10187SKrishna.Elango@Sun.COM 	if ((PCI_CAP_LOCATE(config_handle,
1892*10187SKrishna.Elango@Sun.COM 	    PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_SER), &cap_ptr)) != DDI_FAILURE) {
1893*10187SKrishna.Elango@Sun.COM 		/* Serialid can be 0 thru a full 40b number */
1894*10187SKrishna.Elango@Sun.COM 		serialid = PCI_XCAP_GET32(config_handle, NULL,
1895*10187SKrishna.Elango@Sun.COM 		    cap_ptr, PCIE_SER_SID_UPPER_DW);
1896*10187SKrishna.Elango@Sun.COM 		serialid <<= 32;
1897*10187SKrishna.Elango@Sun.COM 		serialid |= PCI_XCAP_GET32(config_handle, NULL,
1898*10187SKrishna.Elango@Sun.COM 		    cap_ptr, PCIE_SER_SID_LOWER_DW);
1899*10187SKrishna.Elango@Sun.COM 	}
1900*10187SKrishna.Elango@Sun.COM 
1901*10187SKrishna.Elango@Sun.COM 	if (fic)
1902*10187SKrishna.Elango@Sun.COM 		(void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pcieb->pcieb_dip,
1903*10187SKrishna.Elango@Sun.COM 		    "first-in-chassis");
1904*10187SKrishna.Elango@Sun.COM 	if (serialid)
1905*10187SKrishna.Elango@Sun.COM 		(void) ddi_prop_update_int64(DDI_DEV_T_NONE, pcieb->pcieb_dip,
1906*10187SKrishna.Elango@Sun.COM 		    "serialid#", serialid);
1907*10187SKrishna.Elango@Sun.COM }
1908*10187SKrishna.Elango@Sun.COM 
1909*10187SKrishna.Elango@Sun.COM static void
1910*10187SKrishna.Elango@Sun.COM pcieb_create_ranges_prop(dev_info_t *dip,
1911*10187SKrishna.Elango@Sun.COM 	ddi_acc_handle_t config_handle)
1912*10187SKrishna.Elango@Sun.COM {
1913*10187SKrishna.Elango@Sun.COM 	uint32_t base, limit;
1914*10187SKrishna.Elango@Sun.COM 	pcieb_ranges_t	ranges[PCIEB_RANGE_LEN];
1915*10187SKrishna.Elango@Sun.COM 	uint8_t io_base_lo, io_limit_lo;
1916*10187SKrishna.Elango@Sun.COM 	uint16_t io_base_hi, io_limit_hi, mem_base, mem_limit;
1917*10187SKrishna.Elango@Sun.COM 	int i = 0, rangelen = sizeof (pcieb_ranges_t)/sizeof (int);
1918*10187SKrishna.Elango@Sun.COM 
1919*10187SKrishna.Elango@Sun.COM 	io_base_lo = pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW);
1920*10187SKrishna.Elango@Sun.COM 	io_limit_lo = pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW);
1921*10187SKrishna.Elango@Sun.COM 	io_base_hi = pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI);
1922*10187SKrishna.Elango@Sun.COM 	io_limit_hi = pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI);
1923*10187SKrishna.Elango@Sun.COM 	mem_base = pci_config_get16(config_handle, PCI_BCNF_MEM_BASE);
1924*10187SKrishna.Elango@Sun.COM 	mem_limit = pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT);
1925*10187SKrishna.Elango@Sun.COM 
1926*10187SKrishna.Elango@Sun.COM 	/*
1927*10187SKrishna.Elango@Sun.COM 	 * Create ranges for IO space
1928*10187SKrishna.Elango@Sun.COM 	 */
1929*10187SKrishna.Elango@Sun.COM 	ranges[i].size_low = ranges[i].size_high = 0;
1930*10187SKrishna.Elango@Sun.COM 	ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0;
1931*10187SKrishna.Elango@Sun.COM 	ranges[i].child_high = ranges[i].parent_high |=
1932*10187SKrishna.Elango@Sun.COM 	    (PCI_REG_REL_M | PCI_ADDR_IO);
1933*10187SKrishna.Elango@Sun.COM 	base = PCIEB_16bit_IOADDR(io_base_lo);
1934*10187SKrishna.Elango@Sun.COM 	limit = PCIEB_16bit_IOADDR(io_limit_lo);
1935*10187SKrishna.Elango@Sun.COM 
1936*10187SKrishna.Elango@Sun.COM 	if ((io_base_lo & 0xf) == PCIEB_32BIT_IO) {
1937*10187SKrishna.Elango@Sun.COM 		base = PCIEB_LADDR(base, io_base_hi);
1938*10187SKrishna.Elango@Sun.COM 	}
1939*10187SKrishna.Elango@Sun.COM 	if ((io_limit_lo & 0xf) == PCIEB_32BIT_IO) {
1940*10187SKrishna.Elango@Sun.COM 		limit = PCIEB_LADDR(limit, io_limit_hi);
1941*10187SKrishna.Elango@Sun.COM 	}
1942*10187SKrishna.Elango@Sun.COM 
1943*10187SKrishna.Elango@Sun.COM 	if ((io_base_lo & PCIEB_32BIT_IO) && (io_limit_hi > 0)) {
1944*10187SKrishna.Elango@Sun.COM 		base = PCIEB_LADDR(base, io_base_hi);
1945*10187SKrishna.Elango@Sun.COM 		limit = PCIEB_LADDR(limit, io_limit_hi);
1946*10187SKrishna.Elango@Sun.COM 	}
1947*10187SKrishna.Elango@Sun.COM 
1948*10187SKrishna.Elango@Sun.COM 	/*
1949*10187SKrishna.Elango@Sun.COM 	 * Create ranges for 32bit memory space
1950*10187SKrishna.Elango@Sun.COM 	 */
1951*10187SKrishna.Elango@Sun.COM 	base = PCIEB_32bit_MEMADDR(mem_base);
1952*10187SKrishna.Elango@Sun.COM 	limit = PCIEB_32bit_MEMADDR(mem_limit);
1953*10187SKrishna.Elango@Sun.COM 	ranges[i].size_low = ranges[i].size_high = 0;
1954*10187SKrishna.Elango@Sun.COM 	ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0;
1955*10187SKrishna.Elango@Sun.COM 	ranges[i].child_high = ranges[i].parent_high |=
1956*10187SKrishna.Elango@Sun.COM 	    (PCI_REG_REL_M | PCI_ADDR_MEM32);
1957*10187SKrishna.Elango@Sun.COM 	ranges[i].child_low = ranges[i].parent_low = base;
1958*10187SKrishna.Elango@Sun.COM 	if (limit >= base) {
1959*10187SKrishna.Elango@Sun.COM 		ranges[i].size_low = limit - base + PCIEB_MEMGRAIN;
1960*10187SKrishna.Elango@Sun.COM 		i++;
1961*10187SKrishna.Elango@Sun.COM 	}
1962*10187SKrishna.Elango@Sun.COM 
1963*10187SKrishna.Elango@Sun.COM 	if (i) {
1964*10187SKrishna.Elango@Sun.COM 		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
1965*10187SKrishna.Elango@Sun.COM 		    (int *)ranges, i * rangelen);
1966*10187SKrishna.Elango@Sun.COM 	}
1967*10187SKrishna.Elango@Sun.COM }
1968*10187SKrishna.Elango@Sun.COM 
1969*10187SKrishna.Elango@Sun.COM /*
1970*10187SKrishna.Elango@Sun.COM  * For PCI and PCI-X devices including PCIe2PCI bridge, initialize
1971*10187SKrishna.Elango@Sun.COM  * cache-line-size and latency timer configuration registers.
1972*10187SKrishna.Elango@Sun.COM  */
1973*10187SKrishna.Elango@Sun.COM void
1974*10187SKrishna.Elango@Sun.COM pcieb_set_pci_perf_parameters(dev_info_t *dip, ddi_acc_handle_t cfg_hdl)
1975*10187SKrishna.Elango@Sun.COM {
1976*10187SKrishna.Elango@Sun.COM 	uint_t	n;
1977*10187SKrishna.Elango@Sun.COM 
1978*10187SKrishna.Elango@Sun.COM 	/* Initialize cache-line-size configuration register if needed */
1979*10187SKrishna.Elango@Sun.COM 	if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1980*10187SKrishna.Elango@Sun.COM 	    "cache-line-size", 0) == 0) {
1981*10187SKrishna.Elango@Sun.COM 		pci_config_put8(cfg_hdl, PCI_CONF_CACHE_LINESZ,
1982*10187SKrishna.Elango@Sun.COM 		    PCIEB_CACHE_LINE_SIZE);
1983*10187SKrishna.Elango@Sun.COM 		n = pci_config_get8(cfg_hdl, PCI_CONF_CACHE_LINESZ);
1984*10187SKrishna.Elango@Sun.COM 		if (n != 0) {
1985*10187SKrishna.Elango@Sun.COM 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
1986*10187SKrishna.Elango@Sun.COM 			    "cache-line-size", n);
1987*10187SKrishna.Elango@Sun.COM 		}
1988*10187SKrishna.Elango@Sun.COM 	}
1989*10187SKrishna.Elango@Sun.COM 
1990*10187SKrishna.Elango@Sun.COM 	/* Initialize latency timer configuration registers if needed */
1991*10187SKrishna.Elango@Sun.COM 	if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1992*10187SKrishna.Elango@Sun.COM 	    "latency-timer", 0) == 0) {
1993*10187SKrishna.Elango@Sun.COM 		uchar_t	min_gnt, latency_timer;
1994*10187SKrishna.Elango@Sun.COM 		uchar_t header_type;
1995*10187SKrishna.Elango@Sun.COM 
1996*10187SKrishna.Elango@Sun.COM 		/* Determine the configuration header type */
1997*10187SKrishna.Elango@Sun.COM 		header_type = pci_config_get8(cfg_hdl, PCI_CONF_HEADER);
1998*10187SKrishna.Elango@Sun.COM 
1999*10187SKrishna.Elango@Sun.COM 		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
2000*10187SKrishna.Elango@Sun.COM 			latency_timer = PCIEB_LATENCY_TIMER;
2001*10187SKrishna.Elango@Sun.COM 			pci_config_put8(cfg_hdl, PCI_BCNF_LATENCY_TIMER,
2002*10187SKrishna.Elango@Sun.COM 			    latency_timer);
2003*10187SKrishna.Elango@Sun.COM 		} else {
2004*10187SKrishna.Elango@Sun.COM 			min_gnt = pci_config_get8(cfg_hdl, PCI_CONF_MIN_G);
2005*10187SKrishna.Elango@Sun.COM 			latency_timer = min_gnt * 8;
2006*10187SKrishna.Elango@Sun.COM 		}
2007*10187SKrishna.Elango@Sun.COM 
2008*10187SKrishna.Elango@Sun.COM 		pci_config_put8(cfg_hdl, PCI_CONF_LATENCY_TIMER,
2009*10187SKrishna.Elango@Sun.COM 		    latency_timer);
2010*10187SKrishna.Elango@Sun.COM 		n = pci_config_get8(cfg_hdl, PCI_CONF_LATENCY_TIMER);
2011*10187SKrishna.Elango@Sun.COM 		if (n != 0) {
2012*10187SKrishna.Elango@Sun.COM 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
2013*10187SKrishna.Elango@Sun.COM 			    "latency-timer", n);
2014*10187SKrishna.Elango@Sun.COM 		}
2015*10187SKrishna.Elango@Sun.COM 	}
2016*10187SKrishna.Elango@Sun.COM }
2017