xref: /onnv-gate/usr/src/uts/i86pc/io/pci/pci.c (revision 0)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  *	Host to PCI local bus driver
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/conf.h>
34*0Sstevel@tonic-gate #include <sys/kmem.h>
35*0Sstevel@tonic-gate #include <sys/debug.h>
36*0Sstevel@tonic-gate #include <sys/modctl.h>
37*0Sstevel@tonic-gate #include <sys/autoconf.h>
38*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
39*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
40*0Sstevel@tonic-gate #include <sys/pci.h>
41*0Sstevel@tonic-gate #include <sys/pci_impl.h>
42*0Sstevel@tonic-gate #include <sys/ddi.h>
43*0Sstevel@tonic-gate #include <sys/sunddi.h>
44*0Sstevel@tonic-gate #include <sys/sunndi.h>
45*0Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h>
46*0Sstevel@tonic-gate #include <sys/pci_cfgspace.h>
47*0Sstevel@tonic-gate #include <sys/avintr.h>
48*0Sstevel@tonic-gate #include <sys/psm.h>
49*0Sstevel@tonic-gate #include <sys/pci_intr_lib.h>
50*0Sstevel@tonic-gate #include <sys/policy.h>
51*0Sstevel@tonic-gate #include <sys/pci_tools.h>
52*0Sstevel@tonic-gate #include <sys/pci_tools_var.h>
53*0Sstevel@tonic-gate #include "pci_var.h"
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate /* Save minimal state. */
57*0Sstevel@tonic-gate void *pci_statep;
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /*
60*0Sstevel@tonic-gate  * Bus Operation functions
61*0Sstevel@tonic-gate  */
62*0Sstevel@tonic-gate static int	pci_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
63*0Sstevel@tonic-gate 		    off_t, off_t, caddr_t *);
64*0Sstevel@tonic-gate static int	pci_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
65*0Sstevel@tonic-gate 		    void *, void *);
66*0Sstevel@tonic-gate static int	pci_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
67*0Sstevel@tonic-gate 		    ddi_intr_handle_impl_t *, void *);
68*0Sstevel@tonic-gate static int	pci_get_priority(dev_info_t *, int, int *);
69*0Sstevel@tonic-gate static int	pci_get_nintrs(dev_info_t *, int, int *);
70*0Sstevel@tonic-gate static int	pci_enable_intr(dev_info_t *, dev_info_t *,
71*0Sstevel@tonic-gate 		    ddi_intr_handle_impl_t *, uint32_t);
72*0Sstevel@tonic-gate static void	pci_disable_intr(dev_info_t *, dev_info_t *,
73*0Sstevel@tonic-gate 		    ddi_intr_handle_impl_t *, uint32_t);
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate /* Extern decalrations */
76*0Sstevel@tonic-gate extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
77*0Sstevel@tonic-gate 		    psm_intr_op_t, int *);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate struct bus_ops pci_bus_ops = {
80*0Sstevel@tonic-gate 	BUSO_REV,
81*0Sstevel@tonic-gate 	pci_bus_map,
82*0Sstevel@tonic-gate 	NULL,
83*0Sstevel@tonic-gate 	NULL,
84*0Sstevel@tonic-gate 	NULL,
85*0Sstevel@tonic-gate 	i_ddi_map_fault,
86*0Sstevel@tonic-gate 	ddi_dma_map,
87*0Sstevel@tonic-gate 	ddi_dma_allochdl,
88*0Sstevel@tonic-gate 	ddi_dma_freehdl,
89*0Sstevel@tonic-gate 	ddi_dma_bindhdl,
90*0Sstevel@tonic-gate 	ddi_dma_unbindhdl,
91*0Sstevel@tonic-gate 	ddi_dma_flush,
92*0Sstevel@tonic-gate 	ddi_dma_win,
93*0Sstevel@tonic-gate 	ddi_dma_mctl,
94*0Sstevel@tonic-gate 	pci_ctlops,
95*0Sstevel@tonic-gate 	ddi_bus_prop_op,
96*0Sstevel@tonic-gate 	0,		/* (*bus_get_eventcookie)();	*/
97*0Sstevel@tonic-gate 	0,		/* (*bus_add_eventcall)();	*/
98*0Sstevel@tonic-gate 	0,		/* (*bus_remove_eventcall)();	*/
99*0Sstevel@tonic-gate 	0,		/* (*bus_post_event)();		*/
100*0Sstevel@tonic-gate 	0,		/* (*bus_intr_ctl)(); */
101*0Sstevel@tonic-gate 	0,		/* (*bus_config)(); */
102*0Sstevel@tonic-gate 	0,		/* (*bus_unconfig)(); */
103*0Sstevel@tonic-gate 	NULL,		/* (*bus_fm_init)(); */
104*0Sstevel@tonic-gate 	NULL,		/* (*bus_fm_fini)(); */
105*0Sstevel@tonic-gate 	NULL,		/* (*bus_fm_access_enter)(); */
106*0Sstevel@tonic-gate 	NULL,		/* (*bus_fm_access_exit)(); */
107*0Sstevel@tonic-gate 	NULL,		/* (*bus_power)(); */
108*0Sstevel@tonic-gate 	pci_intr_ops	/* (*bus_intr_op)(); */
109*0Sstevel@tonic-gate };
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate static int pci_open(dev_t *devp, int flags, int otyp, cred_t *credp);
112*0Sstevel@tonic-gate static int pci_close(dev_t dev, int flags, int otyp, cred_t *credp);
113*0Sstevel@tonic-gate static int pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
114*0Sstevel@tonic-gate     int *rvalp);
115*0Sstevel@tonic-gate static int pci_prop_op(dev_t dev, dev_info_t *devi, ddi_prop_op_t prop_op,
116*0Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp);
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate /*
119*0Sstevel@tonic-gate  * One goal here is to leverage off of the pcihp.c source without making
120*0Sstevel@tonic-gate  * changes to it.  Call into it's cb_ops directly if needed, piggybacking
121*0Sstevel@tonic-gate  * anything else needed by the pci_tools.c module.  Only pci_tools and pcihp
122*0Sstevel@tonic-gate  * will be using the PCI devctl node.
123*0Sstevel@tonic-gate  */
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate struct cb_ops pci_cb_ops = {
126*0Sstevel@tonic-gate 	pci_open,			/* open */
127*0Sstevel@tonic-gate 	pci_close,			/* close */
128*0Sstevel@tonic-gate 	nodev,				/* strategy */
129*0Sstevel@tonic-gate 	nodev,				/* print */
130*0Sstevel@tonic-gate 	nodev,				/* dump */
131*0Sstevel@tonic-gate 	nodev,				/* read */
132*0Sstevel@tonic-gate 	nodev,				/* write */
133*0Sstevel@tonic-gate 	pci_ioctl,			/* ioctl */
134*0Sstevel@tonic-gate 	nodev,				/* devmap */
135*0Sstevel@tonic-gate 	nodev,				/* mmap */
136*0Sstevel@tonic-gate 	nodev,				/* segmap */
137*0Sstevel@tonic-gate 	nochpoll,			/* poll */
138*0Sstevel@tonic-gate 	pci_prop_op,			/* cb_prop_op */
139*0Sstevel@tonic-gate 	NULL,				/* streamtab */
140*0Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
141*0Sstevel@tonic-gate 	CB_REV,				/* rev */
142*0Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
143*0Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
144*0Sstevel@tonic-gate };
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate /*
147*0Sstevel@tonic-gate  * Device Node Operation functions
148*0Sstevel@tonic-gate  */
149*0Sstevel@tonic-gate static int pci_info(dev_info_t *devi, ddi_info_cmd_t cmd, void *arg,
150*0Sstevel@tonic-gate     void **result);
151*0Sstevel@tonic-gate static int pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
152*0Sstevel@tonic-gate static int pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate struct dev_ops pci_ops = {
155*0Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
156*0Sstevel@tonic-gate 	0,			/* refcnt  */
157*0Sstevel@tonic-gate 	pci_info,		/* info */
158*0Sstevel@tonic-gate 	nulldev,		/* identify */
159*0Sstevel@tonic-gate 	nulldev,		/* probe */
160*0Sstevel@tonic-gate 	pci_attach,		/* attach */
161*0Sstevel@tonic-gate 	pci_detach,		/* detach */
162*0Sstevel@tonic-gate 	nulldev,		/* reset */
163*0Sstevel@tonic-gate 	&pci_cb_ops,		/* driver operations */
164*0Sstevel@tonic-gate 	&pci_bus_ops		/* bus operations */
165*0Sstevel@tonic-gate };
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate /*
168*0Sstevel@tonic-gate  * Internal routines in support of particular pci_ctlops.
169*0Sstevel@tonic-gate  */
170*0Sstevel@tonic-gate static int pci_removechild(dev_info_t *child);
171*0Sstevel@tonic-gate static int pci_initchild(dev_info_t *child);
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate /*
174*0Sstevel@tonic-gate  * Miscellaneous internal function
175*0Sstevel@tonic-gate  */
176*0Sstevel@tonic-gate static int pci_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp);
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate /*
179*0Sstevel@tonic-gate  * These are the access routines.  The pci_bus_map sets the handle
180*0Sstevel@tonic-gate  * to point to these.
181*0Sstevel@tonic-gate  */
182*0Sstevel@tonic-gate static uint8_t pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr);
183*0Sstevel@tonic-gate static uint16_t pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr);
184*0Sstevel@tonic-gate static uint32_t pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr);
185*0Sstevel@tonic-gate static uint64_t pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr);
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate static void pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr,
188*0Sstevel@tonic-gate 				uint8_t value);
189*0Sstevel@tonic-gate static void pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr,
190*0Sstevel@tonic-gate 				uint16_t value);
191*0Sstevel@tonic-gate static void pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr,
192*0Sstevel@tonic-gate 				uint32_t value);
193*0Sstevel@tonic-gate static void pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr,
194*0Sstevel@tonic-gate 				uint64_t value);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate static void pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
197*0Sstevel@tonic-gate 	uint8_t *dev_addr, size_t repcount, uint_t flags);
198*0Sstevel@tonic-gate static void pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
199*0Sstevel@tonic-gate 	uint16_t *dev_addr, size_t repcount, uint_t flags);
200*0Sstevel@tonic-gate static void pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
201*0Sstevel@tonic-gate 	uint32_t *dev_addr, size_t repcount, uint_t flags);
202*0Sstevel@tonic-gate static void pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
203*0Sstevel@tonic-gate 	uint64_t *dev_addr, size_t repcount, uint_t flags);
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate static void pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
206*0Sstevel@tonic-gate 	uint8_t *dev_addr, size_t repcount, uint_t flags);
207*0Sstevel@tonic-gate static void pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
208*0Sstevel@tonic-gate 	uint16_t *dev_addr, size_t repcount, uint_t flags);
209*0Sstevel@tonic-gate static void pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
210*0Sstevel@tonic-gate 	uint32_t *dev_addr, size_t repcount, uint_t flags);
211*0Sstevel@tonic-gate static void pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
212*0Sstevel@tonic-gate 	uint64_t *dev_addr, size_t repcount, uint_t flags);
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate /*
215*0Sstevel@tonic-gate  * Module linkage information for the kernel.
216*0Sstevel@tonic-gate  */
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate static struct modldrv modldrv = {
219*0Sstevel@tonic-gate 	&mod_driverops, /* Type of module */
220*0Sstevel@tonic-gate 	"host to PCI nexus driver %I%",
221*0Sstevel@tonic-gate 	&pci_ops,	/* driver ops */
222*0Sstevel@tonic-gate };
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
225*0Sstevel@tonic-gate 	MODREV_1,
226*0Sstevel@tonic-gate 	(void *)&modldrv,
227*0Sstevel@tonic-gate 	NULL
228*0Sstevel@tonic-gate };
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate int
231*0Sstevel@tonic-gate _init(void)
232*0Sstevel@tonic-gate {
233*0Sstevel@tonic-gate 	int e;
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	/*
236*0Sstevel@tonic-gate 	 * Initialize per-pci bus soft state pointer.
237*0Sstevel@tonic-gate 	 */
238*0Sstevel@tonic-gate 	e = ddi_soft_state_init(&pci_statep, sizeof (pci_state_t), 1);
239*0Sstevel@tonic-gate 	if (e != 0)
240*0Sstevel@tonic-gate 		return (e);
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) != 0)
243*0Sstevel@tonic-gate 		ddi_soft_state_fini(&pci_statep);
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	return (e);
246*0Sstevel@tonic-gate }
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate int
249*0Sstevel@tonic-gate _fini(void)
250*0Sstevel@tonic-gate {
251*0Sstevel@tonic-gate 	int rc;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	rc = mod_remove(&modlinkage);
254*0Sstevel@tonic-gate 	if (rc != 0)
255*0Sstevel@tonic-gate 		return (rc);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	ddi_soft_state_fini(&pci_statep);
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	return (rc);
260*0Sstevel@tonic-gate }
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate int
263*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
264*0Sstevel@tonic-gate {
265*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
266*0Sstevel@tonic-gate }
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate /*ARGSUSED*/
269*0Sstevel@tonic-gate static int
270*0Sstevel@tonic-gate pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
271*0Sstevel@tonic-gate {
272*0Sstevel@tonic-gate 	/*
273*0Sstevel@tonic-gate 	 * Use the minor number as constructed by pcihp, as the index value to
274*0Sstevel@tonic-gate 	 * ddi_soft_state_zalloc.
275*0Sstevel@tonic-gate 	 */
276*0Sstevel@tonic-gate 	int minor = DIP_TO_MINOR(devi);
277*0Sstevel@tonic-gate 	pci_state_t *pcip = NULL;
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci")
280*0Sstevel@tonic-gate 	    != DDI_PROP_SUCCESS) {
281*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "pci:  'device_type' prop create failed");
282*0Sstevel@tonic-gate 	}
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(pci_statep, minor) == DDI_SUCCESS) {
285*0Sstevel@tonic-gate 		pcip = ddi_get_soft_state(pci_statep, minor);
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	if (pcip == NULL) {
289*0Sstevel@tonic-gate 		return (DDI_FAILURE);
290*0Sstevel@tonic-gate 	}
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	pcip->pci_dip = devi;
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	/*
295*0Sstevel@tonic-gate 	 * Initialize hotplug support on this bus. At minimum
296*0Sstevel@tonic-gate 	 * (for non hotplug bus) this would create ":devctl" minor
297*0Sstevel@tonic-gate 	 * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls
298*0Sstevel@tonic-gate 	 * to this bus.
299*0Sstevel@tonic-gate 	 */
300*0Sstevel@tonic-gate 	if (pcihp_init(devi) != DDI_SUCCESS) {
301*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "pci: Failed to setup hotplug framework");
302*0Sstevel@tonic-gate 		ddi_soft_state_free(pci_statep, minor);
303*0Sstevel@tonic-gate 		return (DDI_FAILURE);
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	ddi_report_dev(devi);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate /*ARGSUSED*/
312*0Sstevel@tonic-gate static int
313*0Sstevel@tonic-gate pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
314*0Sstevel@tonic-gate {
315*0Sstevel@tonic-gate 	/*
316*0Sstevel@tonic-gate 	 * Uninitialize hotplug support on this bus.
317*0Sstevel@tonic-gate 	 */
318*0Sstevel@tonic-gate 	(void) pcihp_uninit(devi);
319*0Sstevel@tonic-gate 	ddi_soft_state_free(pci_statep, DIP_TO_MINOR(devi));
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate static int
325*0Sstevel@tonic-gate pci_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate 	pci_regspec_t *assigned_addr;
328*0Sstevel@tonic-gate 	int	assigned_addr_len;
329*0Sstevel@tonic-gate 	uint_t 	phys_hi;
330*0Sstevel@tonic-gate 	int	i;
331*0Sstevel@tonic-gate 	int 	rc;
332*0Sstevel@tonic-gate 	int 	number;
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	phys_hi = pci_rp->pci_phys_hi;
335*0Sstevel@tonic-gate 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
336*0Sstevel@tonic-gate 		(phys_hi & PCI_RELOCAT_B))
337*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	/*
340*0Sstevel@tonic-gate 	 * the "reg" property specifies relocatable, get and interpret the
341*0Sstevel@tonic-gate 	 * "assigned-addresses" property.
342*0Sstevel@tonic-gate 	 */
343*0Sstevel@tonic-gate 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
344*0Sstevel@tonic-gate 		DDI_PROP_DONTPASS, "assigned-addresses",
345*0Sstevel@tonic-gate 		(int **)&assigned_addr, (uint_t *)&assigned_addr_len);
346*0Sstevel@tonic-gate 	if (rc != DDI_PROP_SUCCESS)
347*0Sstevel@tonic-gate 		return (DDI_FAILURE);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	/*
350*0Sstevel@tonic-gate 	 * Scan the "assigned-addresses" for one that matches the specified
351*0Sstevel@tonic-gate 	 * "reg" property entry.
352*0Sstevel@tonic-gate 	 */
353*0Sstevel@tonic-gate 	phys_hi &= PCI_CONF_ADDR_MASK;
354*0Sstevel@tonic-gate 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
355*0Sstevel@tonic-gate 	for (i = 0; i < number; i++) {
356*0Sstevel@tonic-gate 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
357*0Sstevel@tonic-gate 				phys_hi) {
358*0Sstevel@tonic-gate 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
359*0Sstevel@tonic-gate 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
360*0Sstevel@tonic-gate 			ddi_prop_free(assigned_addr);
361*0Sstevel@tonic-gate 			return (DDI_SUCCESS);
362*0Sstevel@tonic-gate 		}
363*0Sstevel@tonic-gate 	}
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	ddi_prop_free(assigned_addr);
366*0Sstevel@tonic-gate 	return (DDI_FAILURE);
367*0Sstevel@tonic-gate }
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate static int
370*0Sstevel@tonic-gate pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
371*0Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *vaddrp)
372*0Sstevel@tonic-gate {
373*0Sstevel@tonic-gate 	struct regspec reg;
374*0Sstevel@tonic-gate 	ddi_map_req_t mr;
375*0Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
376*0Sstevel@tonic-gate 	ddi_acc_impl_t *ap;
377*0Sstevel@tonic-gate 	pci_regspec_t pci_reg;
378*0Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
379*0Sstevel@tonic-gate 	int 	rnumber;
380*0Sstevel@tonic-gate 	int	length;
381*0Sstevel@tonic-gate 	int	rc;
382*0Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
383*0Sstevel@tonic-gate 	int	space;
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	mr = *mp; /* Get private copy of request */
387*0Sstevel@tonic-gate 	mp = &mr;
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	/*
390*0Sstevel@tonic-gate 	 * check for register number
391*0Sstevel@tonic-gate 	 */
392*0Sstevel@tonic-gate 	switch (mp->map_type) {
393*0Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
394*0Sstevel@tonic-gate 		pci_reg = *(pci_regspec_t *)(mp->map_obj.rp);
395*0Sstevel@tonic-gate 		pci_rp = &pci_reg;
396*0Sstevel@tonic-gate 		if (pci_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
397*0Sstevel@tonic-gate 			return (DDI_FAILURE);
398*0Sstevel@tonic-gate 		break;
399*0Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
400*0Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
401*0Sstevel@tonic-gate 		/*
402*0Sstevel@tonic-gate 		 * get ALL "reg" properties for dip, select the one of
403*0Sstevel@tonic-gate 		 * of interest. In x86, "assigned-addresses" property
404*0Sstevel@tonic-gate 		 * is identical to the "reg" property, so there is no
405*0Sstevel@tonic-gate 		 * need to cross check the two to determine the physical
406*0Sstevel@tonic-gate 		 * address of the registers.
407*0Sstevel@tonic-gate 		 * This routine still performs some validity checks to
408*0Sstevel@tonic-gate 		 * make sure that everything is okay.
409*0Sstevel@tonic-gate 		 */
410*0Sstevel@tonic-gate 		rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
411*0Sstevel@tonic-gate 			DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
412*0Sstevel@tonic-gate 			(uint_t *)&length);
413*0Sstevel@tonic-gate 		if (rc != DDI_PROP_SUCCESS) {
414*0Sstevel@tonic-gate 			return (DDI_FAILURE);
415*0Sstevel@tonic-gate 		}
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 		/*
418*0Sstevel@tonic-gate 		 * validate the register number.
419*0Sstevel@tonic-gate 		 */
420*0Sstevel@tonic-gate 		length /= (sizeof (pci_regspec_t) / sizeof (int));
421*0Sstevel@tonic-gate 		if (rnumber >= length) {
422*0Sstevel@tonic-gate 			ddi_prop_free(pci_rp);
423*0Sstevel@tonic-gate 			return (DDI_FAILURE);
424*0Sstevel@tonic-gate 		}
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 		/*
427*0Sstevel@tonic-gate 		 * copy the required entry.
428*0Sstevel@tonic-gate 		 */
429*0Sstevel@tonic-gate 		pci_reg = pci_rp[rnumber];
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 		/*
432*0Sstevel@tonic-gate 		 * free the memory allocated by ddi_prop_lookup_int_array
433*0Sstevel@tonic-gate 		 */
434*0Sstevel@tonic-gate 		ddi_prop_free(pci_rp);
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 		pci_rp = &pci_reg;
437*0Sstevel@tonic-gate 		if (pci_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
438*0Sstevel@tonic-gate 			return (DDI_FAILURE);
439*0Sstevel@tonic-gate 		mp->map_type = DDI_MT_REGSPEC;
440*0Sstevel@tonic-gate 		break;
441*0Sstevel@tonic-gate 	default:
442*0Sstevel@tonic-gate 		return (DDI_ME_INVAL);
443*0Sstevel@tonic-gate 	}
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	/*
448*0Sstevel@tonic-gate 	 * check for unmap and unlock of address space
449*0Sstevel@tonic-gate 	 */
450*0Sstevel@tonic-gate 	if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) {
451*0Sstevel@tonic-gate 		/*
452*0Sstevel@tonic-gate 		 * Adjust offset and length
453*0Sstevel@tonic-gate 		 * A non-zero length means override the one in the regspec.
454*0Sstevel@tonic-gate 		 */
455*0Sstevel@tonic-gate 		pci_rp->pci_phys_low += (uint_t)offset;
456*0Sstevel@tonic-gate 		if (len != 0)
457*0Sstevel@tonic-gate 			pci_rp->pci_size_low = len;
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 		switch (space) {
460*0Sstevel@tonic-gate 		case PCI_ADDR_CONFIG:
461*0Sstevel@tonic-gate 			/* No work required on unmap of Config space */
462*0Sstevel@tonic-gate 			return (DDI_SUCCESS);
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 		case PCI_ADDR_IO:
465*0Sstevel@tonic-gate 			reg.regspec_bustype = 1;
466*0Sstevel@tonic-gate 			break;
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate 		case PCI_ADDR_MEM64:
469*0Sstevel@tonic-gate 			/*
470*0Sstevel@tonic-gate 			 * MEM64 requires special treatment on map, to check
471*0Sstevel@tonic-gate 			 * that the device is below 4G.  On unmap, however,
472*0Sstevel@tonic-gate 			 * we can assume that everything is OK... the map
473*0Sstevel@tonic-gate 			 * must have succeeded.
474*0Sstevel@tonic-gate 			 */
475*0Sstevel@tonic-gate 			/* FALLTHROUGH */
476*0Sstevel@tonic-gate 		case PCI_ADDR_MEM32:
477*0Sstevel@tonic-gate 			reg.regspec_bustype = 0;
478*0Sstevel@tonic-gate 			break;
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 		default:
481*0Sstevel@tonic-gate 			return (DDI_FAILURE);
482*0Sstevel@tonic-gate 		}
483*0Sstevel@tonic-gate 		reg.regspec_addr = pci_rp->pci_phys_low;
484*0Sstevel@tonic-gate 		reg.regspec_size = pci_rp->pci_size_low;
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 		mp->map_obj.rp = &reg;
487*0Sstevel@tonic-gate 		return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	}
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	/* check for user mapping request - not legal for Config */
492*0Sstevel@tonic-gate 	if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) {
493*0Sstevel@tonic-gate 		return (DDI_FAILURE);
494*0Sstevel@tonic-gate 	}
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	/*
497*0Sstevel@tonic-gate 	 * check for config space
498*0Sstevel@tonic-gate 	 * On x86, CONFIG is not mapped via MMU and there is
499*0Sstevel@tonic-gate 	 * no endian-ness issues. Set the attr field in the handle to
500*0Sstevel@tonic-gate 	 * indicate that the common routines to call the nexus driver.
501*0Sstevel@tonic-gate 	 */
502*0Sstevel@tonic-gate 	if (space == PCI_ADDR_CONFIG) {
503*0Sstevel@tonic-gate 		hp = (ddi_acc_hdl_t *)mp->map_handlep;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 		if (hp == NULL) {
506*0Sstevel@tonic-gate 			/* Can't map config space without a handle */
507*0Sstevel@tonic-gate 			return (DDI_FAILURE);
508*0Sstevel@tonic-gate 		}
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 		ap = (ddi_acc_impl_t *)hp->ah_platform_private;
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 		/* endian-ness check */
513*0Sstevel@tonic-gate 		if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
514*0Sstevel@tonic-gate 			return (DDI_FAILURE);
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 		/*
517*0Sstevel@tonic-gate 		 * range check
518*0Sstevel@tonic-gate 		 */
519*0Sstevel@tonic-gate 		if ((offset >= 256) || (len > 256) || (offset + len > 256))
520*0Sstevel@tonic-gate 			return (DDI_FAILURE);
521*0Sstevel@tonic-gate 		*vaddrp = (caddr_t)offset;
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 		ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
524*0Sstevel@tonic-gate 		ap->ahi_put8 = pci_config_wr8;
525*0Sstevel@tonic-gate 		ap->ahi_get8 = pci_config_rd8;
526*0Sstevel@tonic-gate 		ap->ahi_put64 = pci_config_wr64;
527*0Sstevel@tonic-gate 		ap->ahi_get64 = pci_config_rd64;
528*0Sstevel@tonic-gate 		ap->ahi_rep_put8 = pci_config_rep_wr8;
529*0Sstevel@tonic-gate 		ap->ahi_rep_get8 = pci_config_rep_rd8;
530*0Sstevel@tonic-gate 		ap->ahi_rep_put64 = pci_config_rep_wr64;
531*0Sstevel@tonic-gate 		ap->ahi_rep_get64 = pci_config_rep_rd64;
532*0Sstevel@tonic-gate 		ap->ahi_get16 = pci_config_rd16;
533*0Sstevel@tonic-gate 		ap->ahi_get32 = pci_config_rd32;
534*0Sstevel@tonic-gate 		ap->ahi_put16 = pci_config_wr16;
535*0Sstevel@tonic-gate 		ap->ahi_put32 = pci_config_wr32;
536*0Sstevel@tonic-gate 		ap->ahi_rep_get16 = pci_config_rep_rd16;
537*0Sstevel@tonic-gate 		ap->ahi_rep_get32 = pci_config_rep_rd32;
538*0Sstevel@tonic-gate 		ap->ahi_rep_put16 = pci_config_rep_wr16;
539*0Sstevel@tonic-gate 		ap->ahi_rep_put32 = pci_config_rep_wr32;
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 		/* Initialize to default check/notify functions */
542*0Sstevel@tonic-gate 		ap->ahi_fault_check = i_ddi_acc_fault_check;
543*0Sstevel@tonic-gate 		ap->ahi_fault_notify = i_ddi_acc_fault_notify;
544*0Sstevel@tonic-gate 		ap->ahi_fault = 0;
545*0Sstevel@tonic-gate 		impl_acc_err_init(hp);
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 		/* record the device address for future reference */
548*0Sstevel@tonic-gate 		cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private;
549*0Sstevel@tonic-gate 		cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
550*0Sstevel@tonic-gate 		cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
551*0Sstevel@tonic-gate 		cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	/*
557*0Sstevel@tonic-gate 	 * range check
558*0Sstevel@tonic-gate 	 */
559*0Sstevel@tonic-gate 	if ((offset >= pci_rp->pci_size_low) ||
560*0Sstevel@tonic-gate 	    (len > pci_rp->pci_size_low) ||
561*0Sstevel@tonic-gate 	    (offset + len > pci_rp->pci_size_low)) {
562*0Sstevel@tonic-gate 		return (DDI_FAILURE);
563*0Sstevel@tonic-gate 	}
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	/*
566*0Sstevel@tonic-gate 	 * Adjust offset and length
567*0Sstevel@tonic-gate 	 * A non-zero length means override the one in the regspec.
568*0Sstevel@tonic-gate 	 */
569*0Sstevel@tonic-gate 	pci_rp->pci_phys_low += (uint_t)offset;
570*0Sstevel@tonic-gate 	if (len != 0)
571*0Sstevel@tonic-gate 		pci_rp->pci_size_low = len;
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	/*
574*0Sstevel@tonic-gate 	 * convert the pci regsec into the generic regspec used by the
575*0Sstevel@tonic-gate 	 * parent root nexus driver.
576*0Sstevel@tonic-gate 	 */
577*0Sstevel@tonic-gate 	switch (space) {
578*0Sstevel@tonic-gate 	case PCI_ADDR_IO:
579*0Sstevel@tonic-gate 		reg.regspec_bustype = 1;
580*0Sstevel@tonic-gate 		break;
581*0Sstevel@tonic-gate 	case PCI_ADDR_MEM64:
582*0Sstevel@tonic-gate 		/*
583*0Sstevel@tonic-gate 		 * We can't handle 64-bit devices that are mapped above
584*0Sstevel@tonic-gate 		 * 4G or that are larger than 4G.
585*0Sstevel@tonic-gate 		 */
586*0Sstevel@tonic-gate 		if (pci_rp->pci_phys_mid != 0 ||
587*0Sstevel@tonic-gate 		    pci_rp->pci_size_hi != 0)
588*0Sstevel@tonic-gate 			return (DDI_FAILURE);
589*0Sstevel@tonic-gate 		/*
590*0Sstevel@tonic-gate 		 * Other than that, we can treat them as 32-bit mappings
591*0Sstevel@tonic-gate 		 */
592*0Sstevel@tonic-gate 		/* FALLTHROUGH */
593*0Sstevel@tonic-gate 	case PCI_ADDR_MEM32:
594*0Sstevel@tonic-gate 		reg.regspec_bustype = 0;
595*0Sstevel@tonic-gate 		break;
596*0Sstevel@tonic-gate 	default:
597*0Sstevel@tonic-gate 		return (DDI_FAILURE);
598*0Sstevel@tonic-gate 	}
599*0Sstevel@tonic-gate 	reg.regspec_addr = pci_rp->pci_phys_low;
600*0Sstevel@tonic-gate 	reg.regspec_size = pci_rp->pci_size_low;
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	mp->map_obj.rp = &reg;
603*0Sstevel@tonic-gate 	return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
604*0Sstevel@tonic-gate }
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate /*
608*0Sstevel@tonic-gate  * pci_get_priority:
609*0Sstevel@tonic-gate  *	Figure out the priority of the device
610*0Sstevel@tonic-gate  */
611*0Sstevel@tonic-gate static int
612*0Sstevel@tonic-gate pci_get_priority(dev_info_t *dip, int inum, int *pri)
613*0Sstevel@tonic-gate {
614*0Sstevel@tonic-gate 	struct intrspec *ispec;
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p\n",
617*0Sstevel@tonic-gate 	    (void *)dip));
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, inum)) ==
620*0Sstevel@tonic-gate 	    NULL)
621*0Sstevel@tonic-gate 		return (DDI_FAILURE);
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	*pri = ispec->intrspec_pri;
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
626*0Sstevel@tonic-gate }
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate /*
630*0Sstevel@tonic-gate  * pci_get_nintrs:
631*0Sstevel@tonic-gate  *	Figure out how many interrupts the device supports
632*0Sstevel@tonic-gate  */
633*0Sstevel@tonic-gate static int
634*0Sstevel@tonic-gate pci_get_nintrs(dev_info_t *dip, int type, int *nintrs)
635*0Sstevel@tonic-gate {
636*0Sstevel@tonic-gate 	int	ret;
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	*nintrs = 0;
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	if (DDI_INTR_IS_MSI_OR_MSIX(type))
641*0Sstevel@tonic-gate 		ret = pci_msi_get_nintrs(dip, type, nintrs);
642*0Sstevel@tonic-gate 	else {
643*0Sstevel@tonic-gate 		ret = DDI_FAILURE;
644*0Sstevel@tonic-gate 		if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
645*0Sstevel@tonic-gate 		    "interrupts", -1) != -1) {
646*0Sstevel@tonic-gate 			*nintrs = 1;
647*0Sstevel@tonic-gate 			ret = DDI_SUCCESS;
648*0Sstevel@tonic-gate 		}
649*0Sstevel@tonic-gate 	}
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 	return (ret);
652*0Sstevel@tonic-gate }
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate /*
656*0Sstevel@tonic-gate  * pci_intr_ops: bus_intr_op() function for interrupt support
657*0Sstevel@tonic-gate  */
658*0Sstevel@tonic-gate /* ARGSUSED */
659*0Sstevel@tonic-gate static int
660*0Sstevel@tonic-gate pci_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
661*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
662*0Sstevel@tonic-gate {
663*0Sstevel@tonic-gate 	int			priority = 0;
664*0Sstevel@tonic-gate 	int			psm_status = 0;
665*0Sstevel@tonic-gate 	int			pci_status = 0;
666*0Sstevel@tonic-gate 	int			pci_rval, psm_rval = PSM_FAILURE;
667*0Sstevel@tonic-gate 	int			types = 0;
668*0Sstevel@tonic-gate 	int			i, j;
669*0Sstevel@tonic-gate 	int			behavior;
670*0Sstevel@tonic-gate 	ddi_intrspec_t		isp;
671*0Sstevel@tonic-gate 	struct intrspec		*ispec;
672*0Sstevel@tonic-gate 	ddi_intr_handle_impl_t	tmp_hdl;
673*0Sstevel@tonic-gate 	ddi_intr_msix_t		*msix_p;
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	DDI_INTR_NEXDBG((CE_CONT,
676*0Sstevel@tonic-gate 	    "pci_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
677*0Sstevel@tonic-gate 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	/* Process the request */
680*0Sstevel@tonic-gate 	switch (intr_op) {
681*0Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
682*0Sstevel@tonic-gate 		/* Fixed supported by default */
683*0Sstevel@tonic-gate 		*(int *)result = DDI_INTR_TYPE_FIXED;
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 		/* Figure out if MSI or MSI-X is supported? */
686*0Sstevel@tonic-gate 		if (pci_msi_get_supported_type(rdip, &types) != DDI_SUCCESS)
687*0Sstevel@tonic-gate 			return (DDI_SUCCESS);
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 		if (psm_intr_ops != NULL) {
690*0Sstevel@tonic-gate 			/* MSI or MSI-X is supported, OR it in */
691*0Sstevel@tonic-gate 			*(int *)result |= types;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 			tmp_hdl.ih_type = *(int *)result;
694*0Sstevel@tonic-gate 			(void) (*psm_intr_ops)(rdip, &tmp_hdl,
695*0Sstevel@tonic-gate 			    PSM_INTR_OP_CHECK_MSI, result);
696*0Sstevel@tonic-gate 			DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: rdip: 0x%p "
697*0Sstevel@tonic-gate 			    "supported types: 0x%x\n", (void *)rdip,
698*0Sstevel@tonic-gate 			    *(int *)result));
699*0Sstevel@tonic-gate 		}
700*0Sstevel@tonic-gate 		break;
701*0Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
702*0Sstevel@tonic-gate 		if (pci_get_nintrs(rdip, hdlp->ih_type, result) != DDI_SUCCESS)
703*0Sstevel@tonic-gate 			return (DDI_FAILURE);
704*0Sstevel@tonic-gate 		break;
705*0Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
706*0Sstevel@tonic-gate 		/*
707*0Sstevel@tonic-gate 		 * MSI or MSIX (figure out number of vectors available)
708*0Sstevel@tonic-gate 		 * FIXED interrupts: just return available interrupts
709*0Sstevel@tonic-gate 		 */
710*0Sstevel@tonic-gate 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
711*0Sstevel@tonic-gate 		    (psm_intr_ops != NULL) &&
712*0Sstevel@tonic-gate 		    (pci_get_priority(rdip, hdlp->ih_inum,
713*0Sstevel@tonic-gate 		    &priority) == DDI_SUCCESS)) {
714*0Sstevel@tonic-gate 			hdlp->ih_pri = priority;
715*0Sstevel@tonic-gate 			behavior = hdlp->ih_scratch2;
716*0Sstevel@tonic-gate 			(void) (*psm_intr_ops)(rdip, hdlp,
717*0Sstevel@tonic-gate 			    PSM_INTR_OP_ALLOC_VECTORS, result);
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 			/* verify behavior flag and take appropriate action */
720*0Sstevel@tonic-gate 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
721*0Sstevel@tonic-gate 			    (*(int *)result < hdlp->ih_scratch1)) {
722*0Sstevel@tonic-gate 				DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: "
723*0Sstevel@tonic-gate 				    "behavior %x, couldn't get enough intrs\n",
724*0Sstevel@tonic-gate 				    behavior));
725*0Sstevel@tonic-gate 				hdlp->ih_scratch1 = *(int *)result;
726*0Sstevel@tonic-gate 				(void) (*psm_intr_ops)(rdip, hdlp,
727*0Sstevel@tonic-gate 				    PSM_INTR_OP_FREE_VECTORS, NULL);
728*0Sstevel@tonic-gate 				return (DDI_EAGAIN);
729*0Sstevel@tonic-gate 			}
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
732*0Sstevel@tonic-gate 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
733*0Sstevel@tonic-gate 					msix_p = pci_msix_init(hdlp->ih_dip);
734*0Sstevel@tonic-gate 					if (msix_p)
735*0Sstevel@tonic-gate 						i_ddi_set_msix(hdlp->ih_dip,
736*0Sstevel@tonic-gate 						    msix_p);
737*0Sstevel@tonic-gate 				}
738*0Sstevel@tonic-gate 				msix_p->msix_intrs_in_use += *(int *)result;
739*0Sstevel@tonic-gate 			}
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
742*0Sstevel@tonic-gate 			/* Figure out if this device supports MASKING */
743*0Sstevel@tonic-gate 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
744*0Sstevel@tonic-gate 			if (pci_rval == DDI_SUCCESS && pci_status)
745*0Sstevel@tonic-gate 				hdlp->ih_cap |= pci_status;
746*0Sstevel@tonic-gate 			*(int *)result = 1;	/* DDI_INTR_TYPE_FIXED */
747*0Sstevel@tonic-gate 		} else
748*0Sstevel@tonic-gate 			return (DDI_FAILURE);
749*0Sstevel@tonic-gate 		break;
750*0Sstevel@tonic-gate 	case DDI_INTROP_FREE:
751*0Sstevel@tonic-gate 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
752*0Sstevel@tonic-gate 		    (psm_intr_ops != NULL)) {
753*0Sstevel@tonic-gate 			(void) (*psm_intr_ops)(rdip, hdlp,
754*0Sstevel@tonic-gate 			    PSM_INTR_OP_FREE_VECTORS, NULL);
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
757*0Sstevel@tonic-gate 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
758*0Sstevel@tonic-gate 				if (msix_p &&
759*0Sstevel@tonic-gate 				    --msix_p->msix_intrs_in_use == 0) {
760*0Sstevel@tonic-gate 					pci_msix_fini(msix_p);
761*0Sstevel@tonic-gate 					i_ddi_set_msix(hdlp->ih_dip, NULL);
762*0Sstevel@tonic-gate 				}
763*0Sstevel@tonic-gate 			}
764*0Sstevel@tonic-gate 		}
765*0Sstevel@tonic-gate 		break;
766*0Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
767*0Sstevel@tonic-gate 		if (pci_get_priority(rdip, hdlp->ih_inum, &priority) !=
768*0Sstevel@tonic-gate 		    DDI_SUCCESS)	/* Get the priority */
769*0Sstevel@tonic-gate 			return (DDI_FAILURE);
770*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: priority = 0x%x\n",
771*0Sstevel@tonic-gate 		    priority));
772*0Sstevel@tonic-gate 		*(int *)result = priority;
773*0Sstevel@tonic-gate 		break;
774*0Sstevel@tonic-gate 	case DDI_INTROP_SETPRI:
775*0Sstevel@tonic-gate 		/* Validate the interrupt priority passed */
776*0Sstevel@tonic-gate 		if (*(int *)result > LOCK_LEVEL)
777*0Sstevel@tonic-gate 			return (DDI_FAILURE);
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate 		/* Ensure that PSM is all initialized */
780*0Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
781*0Sstevel@tonic-gate 			return (DDI_FAILURE);
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 		/* Change the priority */
784*0Sstevel@tonic-gate 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
785*0Sstevel@tonic-gate 		    PSM_FAILURE)
786*0Sstevel@tonic-gate 			return (DDI_FAILURE);
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 		/* update ispec */
789*0Sstevel@tonic-gate 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
790*0Sstevel@tonic-gate 		ispec = (struct intrspec *)isp;
791*0Sstevel@tonic-gate 		ispec->intrspec_pri = *(int *)result;
792*0Sstevel@tonic-gate 		break;
793*0Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
794*0Sstevel@tonic-gate 		/* update ispec */
795*0Sstevel@tonic-gate 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
796*0Sstevel@tonic-gate 		ispec = (struct intrspec *)isp;
797*0Sstevel@tonic-gate 		ispec->intrspec_func = hdlp->ih_cb_func;
798*0Sstevel@tonic-gate 		break;
799*0Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
800*0Sstevel@tonic-gate 		/* Get the interrupt structure pointer */
801*0Sstevel@tonic-gate 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
802*0Sstevel@tonic-gate 		ispec = (struct intrspec *)isp;
803*0Sstevel@tonic-gate 		ispec->intrspec_func = (uint_t (*)()) 0;
804*0Sstevel@tonic-gate 		break;
805*0Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
806*0Sstevel@tonic-gate 		/*
807*0Sstevel@tonic-gate 		 * First check the config space and/or
808*0Sstevel@tonic-gate 		 * MSI capability register(s)
809*0Sstevel@tonic-gate 		 */
810*0Sstevel@tonic-gate 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
811*0Sstevel@tonic-gate 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
812*0Sstevel@tonic-gate 			    &pci_status);
813*0Sstevel@tonic-gate 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
814*0Sstevel@tonic-gate 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate 		/* next check with pcplusmp */
817*0Sstevel@tonic-gate 		if (psm_intr_ops != NULL)
818*0Sstevel@tonic-gate 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
819*0Sstevel@tonic-gate 			    PSM_INTR_OP_GET_CAP, &psm_status);
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
822*0Sstevel@tonic-gate 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
823*0Sstevel@tonic-gate 		    psm_rval, psm_status, pci_rval, pci_status));
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
826*0Sstevel@tonic-gate 			*(int *)result = 0;
827*0Sstevel@tonic-gate 			return (DDI_FAILURE);
828*0Sstevel@tonic-gate 		}
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 		if (psm_rval == PSM_SUCCESS)
831*0Sstevel@tonic-gate 			*(int *)result = psm_status;
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 		if (pci_rval == DDI_SUCCESS)
834*0Sstevel@tonic-gate 			*(int *)result |= pci_status;
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
837*0Sstevel@tonic-gate 		    *(int *)result));
838*0Sstevel@tonic-gate 		break;
839*0Sstevel@tonic-gate 	case DDI_INTROP_SETCAP:
840*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: SETCAP cap=0x%x\n",
841*0Sstevel@tonic-gate 		    *(int *)result));
842*0Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
843*0Sstevel@tonic-gate 			return (DDI_FAILURE);
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
846*0Sstevel@tonic-gate 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
847*0Sstevel@tonic-gate 			    " returned failure\n"));
848*0Sstevel@tonic-gate 			return (DDI_FAILURE);
849*0Sstevel@tonic-gate 		}
850*0Sstevel@tonic-gate 		break;
851*0Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
852*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: ENABLE\n"));
853*0Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
854*0Sstevel@tonic-gate 			return (DDI_FAILURE);
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
857*0Sstevel@tonic-gate 		    DDI_SUCCESS)
858*0Sstevel@tonic-gate 			return (DDI_FAILURE);
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: ENABLE vector=0x%x\n",
861*0Sstevel@tonic-gate 		    hdlp->ih_vector));
862*0Sstevel@tonic-gate 		break;
863*0Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
864*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: DISABLE\n"));
865*0Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
866*0Sstevel@tonic-gate 			return (DDI_FAILURE);
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
869*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: DISABLE vector = %x\n",
870*0Sstevel@tonic-gate 		    hdlp->ih_vector));
871*0Sstevel@tonic-gate 		break;
872*0Sstevel@tonic-gate 	case DDI_INTROP_BLOCKENABLE:
873*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: BLOCKENABLE\n"));
874*0Sstevel@tonic-gate 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
875*0Sstevel@tonic-gate 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
876*0Sstevel@tonic-gate 			return (DDI_FAILURE);
877*0Sstevel@tonic-gate 		}
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 		/* Check if psm_intr_ops is NULL? */
880*0Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
881*0Sstevel@tonic-gate 			return (DDI_FAILURE);
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 		for (i = 0; i < hdlp->ih_scratch1; i++) {
884*0Sstevel@tonic-gate 			if (pci_enable_intr(pdip, rdip, hdlp,
885*0Sstevel@tonic-gate 			    hdlp->ih_inum + i) != DDI_SUCCESS) {
886*0Sstevel@tonic-gate 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
887*0Sstevel@tonic-gate 				    "pci_enable_intr failed for %d\n", i));
888*0Sstevel@tonic-gate 				for (j = 0; j < i; j++)
889*0Sstevel@tonic-gate 					pci_disable_intr(pdip, rdip, hdlp,
890*0Sstevel@tonic-gate 					    hdlp->ih_inum + j);
891*0Sstevel@tonic-gate 				return (DDI_FAILURE);
892*0Sstevel@tonic-gate 			}
893*0Sstevel@tonic-gate 			DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: BLOCKENABLE "
894*0Sstevel@tonic-gate 			    "inum %x done\n", hdlp->ih_inum + i));
895*0Sstevel@tonic-gate 		}
896*0Sstevel@tonic-gate 		break;
897*0Sstevel@tonic-gate 	case DDI_INTROP_BLOCKDISABLE:
898*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: BLOCKDISABLE\n"));
899*0Sstevel@tonic-gate 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
900*0Sstevel@tonic-gate 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
901*0Sstevel@tonic-gate 			return (DDI_FAILURE);
902*0Sstevel@tonic-gate 		}
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate 		/* Check if psm_intr_ops is present */
905*0Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
906*0Sstevel@tonic-gate 			return (DDI_FAILURE);
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate 		for (i = 0; i < hdlp->ih_scratch1; i++) {
909*0Sstevel@tonic-gate 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum + i);
910*0Sstevel@tonic-gate 			DDI_INTR_NEXDBG((CE_CONT, "pci_intr_ops: BLOCKDISABLE "
911*0Sstevel@tonic-gate 			    "inum %x done\n", hdlp->ih_inum + i));
912*0Sstevel@tonic-gate 		}
913*0Sstevel@tonic-gate 		break;
914*0Sstevel@tonic-gate 	case DDI_INTROP_SETMASK:
915*0Sstevel@tonic-gate 	case DDI_INTROP_CLRMASK:
916*0Sstevel@tonic-gate 		/*
917*0Sstevel@tonic-gate 		 * First handle in the config space
918*0Sstevel@tonic-gate 		 */
919*0Sstevel@tonic-gate 		if (intr_op == DDI_INTROP_SETMASK) {
920*0Sstevel@tonic-gate 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
921*0Sstevel@tonic-gate 				pci_status = pci_msi_set_mask(rdip,
922*0Sstevel@tonic-gate 				    hdlp->ih_type, hdlp->ih_inum);
923*0Sstevel@tonic-gate 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
924*0Sstevel@tonic-gate 				pci_status = pci_intx_set_mask(rdip);
925*0Sstevel@tonic-gate 		} else {
926*0Sstevel@tonic-gate 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
927*0Sstevel@tonic-gate 				pci_status = pci_msi_clr_mask(rdip,
928*0Sstevel@tonic-gate 				    hdlp->ih_type, hdlp->ih_inum);
929*0Sstevel@tonic-gate 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
930*0Sstevel@tonic-gate 				pci_status = pci_intx_clr_mask(rdip);
931*0Sstevel@tonic-gate 		}
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 		/* For MSI/X; no need to check with pcplusmp */
934*0Sstevel@tonic-gate 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
935*0Sstevel@tonic-gate 			return (pci_status);
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 		/* For fixed interrupts only: handle config space first */
938*0Sstevel@tonic-gate 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
939*0Sstevel@tonic-gate 		    pci_status == DDI_SUCCESS)
940*0Sstevel@tonic-gate 			break;
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 		/* For fixed interrupts only: confer with pcplusmp next */
943*0Sstevel@tonic-gate 		if (psm_intr_ops != NULL) {
944*0Sstevel@tonic-gate 			/* If interrupt is shared; do nothing */
945*0Sstevel@tonic-gate 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
946*0Sstevel@tonic-gate 			    PSM_INTR_OP_GET_SHARED, &psm_status);
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 			if (psm_rval == PSM_FAILURE || psm_status == 1)
949*0Sstevel@tonic-gate 				return (pci_status);
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 			/* Now, pcplusmp should try to set/clear the mask */
952*0Sstevel@tonic-gate 			if (intr_op == DDI_INTROP_SETMASK)
953*0Sstevel@tonic-gate 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
954*0Sstevel@tonic-gate 				    PSM_INTR_OP_SET_MASK, NULL);
955*0Sstevel@tonic-gate 			else
956*0Sstevel@tonic-gate 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
957*0Sstevel@tonic-gate 				    PSM_INTR_OP_CLEAR_MASK, NULL);
958*0Sstevel@tonic-gate 		}
959*0Sstevel@tonic-gate 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
960*0Sstevel@tonic-gate 	case DDI_INTROP_GETPENDING:
961*0Sstevel@tonic-gate 		/*
962*0Sstevel@tonic-gate 		 * First check the config space and/or
963*0Sstevel@tonic-gate 		 * MSI capability register(s)
964*0Sstevel@tonic-gate 		 */
965*0Sstevel@tonic-gate 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
966*0Sstevel@tonic-gate 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
967*0Sstevel@tonic-gate 			    hdlp->ih_inum, &pci_status);
968*0Sstevel@tonic-gate 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
969*0Sstevel@tonic-gate 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 		/* On failure; next try with pcplusmp */
972*0Sstevel@tonic-gate 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
973*0Sstevel@tonic-gate 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
974*0Sstevel@tonic-gate 			    PSM_INTR_OP_GET_PENDING, &psm_status);
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
977*0Sstevel@tonic-gate 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
978*0Sstevel@tonic-gate 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
979*0Sstevel@tonic-gate 		    pci_status));
980*0Sstevel@tonic-gate 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
981*0Sstevel@tonic-gate 			*(int *)result = 0;
982*0Sstevel@tonic-gate 			return (DDI_FAILURE);
983*0Sstevel@tonic-gate 		}
984*0Sstevel@tonic-gate 
985*0Sstevel@tonic-gate 		if (psm_rval != PSM_FAILURE)
986*0Sstevel@tonic-gate 			*(int *)result = psm_status;
987*0Sstevel@tonic-gate 		else if (pci_rval != DDI_FAILURE)
988*0Sstevel@tonic-gate 			*(int *)result = pci_status;
989*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
990*0Sstevel@tonic-gate 		    *(int *)result));
991*0Sstevel@tonic-gate 		break;
992*0Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
993*0Sstevel@tonic-gate 		if ((psm_intr_ops != NULL) && (pci_get_priority(rdip,
994*0Sstevel@tonic-gate 		    hdlp->ih_inum, &priority) == DDI_SUCCESS)) {
995*0Sstevel@tonic-gate 			/* Priority in the handle not initialized yet */
996*0Sstevel@tonic-gate 			hdlp->ih_pri = priority;
997*0Sstevel@tonic-gate 			(void) (*psm_intr_ops)(rdip, hdlp,
998*0Sstevel@tonic-gate 			    PSM_INTR_OP_NAVAIL_VECTORS, result);
999*0Sstevel@tonic-gate 		} else {
1000*0Sstevel@tonic-gate 			*(int *)result = 1;
1001*0Sstevel@tonic-gate 		}
1002*0Sstevel@tonic-gate 		DDI_INTR_NEXDBG((CE_CONT, "pci: NAVAIL returned = %x\n",
1003*0Sstevel@tonic-gate 		    *(int *)result));
1004*0Sstevel@tonic-gate 		break;
1005*0Sstevel@tonic-gate 	default:
1006*0Sstevel@tonic-gate 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
1007*0Sstevel@tonic-gate 	}
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1010*0Sstevel@tonic-gate }
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate static int
1014*0Sstevel@tonic-gate pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
1015*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
1016*0Sstevel@tonic-gate {
1017*0Sstevel@tonic-gate 	int		vector;
1018*0Sstevel@tonic-gate 	struct intrspec	*ispec;
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
1021*0Sstevel@tonic-gate 	    (void *)hdlp, inum));
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	/* Translate the interrupt if needed */
1024*0Sstevel@tonic-gate 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
1025*0Sstevel@tonic-gate 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
1026*0Sstevel@tonic-gate 		ispec->intrspec_vec = inum;
1027*0Sstevel@tonic-gate 	hdlp->ih_private = (void *)ispec;
1028*0Sstevel@tonic-gate 
1029*0Sstevel@tonic-gate 	/* translate the interrupt if needed */
1030*0Sstevel@tonic-gate 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &vector);
1031*0Sstevel@tonic-gate 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x vector=%x\n",
1032*0Sstevel@tonic-gate 	    hdlp->ih_pri, vector));
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate 	/* Add the interrupt handler */
1035*0Sstevel@tonic-gate 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
1036*0Sstevel@tonic-gate 	    DEVI(rdip)->devi_name, vector, hdlp->ih_cb_arg1,
1037*0Sstevel@tonic-gate 	    hdlp->ih_cb_arg2, rdip))
1038*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1039*0Sstevel@tonic-gate 
1040*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1041*0Sstevel@tonic-gate }
1042*0Sstevel@tonic-gate 
1043*0Sstevel@tonic-gate 
1044*0Sstevel@tonic-gate static void
1045*0Sstevel@tonic-gate pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
1046*0Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
1047*0Sstevel@tonic-gate {
1048*0Sstevel@tonic-gate 	int		vector;
1049*0Sstevel@tonic-gate 	struct intrspec	*ispec;
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
1052*0Sstevel@tonic-gate 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
1053*0Sstevel@tonic-gate 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
1054*0Sstevel@tonic-gate 		ispec->intrspec_vec = inum;
1055*0Sstevel@tonic-gate 	hdlp->ih_private = (void *)ispec;
1056*0Sstevel@tonic-gate 
1057*0Sstevel@tonic-gate 	/* translate the interrupt if needed */
1058*0Sstevel@tonic-gate 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &vector);
1059*0Sstevel@tonic-gate 
1060*0Sstevel@tonic-gate 	/* Disable the interrupt handler */
1061*0Sstevel@tonic-gate 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, vector);
1062*0Sstevel@tonic-gate }
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 
1065*0Sstevel@tonic-gate /*ARGSUSED*/
1066*0Sstevel@tonic-gate static int
1067*0Sstevel@tonic-gate pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
1068*0Sstevel@tonic-gate 	ddi_ctl_enum_t ctlop, void *arg, void *result)
1069*0Sstevel@tonic-gate {
1070*0Sstevel@tonic-gate 	pci_regspec_t *drv_regp;
1071*0Sstevel@tonic-gate 	uint_t	reglen;
1072*0Sstevel@tonic-gate 	int	rn;
1073*0Sstevel@tonic-gate 	int	totreg;
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	switch (ctlop) {
1076*0Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
1077*0Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
1078*0Sstevel@tonic-gate 			return (DDI_FAILURE);
1079*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
1080*0Sstevel@tonic-gate 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
1081*0Sstevel@tonic-gate 		    ddi_driver_name(rdip),
1082*0Sstevel@tonic-gate 		    ddi_get_instance(rdip));
1083*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
1086*0Sstevel@tonic-gate 		return (pci_initchild((dev_info_t *)arg));
1087*0Sstevel@tonic-gate 
1088*0Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
1089*0Sstevel@tonic-gate 		return (pci_removechild((dev_info_t *)arg));
1090*0Sstevel@tonic-gate 
1091*0Sstevel@tonic-gate 	case DDI_CTLOPS_NINTRS:
1092*0Sstevel@tonic-gate 		if (ddi_get_parent_data(rdip))
1093*0Sstevel@tonic-gate 			*(int *)result = 1;
1094*0Sstevel@tonic-gate 		else
1095*0Sstevel@tonic-gate 			*(int *)result = 0;
1096*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	case DDI_CTLOPS_XLATE_INTRS:
1099*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
1102*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
1105*0Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
1106*0Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
1107*0Sstevel@tonic-gate 			return (DDI_FAILURE);
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 		*(int *)result = 0;
1110*0Sstevel@tonic-gate 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
1111*0Sstevel@tonic-gate 				DDI_PROP_DONTPASS, "reg", (int **)&drv_regp,
1112*0Sstevel@tonic-gate 				&reglen) != DDI_PROP_SUCCESS) {
1113*0Sstevel@tonic-gate 			return (DDI_FAILURE);
1114*0Sstevel@tonic-gate 		}
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate 		totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t);
1117*0Sstevel@tonic-gate 		if (ctlop == DDI_CTLOPS_NREGS)
1118*0Sstevel@tonic-gate 			*(int *)result = totreg;
1119*0Sstevel@tonic-gate 		else if (ctlop == DDI_CTLOPS_REGSIZE) {
1120*0Sstevel@tonic-gate 			rn = *(int *)arg;
1121*0Sstevel@tonic-gate 			if (rn >= totreg) {
1122*0Sstevel@tonic-gate 				ddi_prop_free(drv_regp);
1123*0Sstevel@tonic-gate 				return (DDI_FAILURE);
1124*0Sstevel@tonic-gate 			}
1125*0Sstevel@tonic-gate 			*(off_t *)result = drv_regp[rn].pci_size_low;
1126*0Sstevel@tonic-gate 		}
1127*0Sstevel@tonic-gate 		ddi_prop_free(drv_regp);
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate 	case DDI_CTLOPS_POWER: {
1132*0Sstevel@tonic-gate 		power_req_t	*reqp = (power_req_t *)arg;
1133*0Sstevel@tonic-gate 		/*
1134*0Sstevel@tonic-gate 		 * We currently understand reporting of PCI_PM_IDLESPEED
1135*0Sstevel@tonic-gate 		 * capability. Everything else is passed up.
1136*0Sstevel@tonic-gate 		 */
1137*0Sstevel@tonic-gate 		if ((reqp->request_type == PMR_REPORT_PMCAP) &&
1138*0Sstevel@tonic-gate 		    (reqp->req.report_pmcap_req.cap ==  PCI_PM_IDLESPEED)) {
1139*0Sstevel@tonic-gate 
1140*0Sstevel@tonic-gate 			return (DDI_SUCCESS);
1141*0Sstevel@tonic-gate 		}
1142*0Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1143*0Sstevel@tonic-gate 	}
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 	default:
1146*0Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1147*0Sstevel@tonic-gate 	}
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate 	/* NOTREACHED */
1150*0Sstevel@tonic-gate 
1151*0Sstevel@tonic-gate }
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate /*
1154*0Sstevel@tonic-gate  * Assign the address portion of the node name
1155*0Sstevel@tonic-gate  */
1156*0Sstevel@tonic-gate static int
1157*0Sstevel@tonic-gate pci_name_child(dev_info_t *child, char *name, int namelen)
1158*0Sstevel@tonic-gate {
1159*0Sstevel@tonic-gate 	pci_regspec_t *pci_rp;
1160*0Sstevel@tonic-gate 	char **unit_addr;
1161*0Sstevel@tonic-gate 	int dev, func, length;
1162*0Sstevel@tonic-gate 	uint_t n;
1163*0Sstevel@tonic-gate 
1164*0Sstevel@tonic-gate 	if (ndi_dev_is_persistent_node(child) == 0) {
1165*0Sstevel@tonic-gate 		/*
1166*0Sstevel@tonic-gate 		 * For .conf node, use "unit-address" property
1167*0Sstevel@tonic-gate 		 */
1168*0Sstevel@tonic-gate 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
1169*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
1170*0Sstevel@tonic-gate 		    DDI_PROP_SUCCESS) {
1171*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
1172*0Sstevel@tonic-gate 			    "cannot find unit-address in %s.conf",
1173*0Sstevel@tonic-gate 			    ddi_get_name(child));
1174*0Sstevel@tonic-gate 			return (DDI_FAILURE);
1175*0Sstevel@tonic-gate 		}
1176*0Sstevel@tonic-gate 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
1177*0Sstevel@tonic-gate 			cmn_err(CE_WARN, "unit-address property in %s.conf"
1178*0Sstevel@tonic-gate 			    " not well-formed", ddi_get_name(child));
1179*0Sstevel@tonic-gate 			ddi_prop_free(unit_addr);
1180*0Sstevel@tonic-gate 			return (DDI_FAILURE);
1181*0Sstevel@tonic-gate 		}
1182*0Sstevel@tonic-gate 		(void) snprintf(name, namelen, "%s", *unit_addr);
1183*0Sstevel@tonic-gate 		ddi_prop_free(unit_addr);
1184*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
1185*0Sstevel@tonic-gate 	}
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
1188*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
1189*0Sstevel@tonic-gate 	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
1190*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "cannot find reg property in %s",
1191*0Sstevel@tonic-gate 		    ddi_get_name(child));
1192*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1193*0Sstevel@tonic-gate 	}
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate 	/* copy the device identifications */
1196*0Sstevel@tonic-gate 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
1197*0Sstevel@tonic-gate 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
1198*0Sstevel@tonic-gate 
1199*0Sstevel@tonic-gate 	/*
1200*0Sstevel@tonic-gate 	 * free the memory allocated by ddi_prop_lookup_int_array
1201*0Sstevel@tonic-gate 	 */
1202*0Sstevel@tonic-gate 	ddi_prop_free(pci_rp);
1203*0Sstevel@tonic-gate 
1204*0Sstevel@tonic-gate 	if (func != 0) {
1205*0Sstevel@tonic-gate 		(void) snprintf(name, namelen, "%x,%x", dev, func);
1206*0Sstevel@tonic-gate 	} else {
1207*0Sstevel@tonic-gate 		(void) snprintf(name, namelen, "%x", dev);
1208*0Sstevel@tonic-gate 	}
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1211*0Sstevel@tonic-gate }
1212*0Sstevel@tonic-gate 
1213*0Sstevel@tonic-gate static int
1214*0Sstevel@tonic-gate pci_initchild(dev_info_t *child)
1215*0Sstevel@tonic-gate {
1216*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
1217*0Sstevel@tonic-gate 	char name[80];
1218*0Sstevel@tonic-gate 
1219*0Sstevel@tonic-gate 	if (pci_name_child(child, name, 80) != DDI_SUCCESS) {
1220*0Sstevel@tonic-gate 		return (DDI_FAILURE);
1221*0Sstevel@tonic-gate 	}
1222*0Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate 	/*
1225*0Sstevel@tonic-gate 	 * Pseudo nodes indicate a prototype node with per-instance
1226*0Sstevel@tonic-gate 	 * properties to be merged into the real h/w device node.
1227*0Sstevel@tonic-gate 	 * The interpretation of the unit-address is DD[,F]
1228*0Sstevel@tonic-gate 	 * where DD is the device id and F is the function.
1229*0Sstevel@tonic-gate 	 */
1230*0Sstevel@tonic-gate 	if (ndi_dev_is_persistent_node(child) == 0) {
1231*0Sstevel@tonic-gate 		extern int pci_allow_pseudo_children;
1232*0Sstevel@tonic-gate 
1233*0Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
1234*0Sstevel@tonic-gate 
1235*0Sstevel@tonic-gate 		/*
1236*0Sstevel@tonic-gate 		 * Try to merge the properties from this prototype
1237*0Sstevel@tonic-gate 		 * node into real h/w nodes.
1238*0Sstevel@tonic-gate 		 */
1239*0Sstevel@tonic-gate 		if (ndi_merge_node(child, pci_name_child) == DDI_SUCCESS) {
1240*0Sstevel@tonic-gate 			/*
1241*0Sstevel@tonic-gate 			 * Merged ok - return failure to remove the node.
1242*0Sstevel@tonic-gate 			 */
1243*0Sstevel@tonic-gate 			ddi_set_name_addr(child, NULL);
1244*0Sstevel@tonic-gate 			return (DDI_FAILURE);
1245*0Sstevel@tonic-gate 		}
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 		/* workaround for ddivs to run under PCI */
1248*0Sstevel@tonic-gate 		if (pci_allow_pseudo_children) {
1249*0Sstevel@tonic-gate 			/*
1250*0Sstevel@tonic-gate 			 * If the "interrupts" property doesn't exist,
1251*0Sstevel@tonic-gate 			 * this must be the ddivs no-intr case, and it returns
1252*0Sstevel@tonic-gate 			 * DDI_SUCCESS instead of DDI_FAILURE.
1253*0Sstevel@tonic-gate 			 */
1254*0Sstevel@tonic-gate 			if (ddi_prop_get_int(DDI_DEV_T_ANY, child,
1255*0Sstevel@tonic-gate 			    DDI_PROP_DONTPASS, "interrupts", -1) == -1)
1256*0Sstevel@tonic-gate 				return (DDI_SUCCESS);
1257*0Sstevel@tonic-gate 			/*
1258*0Sstevel@tonic-gate 			 * Create the ddi_parent_private_data for a pseudo
1259*0Sstevel@tonic-gate 			 * child.
1260*0Sstevel@tonic-gate 			 */
1261*0Sstevel@tonic-gate 			pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
1262*0Sstevel@tonic-gate 			    (sizeof (struct ddi_parent_private_data) +
1263*0Sstevel@tonic-gate 			    sizeof (struct intrspec)), KM_SLEEP);
1264*0Sstevel@tonic-gate 			pdptr->par_intr = (struct intrspec *)(pdptr + 1);
1265*0Sstevel@tonic-gate 			pdptr->par_nintr = 1;
1266*0Sstevel@tonic-gate 			ddi_set_parent_data(child, pdptr);
1267*0Sstevel@tonic-gate 			return (DDI_SUCCESS);
1268*0Sstevel@tonic-gate 		}
1269*0Sstevel@tonic-gate 
1270*0Sstevel@tonic-gate 		/*
1271*0Sstevel@tonic-gate 		 * The child was not merged into a h/w node,
1272*0Sstevel@tonic-gate 		 * but there's not much we can do with it other
1273*0Sstevel@tonic-gate 		 * than return failure to cause the node to be removed.
1274*0Sstevel@tonic-gate 		 */
1275*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
1276*0Sstevel@tonic-gate 		    ddi_get_name(child), ddi_get_name_addr(child),
1277*0Sstevel@tonic-gate 		    ddi_get_name(child));
1278*0Sstevel@tonic-gate 		ddi_set_name_addr(child, NULL);
1279*0Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
1280*0Sstevel@tonic-gate 	}
1281*0Sstevel@tonic-gate 
1282*0Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1283*0Sstevel@tonic-gate 	    "interrupts", -1) != -1) {
1284*0Sstevel@tonic-gate 		pdptr = (struct ddi_parent_private_data *)
1285*0Sstevel@tonic-gate 		    kmem_zalloc((sizeof (struct ddi_parent_private_data) +
1286*0Sstevel@tonic-gate 		    sizeof (struct intrspec)), KM_SLEEP);
1287*0Sstevel@tonic-gate 		pdptr->par_intr = (struct intrspec *)(pdptr + 1);
1288*0Sstevel@tonic-gate 		pdptr->par_nintr = 1;
1289*0Sstevel@tonic-gate 		ddi_set_parent_data(child, pdptr);
1290*0Sstevel@tonic-gate 	} else
1291*0Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
1292*0Sstevel@tonic-gate 
1293*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1294*0Sstevel@tonic-gate }
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate static int
1297*0Sstevel@tonic-gate pci_removechild(dev_info_t *dip)
1298*0Sstevel@tonic-gate {
1299*0Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate 	if ((pdptr = ddi_get_parent_data(dip)) != NULL) {
1302*0Sstevel@tonic-gate 		kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec)));
1303*0Sstevel@tonic-gate 		ddi_set_parent_data(dip, NULL);
1304*0Sstevel@tonic-gate 	}
1305*0Sstevel@tonic-gate 	ddi_set_name_addr(dip, NULL);
1306*0Sstevel@tonic-gate 
1307*0Sstevel@tonic-gate 	/*
1308*0Sstevel@tonic-gate 	 * Strip the node to properly convert it back to prototype form
1309*0Sstevel@tonic-gate 	 */
1310*0Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
1311*0Sstevel@tonic-gate 
1312*0Sstevel@tonic-gate 	impl_rem_dev_props(dip);
1313*0Sstevel@tonic-gate 
1314*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
1315*0Sstevel@tonic-gate }
1316*0Sstevel@tonic-gate 
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate /*
1319*0Sstevel@tonic-gate  * These are the get and put functions to be shared with drivers. The
1320*0Sstevel@tonic-gate  * mutex locking is done inside the functions referenced, rather than
1321*0Sstevel@tonic-gate  * here, and is thus shared across PCI child drivers and any other
1322*0Sstevel@tonic-gate  * consumers of PCI config space (such as the ACPI subsystem).
1323*0Sstevel@tonic-gate  *
1324*0Sstevel@tonic-gate  * The configuration space addresses come in as pointers.  This is fine on
1325*0Sstevel@tonic-gate  * a 32-bit system, where the VM space and configuration space are the same
1326*0Sstevel@tonic-gate  * size.  It's not such a good idea on a 64-bit system, where memory
1327*0Sstevel@tonic-gate  * addresses are twice as large as configuration space addresses.  At some
1328*0Sstevel@tonic-gate  * point in the call tree we need to take a stand and say "you are 32-bit
1329*0Sstevel@tonic-gate  * from this time forth", and this seems like a nice self-contained place.
1330*0Sstevel@tonic-gate  */
1331*0Sstevel@tonic-gate 
1332*0Sstevel@tonic-gate static uint8_t
1333*0Sstevel@tonic-gate pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1334*0Sstevel@tonic-gate {
1335*0Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
1336*0Sstevel@tonic-gate 	uint8_t	rval;
1337*0Sstevel@tonic-gate 	int reg;
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1340*0Sstevel@tonic-gate 
1341*0Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1346*0Sstevel@tonic-gate 	    reg);
1347*0Sstevel@tonic-gate 
1348*0Sstevel@tonic-gate 	return (rval);
1349*0Sstevel@tonic-gate }
1350*0Sstevel@tonic-gate 
1351*0Sstevel@tonic-gate static void
1352*0Sstevel@tonic-gate pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1353*0Sstevel@tonic-gate 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1354*0Sstevel@tonic-gate {
1355*0Sstevel@tonic-gate 	uint8_t *h, *d;
1356*0Sstevel@tonic-gate 
1357*0Sstevel@tonic-gate 	h = host_addr;
1358*0Sstevel@tonic-gate 	d = dev_addr;
1359*0Sstevel@tonic-gate 
1360*0Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
1361*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1362*0Sstevel@tonic-gate 			*h++ = pci_config_rd8(hdlp, d++);
1363*0Sstevel@tonic-gate 	else
1364*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1365*0Sstevel@tonic-gate 			*h++ = pci_config_rd8(hdlp, d);
1366*0Sstevel@tonic-gate }
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate static uint16_t
1369*0Sstevel@tonic-gate pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1370*0Sstevel@tonic-gate {
1371*0Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
1372*0Sstevel@tonic-gate 	uint16_t rval;
1373*0Sstevel@tonic-gate 	int reg;
1374*0Sstevel@tonic-gate 
1375*0Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
1378*0Sstevel@tonic-gate 
1379*0Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1380*0Sstevel@tonic-gate 
1381*0Sstevel@tonic-gate 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1382*0Sstevel@tonic-gate 	    reg);
1383*0Sstevel@tonic-gate 
1384*0Sstevel@tonic-gate 	return (rval);
1385*0Sstevel@tonic-gate }
1386*0Sstevel@tonic-gate 
1387*0Sstevel@tonic-gate static void
1388*0Sstevel@tonic-gate pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1389*0Sstevel@tonic-gate 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1390*0Sstevel@tonic-gate {
1391*0Sstevel@tonic-gate 	uint16_t *h, *d;
1392*0Sstevel@tonic-gate 
1393*0Sstevel@tonic-gate 	h = host_addr;
1394*0Sstevel@tonic-gate 	d = dev_addr;
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
1397*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1398*0Sstevel@tonic-gate 			*h++ = pci_config_rd16(hdlp, d++);
1399*0Sstevel@tonic-gate 	else
1400*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1401*0Sstevel@tonic-gate 			*h++ = pci_config_rd16(hdlp, d);
1402*0Sstevel@tonic-gate }
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate static uint32_t
1405*0Sstevel@tonic-gate pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1406*0Sstevel@tonic-gate {
1407*0Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
1408*0Sstevel@tonic-gate 	uint32_t rval;
1409*0Sstevel@tonic-gate 	int reg;
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1412*0Sstevel@tonic-gate 
1413*0Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1418*0Sstevel@tonic-gate 	    cfp->c_funcnum, reg);
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 	return (rval);
1421*0Sstevel@tonic-gate }
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate static void
1424*0Sstevel@tonic-gate pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1425*0Sstevel@tonic-gate 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1426*0Sstevel@tonic-gate {
1427*0Sstevel@tonic-gate 	uint32_t *h, *d;
1428*0Sstevel@tonic-gate 
1429*0Sstevel@tonic-gate 	h = host_addr;
1430*0Sstevel@tonic-gate 	d = dev_addr;
1431*0Sstevel@tonic-gate 
1432*0Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
1433*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1434*0Sstevel@tonic-gate 			*h++ = pci_config_rd32(hdlp, d++);
1435*0Sstevel@tonic-gate 	else
1436*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1437*0Sstevel@tonic-gate 			*h++ = pci_config_rd32(hdlp, d);
1438*0Sstevel@tonic-gate }
1439*0Sstevel@tonic-gate 
1440*0Sstevel@tonic-gate 
1441*0Sstevel@tonic-gate static void
1442*0Sstevel@tonic-gate pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1443*0Sstevel@tonic-gate {
1444*0Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
1445*0Sstevel@tonic-gate 	int reg;
1446*0Sstevel@tonic-gate 
1447*0Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1448*0Sstevel@tonic-gate 
1449*0Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1452*0Sstevel@tonic-gate 
1453*0Sstevel@tonic-gate 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1454*0Sstevel@tonic-gate 	    cfp->c_funcnum, reg, value);
1455*0Sstevel@tonic-gate }
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate static void
1458*0Sstevel@tonic-gate pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1459*0Sstevel@tonic-gate 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1460*0Sstevel@tonic-gate {
1461*0Sstevel@tonic-gate 	uint8_t *h, *d;
1462*0Sstevel@tonic-gate 
1463*0Sstevel@tonic-gate 	h = host_addr;
1464*0Sstevel@tonic-gate 	d = dev_addr;
1465*0Sstevel@tonic-gate 
1466*0Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
1467*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1468*0Sstevel@tonic-gate 			pci_config_wr8(hdlp, d++, *h++);
1469*0Sstevel@tonic-gate 	else
1470*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1471*0Sstevel@tonic-gate 			pci_config_wr8(hdlp, d, *h++);
1472*0Sstevel@tonic-gate }
1473*0Sstevel@tonic-gate 
1474*0Sstevel@tonic-gate static void
1475*0Sstevel@tonic-gate pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1476*0Sstevel@tonic-gate {
1477*0Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
1478*0Sstevel@tonic-gate 	int reg;
1479*0Sstevel@tonic-gate 
1480*0Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1481*0Sstevel@tonic-gate 
1482*0Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
1483*0Sstevel@tonic-gate 
1484*0Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1485*0Sstevel@tonic-gate 
1486*0Sstevel@tonic-gate 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1487*0Sstevel@tonic-gate 	    cfp->c_funcnum, reg, value);
1488*0Sstevel@tonic-gate }
1489*0Sstevel@tonic-gate 
1490*0Sstevel@tonic-gate static void
1491*0Sstevel@tonic-gate pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1492*0Sstevel@tonic-gate 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1493*0Sstevel@tonic-gate {
1494*0Sstevel@tonic-gate 	uint16_t *h, *d;
1495*0Sstevel@tonic-gate 
1496*0Sstevel@tonic-gate 	h = host_addr;
1497*0Sstevel@tonic-gate 	d = dev_addr;
1498*0Sstevel@tonic-gate 
1499*0Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
1500*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1501*0Sstevel@tonic-gate 			pci_config_wr16(hdlp, d++, *h++);
1502*0Sstevel@tonic-gate 	else
1503*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1504*0Sstevel@tonic-gate 			pci_config_wr16(hdlp, d, *h++);
1505*0Sstevel@tonic-gate }
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate static void
1508*0Sstevel@tonic-gate pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1509*0Sstevel@tonic-gate {
1510*0Sstevel@tonic-gate 	pci_acc_cfblk_t *cfp;
1511*0Sstevel@tonic-gate 	int reg;
1512*0Sstevel@tonic-gate 
1513*0Sstevel@tonic-gate 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate 	reg = (int)(uintptr_t)addr;
1516*0Sstevel@tonic-gate 
1517*0Sstevel@tonic-gate 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1518*0Sstevel@tonic-gate 
1519*0Sstevel@tonic-gate 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1520*0Sstevel@tonic-gate 	    cfp->c_funcnum, reg, value);
1521*0Sstevel@tonic-gate }
1522*0Sstevel@tonic-gate 
1523*0Sstevel@tonic-gate static void
1524*0Sstevel@tonic-gate pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1525*0Sstevel@tonic-gate 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1526*0Sstevel@tonic-gate {
1527*0Sstevel@tonic-gate 	uint32_t *h, *d;
1528*0Sstevel@tonic-gate 
1529*0Sstevel@tonic-gate 	h = host_addr;
1530*0Sstevel@tonic-gate 	d = dev_addr;
1531*0Sstevel@tonic-gate 
1532*0Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR)
1533*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1534*0Sstevel@tonic-gate 			pci_config_wr32(hdlp, d++, *h++);
1535*0Sstevel@tonic-gate 	else
1536*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1537*0Sstevel@tonic-gate 			pci_config_wr32(hdlp, d, *h++);
1538*0Sstevel@tonic-gate }
1539*0Sstevel@tonic-gate 
1540*0Sstevel@tonic-gate static uint64_t
1541*0Sstevel@tonic-gate pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1542*0Sstevel@tonic-gate {
1543*0Sstevel@tonic-gate 	uint32_t lw_val;
1544*0Sstevel@tonic-gate 	uint32_t hi_val;
1545*0Sstevel@tonic-gate 	uint32_t *dp;
1546*0Sstevel@tonic-gate 	uint64_t val;
1547*0Sstevel@tonic-gate 
1548*0Sstevel@tonic-gate 	dp = (uint32_t *)addr;
1549*0Sstevel@tonic-gate 	lw_val = pci_config_rd32(hdlp, dp);
1550*0Sstevel@tonic-gate 	dp++;
1551*0Sstevel@tonic-gate 	hi_val = pci_config_rd32(hdlp, dp);
1552*0Sstevel@tonic-gate 	val = ((uint64_t)hi_val << 32) | lw_val;
1553*0Sstevel@tonic-gate 	return (val);
1554*0Sstevel@tonic-gate }
1555*0Sstevel@tonic-gate 
1556*0Sstevel@tonic-gate static void
1557*0Sstevel@tonic-gate pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1558*0Sstevel@tonic-gate {
1559*0Sstevel@tonic-gate 	uint32_t lw_val;
1560*0Sstevel@tonic-gate 	uint32_t hi_val;
1561*0Sstevel@tonic-gate 	uint32_t *dp;
1562*0Sstevel@tonic-gate 
1563*0Sstevel@tonic-gate 	dp = (uint32_t *)addr;
1564*0Sstevel@tonic-gate 	lw_val = (uint32_t)(value & 0xffffffff);
1565*0Sstevel@tonic-gate 	hi_val = (uint32_t)(value >> 32);
1566*0Sstevel@tonic-gate 	pci_config_wr32(hdlp, dp, lw_val);
1567*0Sstevel@tonic-gate 	dp++;
1568*0Sstevel@tonic-gate 	pci_config_wr32(hdlp, dp, hi_val);
1569*0Sstevel@tonic-gate }
1570*0Sstevel@tonic-gate 
1571*0Sstevel@tonic-gate static void
1572*0Sstevel@tonic-gate pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1573*0Sstevel@tonic-gate 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1574*0Sstevel@tonic-gate {
1575*0Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR) {
1576*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1577*0Sstevel@tonic-gate 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1578*0Sstevel@tonic-gate 	} else {
1579*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1580*0Sstevel@tonic-gate 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
1581*0Sstevel@tonic-gate 	}
1582*0Sstevel@tonic-gate }
1583*0Sstevel@tonic-gate 
1584*0Sstevel@tonic-gate static void
1585*0Sstevel@tonic-gate pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1586*0Sstevel@tonic-gate 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1587*0Sstevel@tonic-gate {
1588*0Sstevel@tonic-gate 	if (flags == DDI_DEV_AUTOINCR) {
1589*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1590*0Sstevel@tonic-gate 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1591*0Sstevel@tonic-gate 	} else {
1592*0Sstevel@tonic-gate 		for (; repcount; repcount--)
1593*0Sstevel@tonic-gate 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
1594*0Sstevel@tonic-gate 	}
1595*0Sstevel@tonic-gate }
1596*0Sstevel@tonic-gate 
1597*0Sstevel@tonic-gate /*
1598*0Sstevel@tonic-gate  * When retrofitting this module for pci_tools, functions such as open, close,
1599*0Sstevel@tonic-gate  * and ioctl are now pulled into this module.  Before this, the functions in
1600*0Sstevel@tonic-gate  * the pcihp module were referenced directly.  Now they are called or
1601*0Sstevel@tonic-gate  * referenced through the pcihp cb_ops structure from functions in this module.
1602*0Sstevel@tonic-gate  */
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate static int
1605*0Sstevel@tonic-gate pci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1606*0Sstevel@tonic-gate {
1607*0Sstevel@tonic-gate 	return ((pcihp_cb_ops.cb_open)(devp, flags, otyp, credp));
1608*0Sstevel@tonic-gate }
1609*0Sstevel@tonic-gate 
1610*0Sstevel@tonic-gate static int
1611*0Sstevel@tonic-gate pci_close(dev_t dev, int flags, int otyp, cred_t *credp)
1612*0Sstevel@tonic-gate {
1613*0Sstevel@tonic-gate 	return ((pcihp_cb_ops.cb_close)(dev, flags, otyp, credp));
1614*0Sstevel@tonic-gate }
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate static int
1617*0Sstevel@tonic-gate pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1618*0Sstevel@tonic-gate 	int *rvalp)
1619*0Sstevel@tonic-gate {
1620*0Sstevel@tonic-gate 	int rv = ENOTTY;
1621*0Sstevel@tonic-gate 
1622*0Sstevel@tonic-gate 	if (IS_DEVCTL(cmd)) {
1623*0Sstevel@tonic-gate 		return ((pcihp_cb_ops.cb_ioctl)(dev, cmd, arg, mode,
1624*0Sstevel@tonic-gate 		    credp, rvalp));
1625*0Sstevel@tonic-gate 	}
1626*0Sstevel@tonic-gate 
1627*0Sstevel@tonic-gate 	/*
1628*0Sstevel@tonic-gate 	 * PCI tools.
1629*0Sstevel@tonic-gate 	 */
1630*0Sstevel@tonic-gate 
1631*0Sstevel@tonic-gate 	if ((cmd & ~IOCPARM_MASK) == PCITOOL_IOC) {
1632*0Sstevel@tonic-gate 		switch (cmd) {
1633*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_SET_REG:
1634*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_GET_REG:
1635*0Sstevel@tonic-gate 
1636*0Sstevel@tonic-gate 			/* Require full privileges. */
1637*0Sstevel@tonic-gate 			if (secpolicy_kmdb(credp))
1638*0Sstevel@tonic-gate 				rv = EPERM;
1639*0Sstevel@tonic-gate 			else
1640*0Sstevel@tonic-gate 				rv = pcitool_dev_reg_ops(
1641*0Sstevel@tonic-gate 				    dev, (void *)arg, cmd, mode);
1642*0Sstevel@tonic-gate 			break;
1643*0Sstevel@tonic-gate 
1644*0Sstevel@tonic-gate 		case PCITOOL_NEXUS_SET_REG:
1645*0Sstevel@tonic-gate 		case PCITOOL_NEXUS_GET_REG:
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate 			/* Require full privileges. */
1648*0Sstevel@tonic-gate 			if (secpolicy_kmdb(credp))
1649*0Sstevel@tonic-gate 				rv = EPERM;
1650*0Sstevel@tonic-gate 			else
1651*0Sstevel@tonic-gate 				rv = pcitool_bus_reg_ops(
1652*0Sstevel@tonic-gate 				    dev, (void *)arg, cmd, mode);
1653*0Sstevel@tonic-gate 			break;
1654*0Sstevel@tonic-gate 
1655*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_SET_INTR:
1656*0Sstevel@tonic-gate 
1657*0Sstevel@tonic-gate 			/* Require PRIV_SYS_RES_CONFIG */
1658*0Sstevel@tonic-gate 			if (secpolicy_ponline(credp)) {
1659*0Sstevel@tonic-gate 				rv = EPERM;
1660*0Sstevel@tonic-gate 				break;
1661*0Sstevel@tonic-gate 			}
1662*0Sstevel@tonic-gate 
1663*0Sstevel@tonic-gate 		/*FALLTHRU*/
1664*0Sstevel@tonic-gate 		/* These require no special privileges. */
1665*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_GET_INTR:
1666*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_NUM_INTR:
1667*0Sstevel@tonic-gate 			rv = pcitool_intr_admn(dev, (void *)arg, cmd, mode);
1668*0Sstevel@tonic-gate 			break;
1669*0Sstevel@tonic-gate 
1670*0Sstevel@tonic-gate 		default:
1671*0Sstevel@tonic-gate 			rv = ENOTTY;
1672*0Sstevel@tonic-gate 			break;
1673*0Sstevel@tonic-gate 		}
1674*0Sstevel@tonic-gate 	}
1675*0Sstevel@tonic-gate 
1676*0Sstevel@tonic-gate 	return (rv);
1677*0Sstevel@tonic-gate }
1678*0Sstevel@tonic-gate 
1679*0Sstevel@tonic-gate static int
1680*0Sstevel@tonic-gate pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1681*0Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp)
1682*0Sstevel@tonic-gate {
1683*0Sstevel@tonic-gate 	return ((pcihp_cb_ops.cb_prop_op)(dev, dip, prop_op, flags,
1684*0Sstevel@tonic-gate 	    name, valuep, lengthp));
1685*0Sstevel@tonic-gate }
1686*0Sstevel@tonic-gate 
1687*0Sstevel@tonic-gate static int
1688*0Sstevel@tonic-gate pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
1689*0Sstevel@tonic-gate {
1690*0Sstevel@tonic-gate 	return (pcihp_info(dip, cmd, arg, result));
1691*0Sstevel@tonic-gate }
1692