xref: /onnv-gate/usr/src/uts/i86pc/io/pci/pci_common.c (revision 4160:c23579e36e7c)
1881Sjohnny /*
2881Sjohnny  * CDDL HEADER START
3881Sjohnny  *
4881Sjohnny  * The contents of this file are subject to the terms of the
51542Sjohnny  * Common Development and Distribution License (the "License").
61542Sjohnny  * You may not use this file except in compliance with the License.
7881Sjohnny  *
8881Sjohnny  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9881Sjohnny  * or http://www.opensolaris.org/os/licensing.
10881Sjohnny  * See the License for the specific language governing permissions
11881Sjohnny  * and limitations under the License.
12881Sjohnny  *
13881Sjohnny  * When distributing Covered Code, include this CDDL HEADER in each
14881Sjohnny  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15881Sjohnny  * If applicable, add the following below this CDDL HEADER, with the
16881Sjohnny  * fields enclosed by brackets "[]" replaced with your own identifying
17881Sjohnny  * information: Portions Copyright [yyyy] [name of copyright owner]
18881Sjohnny  *
19881Sjohnny  * CDDL HEADER END
20881Sjohnny  */
21881Sjohnny 
22881Sjohnny /*
233446Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24881Sjohnny  * Use is subject to license terms.
25881Sjohnny  */
26881Sjohnny 
27881Sjohnny #pragma ident	"%Z%%M%	%I%	%E% SMI"
28881Sjohnny 
29881Sjohnny /*
30881Sjohnny  *	File that has code which is common between pci(7d) and npe(7d)
31881Sjohnny  *	It shares the following:
32881Sjohnny  *	- interrupt code
33881Sjohnny  *	- pci_tools ioctl code
34881Sjohnny  *	- name_child code
35881Sjohnny  *	- set_parent_private_data code
36881Sjohnny  */
37881Sjohnny 
38881Sjohnny #include <sys/conf.h>
39881Sjohnny #include <sys/pci.h>
40881Sjohnny #include <sys/sunndi.h>
41916Sschwartz #include <sys/mach_intr.h>
42881Sjohnny #include <sys/hotplug/pci/pcihp.h>
43881Sjohnny #include <sys/pci_intr_lib.h>
44881Sjohnny #include <sys/psm.h>
45881Sjohnny #include <sys/policy.h>
46881Sjohnny #include <sys/sysmacros.h>
47916Sschwartz #include <sys/clock.h>
483446Smrj #include <sys/apic.h>
49881Sjohnny #include <sys/pci_tools.h>
50881Sjohnny #include <io/pci/pci_var.h>
51881Sjohnny #include <io/pci/pci_tools_ext.h>
52881Sjohnny #include <io/pci/pci_common.h>
531083Sanish #include <sys/pci_cfgspace.h>
541083Sanish #include <sys/pci_impl.h>
55*4160Sjveta #include <sys/pci_cap.h>
56881Sjohnny 
57881Sjohnny /*
58881Sjohnny  * Function prototypes
59881Sjohnny  */
60881Sjohnny static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
61881Sjohnny static int	pci_enable_intr(dev_info_t *, dev_info_t *,
62881Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
63881Sjohnny static void	pci_disable_intr(dev_info_t *, dev_info_t *,
64881Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
65881Sjohnny 
66881Sjohnny /* Extern decalration for pcplusmp module */
67881Sjohnny extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
68881Sjohnny 		    psm_intr_op_t, int *);
69881Sjohnny 
70881Sjohnny 
71881Sjohnny /*
72881Sjohnny  * pci_name_child:
73881Sjohnny  *
74881Sjohnny  *	Assign the address portion of the node name
75881Sjohnny  */
76881Sjohnny int
77881Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
78881Sjohnny {
79881Sjohnny 	int		dev, func, length;
80881Sjohnny 	char		**unit_addr;
81881Sjohnny 	uint_t		n;
82881Sjohnny 	pci_regspec_t	*pci_rp;
83881Sjohnny 
84881Sjohnny 	if (ndi_dev_is_persistent_node(child) == 0) {
85881Sjohnny 		/*
86881Sjohnny 		 * For .conf node, use "unit-address" property
87881Sjohnny 		 */
88881Sjohnny 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
89881Sjohnny 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
90881Sjohnny 		    DDI_PROP_SUCCESS) {
91881Sjohnny 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
92881Sjohnny 			    ddi_get_name(child));
93881Sjohnny 			return (DDI_FAILURE);
94881Sjohnny 		}
95881Sjohnny 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
96881Sjohnny 			cmn_err(CE_WARN, "unit-address property in %s.conf"
97881Sjohnny 			    " not well-formed", ddi_get_name(child));
98881Sjohnny 			ddi_prop_free(unit_addr);
99881Sjohnny 			return (DDI_FAILURE);
100881Sjohnny 		}
101881Sjohnny 		(void) snprintf(name, namelen, "%s", *unit_addr);
102881Sjohnny 		ddi_prop_free(unit_addr);
103881Sjohnny 		return (DDI_SUCCESS);
104881Sjohnny 	}
105881Sjohnny 
106881Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
107881Sjohnny 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
108881Sjohnny 		cmn_err(CE_WARN, "cannot find reg property in %s",
109881Sjohnny 		    ddi_get_name(child));
110881Sjohnny 		return (DDI_FAILURE);
111881Sjohnny 	}
112881Sjohnny 
113881Sjohnny 	/* copy the device identifications */
114881Sjohnny 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
115881Sjohnny 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
116881Sjohnny 
117881Sjohnny 	/*
118881Sjohnny 	 * free the memory allocated by ddi_prop_lookup_int_array
119881Sjohnny 	 */
120881Sjohnny 	ddi_prop_free(pci_rp);
121881Sjohnny 
122881Sjohnny 	if (func != 0) {
123881Sjohnny 		(void) snprintf(name, namelen, "%x,%x", dev, func);
124881Sjohnny 	} else {
125881Sjohnny 		(void) snprintf(name, namelen, "%x", dev);
126881Sjohnny 	}
127881Sjohnny 
128881Sjohnny 	return (DDI_SUCCESS);
129881Sjohnny }
130881Sjohnny 
131881Sjohnny /*
132881Sjohnny  * Interrupt related code:
133881Sjohnny  *
134881Sjohnny  * The following busop is common to npe and pci drivers
135881Sjohnny  *	bus_introp
136881Sjohnny  */
137881Sjohnny 
138881Sjohnny /*
139881Sjohnny  * Create the ddi_parent_private_data for a pseudo child.
140881Sjohnny  */
141881Sjohnny void
142881Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
143881Sjohnny {
144881Sjohnny 	struct ddi_parent_private_data *pdptr;
145881Sjohnny 
146881Sjohnny 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
147881Sjohnny 	    (sizeof (struct ddi_parent_private_data) +
148881Sjohnny 	sizeof (struct intrspec)), KM_SLEEP);
149881Sjohnny 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
150881Sjohnny 	pdptr->par_nintr = 1;
151881Sjohnny 	ddi_set_parent_data(dip, pdptr);
152881Sjohnny }
153881Sjohnny 
154881Sjohnny /*
155881Sjohnny  * pci_get_priority:
156881Sjohnny  *	Figure out the priority of the device
157881Sjohnny  */
158881Sjohnny static int
159881Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
160881Sjohnny {
161881Sjohnny 	struct intrspec *ispec;
162881Sjohnny 
163881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
164881Sjohnny 	    (void *)dip, (void *)hdlp));
165881Sjohnny 
166881Sjohnny 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
167881Sjohnny 	    hdlp->ih_inum)) == NULL) {
168881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
169881Sjohnny 			int class = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
170881Sjohnny 			    DDI_PROP_DONTPASS, "class-code", -1);
171881Sjohnny 
172881Sjohnny 			*pri = (class == -1) ? 1 : pci_devclass_to_ipl(class);
173881Sjohnny 			pci_common_set_parent_private_data(hdlp->ih_dip);
174881Sjohnny 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
175881Sjohnny 			    hdlp->ih_inum);
176881Sjohnny 			return (DDI_SUCCESS);
177881Sjohnny 		}
178881Sjohnny 		return (DDI_FAILURE);
179881Sjohnny 	}
180881Sjohnny 
181881Sjohnny 	*pri = ispec->intrspec_pri;
182881Sjohnny 	return (DDI_SUCCESS);
183881Sjohnny }
184881Sjohnny 
185881Sjohnny 
186881Sjohnny 
187881Sjohnny static int pcie_pci_intr_pri_counter = 0;
188881Sjohnny 
189881Sjohnny /*
190881Sjohnny  * pci_common_intr_ops: bus_intr_op() function for interrupt support
191881Sjohnny  */
192881Sjohnny int
193881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
194881Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
195881Sjohnny {
196881Sjohnny 	int			priority = 0;
197881Sjohnny 	int			psm_status = 0;
198881Sjohnny 	int			pci_status = 0;
199881Sjohnny 	int			pci_rval, psm_rval = PSM_FAILURE;
200881Sjohnny 	int			types = 0;
201881Sjohnny 	int			pciepci = 0;
2021542Sjohnny 	int			i, j, count;
203*4160Sjveta 	int			rv;
204881Sjohnny 	int			behavior;
2051997Sanish 	int			cap_ptr;
206*4160Sjveta 	uint16_t		msi_cap_base, msix_cap_base, cap_ctrl;
207*4160Sjveta 	char			*prop;
208881Sjohnny 	ddi_intrspec_t		isp;
209881Sjohnny 	struct intrspec		*ispec;
210881Sjohnny 	ddi_intr_handle_impl_t	tmp_hdl;
211881Sjohnny 	ddi_intr_msix_t		*msix_p;
2121087Sschwartz 	ihdl_plat_t		*ihdl_plat_datap;
2131542Sjohnny 	ddi_intr_handle_t	*h_array;
2141997Sanish 	ddi_acc_handle_t	handle;
215881Sjohnny 
216881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT,
217881Sjohnny 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
218881Sjohnny 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
219881Sjohnny 
220881Sjohnny 	/* Process the request */
221881Sjohnny 	switch (intr_op) {
222881Sjohnny 	case DDI_INTROP_SUPPORTED_TYPES:
223*4160Sjveta 		/*
224*4160Sjveta 		 * First we determine the interrupt types supported by the
225*4160Sjveta 		 * device itself, then we filter them through what the OS
226*4160Sjveta 		 * and system supports.  We determine system-level
227*4160Sjveta 		 * interrupt type support for anything other than fixed intrs
228*4160Sjveta 		 * through the psm_intr_ops vector
229*4160Sjveta 		 */
230*4160Sjveta 		rv = DDI_FAILURE;
231*4160Sjveta 
232881Sjohnny 		/* Fixed supported by default */
233*4160Sjveta 		types = DDI_INTR_TYPE_FIXED;
234*4160Sjveta 
235*4160Sjveta 		if (psm_intr_ops == NULL) {
236*4160Sjveta 			*(int *)result = types;
237*4160Sjveta 			return (DDI_SUCCESS);
238*4160Sjveta 		}
239*4160Sjveta 		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
240*4160Sjveta 			return (DDI_FAILURE);
241881Sjohnny 
242*4160Sjveta 		/* Sanity test cap control values if found */
243*4160Sjveta 
244*4160Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
245*4160Sjveta 		    DDI_SUCCESS) {
246*4160Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
247*4160Sjveta 			    PCI_MSI_CTRL);
248*4160Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
249*4160Sjveta 				goto SUPPORTED_TYPES_OUT;
250*4160Sjveta 
251*4160Sjveta 			types |= DDI_INTR_TYPE_MSI;
252*4160Sjveta 		}
253*4160Sjveta 
254*4160Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
255*4160Sjveta 		    DDI_SUCCESS) {
256*4160Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
257*4160Sjveta 			    PCI_MSIX_CTRL);
258*4160Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
259*4160Sjveta 				goto SUPPORTED_TYPES_OUT;
260881Sjohnny 
261*4160Sjveta 			types |= DDI_INTR_TYPE_MSIX;
262*4160Sjveta 		}
263*4160Sjveta 
264*4160Sjveta 		/*
265*4160Sjveta 		 * Filter device-level types through system-level support
266*4160Sjveta 		 */
267*4160Sjveta 
268*4160Sjveta 		/* No official MSI-X support for now */
269*4160Sjveta 		types &= ~DDI_INTR_TYPE_MSIX;
270*4160Sjveta 
271*4160Sjveta 		tmp_hdl.ih_type = types;
272*4160Sjveta 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
273*4160Sjveta 		    &types) != PSM_SUCCESS)
274*4160Sjveta 			goto SUPPORTED_TYPES_OUT;
275*4160Sjveta 
276*4160Sjveta 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
277*4160Sjveta 		    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
278*4160Sjveta 		    *(int *)result));
279881Sjohnny 
280*4160Sjveta 		/*
281*4160Sjveta 		 * Export any MSI/MSI-X cap locations via properties
282*4160Sjveta 		 */
283*4160Sjveta 		if (types & DDI_INTR_TYPE_MSI) {
284*4160Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
285*4160Sjveta 			    "pci-msi-capid-pointer", (int)msi_cap_base) !=
286*4160Sjveta 			    DDI_PROP_SUCCESS)
287*4160Sjveta 				goto SUPPORTED_TYPES_OUT;
288881Sjohnny 		}
289*4160Sjveta 		if (types & DDI_INTR_TYPE_MSIX) {
290*4160Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
291*4160Sjveta 			    "pci-msix-capid-pointer", (int)msix_cap_base) !=
292*4160Sjveta 			    DDI_PROP_SUCCESS)
293*4160Sjveta 				goto SUPPORTED_TYPES_OUT;
294*4160Sjveta 		}
295*4160Sjveta 
296*4160Sjveta 		rv = DDI_SUCCESS;
297*4160Sjveta 
298*4160Sjveta SUPPORTED_TYPES_OUT:
299*4160Sjveta 		*(int *)result = types;
300*4160Sjveta 		pci_config_teardown(&handle);
301*4160Sjveta 		return (rv);
302*4160Sjveta 
3032580Sanish 	case DDI_INTROP_NAVAIL:
304881Sjohnny 	case DDI_INTROP_NINTRS:
3052580Sanish 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
3062580Sanish 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
3072580Sanish 			    result) != DDI_SUCCESS)
3082580Sanish 				return (DDI_FAILURE);
3092580Sanish 		} else {
3102580Sanish 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
3112580Sanish 			if (*(int *)result == 0)
3122580Sanish 				return (DDI_FAILURE);
3132580Sanish 		}
314881Sjohnny 		break;
315881Sjohnny 	case DDI_INTROP_ALLOC:
316881Sjohnny 		/*
317881Sjohnny 		 * MSI or MSIX (figure out number of vectors available)
318881Sjohnny 		 * FIXED interrupts: just return available interrupts
319881Sjohnny 		 */
320881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
321881Sjohnny 		    (psm_intr_ops != NULL) &&
322881Sjohnny 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
323881Sjohnny 			/*
324881Sjohnny 			 * Following check is a special case for 'pcie_pci'.
325881Sjohnny 			 * This makes sure vectors with the right priority
326881Sjohnny 			 * are allocated for pcie_pci during ALLOC time.
327881Sjohnny 			 */
328881Sjohnny 			if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) {
329881Sjohnny 				hdlp->ih_pri =
330881Sjohnny 				    (pcie_pci_intr_pri_counter % 2) ? 4 : 7;
331881Sjohnny 				pciepci = 1;
332881Sjohnny 			} else
333881Sjohnny 				hdlp->ih_pri = priority;
3341717Swesolows 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
3351997Sanish 
3361997Sanish 			/*
3371997Sanish 			 * Cache in the config handle and cap_ptr
3381997Sanish 			 */
3391997Sanish 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
3401997Sanish 				if (pci_config_setup(rdip, &handle) !=
3411997Sanish 				    DDI_SUCCESS)
3421997Sanish 					return (DDI_FAILURE);
3431997Sanish 				i_ddi_set_pci_config_handle(rdip, handle);
3441997Sanish 			}
3451997Sanish 
346*4160Sjveta 			prop = NULL;
347*4160Sjveta 			cap_ptr = 0;
348*4160Sjveta 			if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
349*4160Sjveta 				prop = "pci-msi-capid-pointer";
350*4160Sjveta 			else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
351*4160Sjveta 				prop = "pci-msix-capid-pointer";
3521997Sanish 
353*4160Sjveta 			/*
354*4160Sjveta 			 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
355*4160Sjveta 			 * for MSI(X) before allocation
356*4160Sjveta 			 */
357*4160Sjveta 			if (prop != NULL) {
3581997Sanish 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
359*4160Sjveta 				    DDI_PROP_DONTPASS, prop, 0);
360*4160Sjveta 				if (cap_ptr == 0) {
361*4160Sjveta 					DDI_INTR_NEXDBG((CE_CONT,
362*4160Sjveta 					    "pci_common_intr_ops: rdip: 0x%p "
363*4160Sjveta 					    "attempted MSI(X) alloc without "
364*4160Sjveta 					    "cap property\n", (void *)rdip));
365*4160Sjveta 					return (DDI_FAILURE);
366*4160Sjveta 				}
3671997Sanish 			}
368*4160Sjveta 			i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
3691997Sanish 
370*4160Sjveta 			/*
371*4160Sjveta 			 * Allocate interrupt vectors
372*4160Sjveta 			 */
373881Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
374881Sjohnny 			    PSM_INTR_OP_ALLOC_VECTORS, result);
375881Sjohnny 
3763112Sanish 			if (*(int *)result == 0)
3773112Sanish 				return (DDI_INTR_NOTFOUND);
3783112Sanish 
379881Sjohnny 			/* verify behavior flag and take appropriate action */
380881Sjohnny 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
381881Sjohnny 			    (*(int *)result < hdlp->ih_scratch1)) {
382881Sjohnny 				DDI_INTR_NEXDBG((CE_CONT,
383881Sjohnny 				    "pci_common_intr_ops: behavior %x, "
384881Sjohnny 				    "couldn't get enough intrs\n", behavior));
385881Sjohnny 				hdlp->ih_scratch1 = *(int *)result;
386881Sjohnny 				(void) (*psm_intr_ops)(rdip, hdlp,
387881Sjohnny 				    PSM_INTR_OP_FREE_VECTORS, NULL);
388881Sjohnny 				return (DDI_EAGAIN);
389881Sjohnny 			}
390881Sjohnny 
391881Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
392881Sjohnny 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
393881Sjohnny 					msix_p = pci_msix_init(hdlp->ih_dip);
394881Sjohnny 					if (msix_p)
395881Sjohnny 						i_ddi_set_msix(hdlp->ih_dip,
396881Sjohnny 						    msix_p);
397881Sjohnny 				}
398881Sjohnny 			}
399881Sjohnny 
400881Sjohnny 			if (pciepci) {
401881Sjohnny 				/* update priority in ispec */
402881Sjohnny 				isp = pci_intx_get_ispec(pdip, rdip,
403881Sjohnny 					(int)hdlp->ih_inum);
404881Sjohnny 				ispec = (struct intrspec *)isp;
405881Sjohnny 				if (ispec)
406881Sjohnny 					ispec->intrspec_pri = hdlp->ih_pri;
407881Sjohnny 				++pcie_pci_intr_pri_counter;
408881Sjohnny 			}
409881Sjohnny 
410881Sjohnny 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
411881Sjohnny 			/* Figure out if this device supports MASKING */
412881Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
413881Sjohnny 			if (pci_rval == DDI_SUCCESS && pci_status)
414881Sjohnny 				hdlp->ih_cap |= pci_status;
415881Sjohnny 			*(int *)result = 1;	/* DDI_INTR_TYPE_FIXED */
416881Sjohnny 		} else
417881Sjohnny 			return (DDI_FAILURE);
418881Sjohnny 		break;
419881Sjohnny 	case DDI_INTROP_FREE:
420881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
421881Sjohnny 		    (psm_intr_ops != NULL)) {
4222018Sanish 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
4232018Sanish 			    0) {
4241997Sanish 				if (handle = i_ddi_get_pci_config_handle(
4251997Sanish 				    rdip)) {
4261997Sanish 					(void) pci_config_teardown(&handle);
4271997Sanish 					i_ddi_set_pci_config_handle(rdip, NULL);
4281997Sanish 				}
4291997Sanish 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
4301997Sanish 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
4311997Sanish 			}
4321997Sanish 
433881Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
434881Sjohnny 			    PSM_INTR_OP_FREE_VECTORS, NULL);
435881Sjohnny 
436881Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
437881Sjohnny 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
438881Sjohnny 				if (msix_p &&
4392018Sanish 				    (i_ddi_intr_get_current_nintrs(
4402018Sanish 					hdlp->ih_dip) - 1) == 0) {
441881Sjohnny 					pci_msix_fini(msix_p);
442881Sjohnny 					i_ddi_set_msix(hdlp->ih_dip, NULL);
443881Sjohnny 				}
444881Sjohnny 			}
445881Sjohnny 		}
446881Sjohnny 		break;
447881Sjohnny 	case DDI_INTROP_GETPRI:
448881Sjohnny 		/* Get the priority */
449881Sjohnny 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
450881Sjohnny 			return (DDI_FAILURE);
451881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
452881Sjohnny 		    "priority = 0x%x\n", priority));
453881Sjohnny 		*(int *)result = priority;
454881Sjohnny 		break;
455881Sjohnny 	case DDI_INTROP_SETPRI:
456881Sjohnny 		/* Validate the interrupt priority passed */
457881Sjohnny 		if (*(int *)result > LOCK_LEVEL)
458881Sjohnny 			return (DDI_FAILURE);
459881Sjohnny 
460881Sjohnny 		/* Ensure that PSM is all initialized */
461881Sjohnny 		if (psm_intr_ops == NULL)
462881Sjohnny 			return (DDI_FAILURE);
463881Sjohnny 
464881Sjohnny 		/* Change the priority */
465881Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
466881Sjohnny 		    PSM_FAILURE)
467881Sjohnny 			return (DDI_FAILURE);
468881Sjohnny 
469881Sjohnny 		/* update ispec */
470881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
471881Sjohnny 		ispec = (struct intrspec *)isp;
472881Sjohnny 		if (ispec)
473881Sjohnny 			ispec->intrspec_pri = *(int *)result;
474881Sjohnny 		break;
475881Sjohnny 	case DDI_INTROP_ADDISR:
476881Sjohnny 		/* update ispec */
477881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
478881Sjohnny 		ispec = (struct intrspec *)isp;
4791087Sschwartz 		if (ispec) {
480881Sjohnny 			ispec->intrspec_func = hdlp->ih_cb_func;
4811087Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
4821087Sschwartz 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
4831087Sschwartz 		}
484881Sjohnny 		break;
485881Sjohnny 	case DDI_INTROP_REMISR:
486881Sjohnny 		/* Get the interrupt structure pointer */
487881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
488881Sjohnny 		ispec = (struct intrspec *)isp;
4891087Sschwartz 		if (ispec) {
490881Sjohnny 			ispec->intrspec_func = (uint_t (*)()) 0;
4911087Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
4921087Sschwartz 			if (ihdl_plat_datap->ip_ksp != NULL)
4931087Sschwartz 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
4941087Sschwartz 		}
495881Sjohnny 		break;
496881Sjohnny 	case DDI_INTROP_GETCAP:
497881Sjohnny 		/*
498881Sjohnny 		 * First check the config space and/or
499881Sjohnny 		 * MSI capability register(s)
500881Sjohnny 		 */
501881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
502881Sjohnny 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
503881Sjohnny 			    &pci_status);
504881Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
505881Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
506881Sjohnny 
507881Sjohnny 		/* next check with pcplusmp */
508881Sjohnny 		if (psm_intr_ops != NULL)
509881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
510881Sjohnny 			    PSM_INTR_OP_GET_CAP, &psm_status);
511881Sjohnny 
512881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
513881Sjohnny 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
514881Sjohnny 		    psm_rval, psm_status, pci_rval, pci_status));
515881Sjohnny 
516881Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
517881Sjohnny 			*(int *)result = 0;
518881Sjohnny 			return (DDI_FAILURE);
519881Sjohnny 		}
520881Sjohnny 
521881Sjohnny 		if (psm_rval == PSM_SUCCESS)
522881Sjohnny 			*(int *)result = psm_status;
523881Sjohnny 
524881Sjohnny 		if (pci_rval == DDI_SUCCESS)
525881Sjohnny 			*(int *)result |= pci_status;
526881Sjohnny 
527881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
528881Sjohnny 		    *(int *)result));
529881Sjohnny 		break;
530881Sjohnny 	case DDI_INTROP_SETCAP:
531881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
532881Sjohnny 		    "SETCAP cap=0x%x\n", *(int *)result));
533881Sjohnny 		if (psm_intr_ops == NULL)
534881Sjohnny 			return (DDI_FAILURE);
535881Sjohnny 
536881Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
537881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
538881Sjohnny 			    " returned failure\n"));
539881Sjohnny 			return (DDI_FAILURE);
540881Sjohnny 		}
541881Sjohnny 		break;
542881Sjohnny 	case DDI_INTROP_ENABLE:
543881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
544881Sjohnny 		if (psm_intr_ops == NULL)
545881Sjohnny 			return (DDI_FAILURE);
546881Sjohnny 
547881Sjohnny 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
548881Sjohnny 		    DDI_SUCCESS)
549881Sjohnny 			return (DDI_FAILURE);
550881Sjohnny 
551881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
552881Sjohnny 		    "vector=0x%x\n", hdlp->ih_vector));
553881Sjohnny 		break;
554881Sjohnny 	case DDI_INTROP_DISABLE:
555881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
556881Sjohnny 		if (psm_intr_ops == NULL)
557881Sjohnny 			return (DDI_FAILURE);
558881Sjohnny 
559881Sjohnny 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
560881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
561881Sjohnny 		    "vector = %x\n", hdlp->ih_vector));
562881Sjohnny 		break;
563881Sjohnny 	case DDI_INTROP_BLOCKENABLE:
564881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
565881Sjohnny 		    "BLOCKENABLE\n"));
566881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
567881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
568881Sjohnny 			return (DDI_FAILURE);
569881Sjohnny 		}
570881Sjohnny 
571881Sjohnny 		/* Check if psm_intr_ops is NULL? */
572881Sjohnny 		if (psm_intr_ops == NULL)
573881Sjohnny 			return (DDI_FAILURE);
574881Sjohnny 
5751542Sjohnny 		count = hdlp->ih_scratch1;
5761542Sjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
5771542Sjohnny 		for (i = 0; i < count; i++) {
5781542Sjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
579881Sjohnny 			if (pci_enable_intr(pdip, rdip, hdlp,
5801542Sjohnny 			    hdlp->ih_inum) != DDI_SUCCESS) {
581881Sjohnny 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
582881Sjohnny 				    "pci_enable_intr failed for %d\n", i));
5831542Sjohnny 				for (j = 0; j < i; j++) {
5841542Sjohnny 				    hdlp = (ddi_intr_handle_impl_t *)h_array[j];
5851542Sjohnny 				    pci_disable_intr(pdip, rdip, hdlp,
5861542Sjohnny 					    hdlp->ih_inum);
5871542Sjohnny 				}
588881Sjohnny 				return (DDI_FAILURE);
589881Sjohnny 			}
590881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
5911542Sjohnny 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
592881Sjohnny 		}
593881Sjohnny 		break;
594881Sjohnny 	case DDI_INTROP_BLOCKDISABLE:
595881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
596881Sjohnny 		    "BLOCKDISABLE\n"));
597881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
598881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
599881Sjohnny 			return (DDI_FAILURE);
600881Sjohnny 		}
601881Sjohnny 
602881Sjohnny 		/* Check if psm_intr_ops is present */
603881Sjohnny 		if (psm_intr_ops == NULL)
604881Sjohnny 			return (DDI_FAILURE);
605881Sjohnny 
6061542Sjohnny 		count = hdlp->ih_scratch1;
6071542Sjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
6081542Sjohnny 		for (i = 0; i < count; i++) {
6091542Sjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
6101542Sjohnny 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
611881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
6121542Sjohnny 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
613881Sjohnny 		}
614881Sjohnny 		break;
615881Sjohnny 	case DDI_INTROP_SETMASK:
616881Sjohnny 	case DDI_INTROP_CLRMASK:
617881Sjohnny 		/*
618881Sjohnny 		 * First handle in the config space
619881Sjohnny 		 */
620881Sjohnny 		if (intr_op == DDI_INTROP_SETMASK) {
621881Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
622881Sjohnny 				pci_status = pci_msi_set_mask(rdip,
623881Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
624881Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
625881Sjohnny 				pci_status = pci_intx_set_mask(rdip);
626881Sjohnny 		} else {
627881Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
628881Sjohnny 				pci_status = pci_msi_clr_mask(rdip,
629881Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
630881Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
631881Sjohnny 				pci_status = pci_intx_clr_mask(rdip);
632881Sjohnny 		}
633881Sjohnny 
634881Sjohnny 		/* For MSI/X; no need to check with pcplusmp */
635881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
636881Sjohnny 			return (pci_status);
637881Sjohnny 
638881Sjohnny 		/* For fixed interrupts only: handle config space first */
639881Sjohnny 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
640881Sjohnny 		    pci_status == DDI_SUCCESS)
641881Sjohnny 			break;
642881Sjohnny 
643881Sjohnny 		/* For fixed interrupts only: confer with pcplusmp next */
644881Sjohnny 		if (psm_intr_ops != NULL) {
645881Sjohnny 			/* If interrupt is shared; do nothing */
646881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
647881Sjohnny 			    PSM_INTR_OP_GET_SHARED, &psm_status);
648881Sjohnny 
649881Sjohnny 			if (psm_rval == PSM_FAILURE || psm_status == 1)
650881Sjohnny 				return (pci_status);
651881Sjohnny 
652881Sjohnny 			/* Now, pcplusmp should try to set/clear the mask */
653881Sjohnny 			if (intr_op == DDI_INTROP_SETMASK)
654881Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
655881Sjohnny 				    PSM_INTR_OP_SET_MASK, NULL);
656881Sjohnny 			else
657881Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
658881Sjohnny 				    PSM_INTR_OP_CLEAR_MASK, NULL);
659881Sjohnny 		}
660881Sjohnny 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
661881Sjohnny 	case DDI_INTROP_GETPENDING:
662881Sjohnny 		/*
663881Sjohnny 		 * First check the config space and/or
664881Sjohnny 		 * MSI capability register(s)
665881Sjohnny 		 */
666881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
667881Sjohnny 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
668881Sjohnny 			    hdlp->ih_inum, &pci_status);
669881Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
670881Sjohnny 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
671881Sjohnny 
672881Sjohnny 		/* On failure; next try with pcplusmp */
673881Sjohnny 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
674881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
675881Sjohnny 			    PSM_INTR_OP_GET_PENDING, &psm_status);
676881Sjohnny 
677881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
678881Sjohnny 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
679881Sjohnny 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
680881Sjohnny 		    pci_status));
681881Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
682881Sjohnny 			*(int *)result = 0;
683881Sjohnny 			return (DDI_FAILURE);
684881Sjohnny 		}
685881Sjohnny 
686881Sjohnny 		if (psm_rval != PSM_FAILURE)
687881Sjohnny 			*(int *)result = psm_status;
688881Sjohnny 		else if (pci_rval != DDI_FAILURE)
689881Sjohnny 			*(int *)result = pci_status;
690881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
691881Sjohnny 		    *(int *)result));
692881Sjohnny 		break;
693881Sjohnny 	default:
694881Sjohnny 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
695881Sjohnny 	}
696881Sjohnny 
697881Sjohnny 	return (DDI_SUCCESS);
698881Sjohnny }
699881Sjohnny 
700916Sschwartz int
701916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
702916Sschwartz     int vecirq, boolean_t is_irq)
703916Sschwartz {
704916Sschwartz 	ddi_intr_handle_impl_t	get_info_ii_hdl;
705916Sschwartz 
706916Sschwartz 	if (is_irq)
707916Sschwartz 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
708916Sschwartz 
709916Sschwartz 	/*
710916Sschwartz 	 * For this locally-declared and used handle, ih_private will contain a
711916Sschwartz 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
712916Sschwartz 	 * global interrupt handling.
713916Sschwartz 	 */
714916Sschwartz 	get_info_ii_hdl.ih_private = intrinfo_p;
715916Sschwartz 	get_info_ii_hdl.ih_vector = (ushort_t)vecirq;
716916Sschwartz 
717916Sschwartz 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
718916Sschwartz 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
719916Sschwartz 		return (DDI_FAILURE);
720916Sschwartz 
721916Sschwartz 	return (DDI_SUCCESS);
722916Sschwartz }
723916Sschwartz 
724916Sschwartz 
725916Sschwartz int
726916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
727916Sschwartz {
728916Sschwartz 	int rval;
729916Sschwartz 
730916Sschwartz 	apic_get_intr_t	intrinfo;
731916Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
732916Sschwartz 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
733916Sschwartz 
734916Sschwartz 	if (rval == DDI_SUCCESS)
735916Sschwartz 		return (intrinfo.avgi_cpu_id);
736916Sschwartz 	else
737916Sschwartz 		return (-1);
738916Sschwartz }
739916Sschwartz 
740881Sjohnny 
741881Sjohnny static int
742881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
743881Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
744881Sjohnny {
745881Sjohnny 	struct intrspec	*ispec;
746916Sschwartz 	int		irq;
747916Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
748881Sjohnny 
749881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
750881Sjohnny 	    (void *)hdlp, inum));
751881Sjohnny 
752881Sjohnny 	/* Translate the interrupt if needed */
753881Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
7542288Sanish 	if (ispec == NULL)
7552288Sanish 		return (DDI_FAILURE);
7562288Sanish 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
757881Sjohnny 		ispec->intrspec_vec = inum;
758916Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
759881Sjohnny 
760881Sjohnny 	/* translate the interrupt if needed */
761916Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
762916Sschwartz 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
763916Sschwartz 	    hdlp->ih_pri, irq));
764881Sjohnny 
765881Sjohnny 	/* Add the interrupt handler */
766881Sjohnny 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
767916Sschwartz 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
768916Sschwartz 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
769881Sjohnny 		return (DDI_FAILURE);
770881Sjohnny 
771916Sschwartz 	/* Note this really is an irq. */
772916Sschwartz 	hdlp->ih_vector = (ushort_t)irq;
773916Sschwartz 
774881Sjohnny 	return (DDI_SUCCESS);
775881Sjohnny }
776881Sjohnny 
777881Sjohnny 
778881Sjohnny static void
779881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
780881Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
781881Sjohnny {
782916Sschwartz 	int		irq;
783881Sjohnny 	struct intrspec	*ispec;
784916Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
785881Sjohnny 
786881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
787881Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
7882288Sanish 	if (ispec == NULL)
7892288Sanish 		return;
7902288Sanish 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
791881Sjohnny 		ispec->intrspec_vec = inum;
792916Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
793881Sjohnny 
794881Sjohnny 	/* translate the interrupt if needed */
795916Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
796881Sjohnny 
797881Sjohnny 	/* Disable the interrupt handler */
798916Sschwartz 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
799916Sschwartz 	ihdl_plat_datap->ip_ispecp = NULL;
800881Sjohnny }
801881Sjohnny 
802881Sjohnny /*
803881Sjohnny  * Miscellaneous library function
804881Sjohnny  */
805881Sjohnny int
806881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
807881Sjohnny {
808881Sjohnny 	int		i;
809881Sjohnny 	int 		number;
810881Sjohnny 	int		assigned_addr_len;
811881Sjohnny 	uint_t		phys_hi = pci_rp->pci_phys_hi;
812881Sjohnny 	pci_regspec_t	*assigned_addr;
813881Sjohnny 
814881Sjohnny 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
815881Sjohnny 	    (phys_hi & PCI_RELOCAT_B))
816881Sjohnny 		return (DDI_SUCCESS);
817881Sjohnny 
818881Sjohnny 	/*
819881Sjohnny 	 * the "reg" property specifies relocatable, get and interpret the
820881Sjohnny 	 * "assigned-addresses" property.
821881Sjohnny 	 */
822881Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
823881Sjohnny 	    "assigned-addresses", (int **)&assigned_addr,
824881Sjohnny 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
825881Sjohnny 		return (DDI_FAILURE);
826881Sjohnny 
827881Sjohnny 	/*
828881Sjohnny 	 * Scan the "assigned-addresses" for one that matches the specified
829881Sjohnny 	 * "reg" property entry.
830881Sjohnny 	 */
831881Sjohnny 	phys_hi &= PCI_CONF_ADDR_MASK;
832881Sjohnny 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
833881Sjohnny 	for (i = 0; i < number; i++) {
834881Sjohnny 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
835881Sjohnny 		    phys_hi) {
836881Sjohnny 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
837881Sjohnny 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
838881Sjohnny 			ddi_prop_free(assigned_addr);
839881Sjohnny 			return (DDI_SUCCESS);
840881Sjohnny 		}
841881Sjohnny 	}
842881Sjohnny 
843881Sjohnny 	ddi_prop_free(assigned_addr);
844881Sjohnny 	return (DDI_FAILURE);
845881Sjohnny }
846881Sjohnny 
847881Sjohnny 
848881Sjohnny /*
849881Sjohnny  * For pci_tools
850881Sjohnny  */
851881Sjohnny 
852881Sjohnny int
853881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
854881Sjohnny     int mode, cred_t *credp, int *rvalp)
855881Sjohnny {
856881Sjohnny 	int rv = ENOTTY;
857881Sjohnny 
858881Sjohnny 	minor_t minor = getminor(dev);
859881Sjohnny 
860881Sjohnny 	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
861881Sjohnny 	case PCI_TOOL_REG_MINOR_NUM:
862881Sjohnny 
863881Sjohnny 		switch (cmd) {
864881Sjohnny 		case PCITOOL_DEVICE_SET_REG:
865881Sjohnny 		case PCITOOL_DEVICE_GET_REG:
866881Sjohnny 
867881Sjohnny 			/* Require full privileges. */
868881Sjohnny 			if (secpolicy_kmdb(credp))
869881Sjohnny 				rv = EPERM;
870881Sjohnny 			else
871881Sjohnny 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
872881Sjohnny 				    cmd, mode);
873881Sjohnny 			break;
874881Sjohnny 
875881Sjohnny 		case PCITOOL_NEXUS_SET_REG:
876881Sjohnny 		case PCITOOL_NEXUS_GET_REG:
877881Sjohnny 
878881Sjohnny 			/* Require full privileges. */
879881Sjohnny 			if (secpolicy_kmdb(credp))
880881Sjohnny 				rv = EPERM;
881881Sjohnny 			else
882881Sjohnny 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
883881Sjohnny 				    cmd, mode);
884881Sjohnny 			break;
885881Sjohnny 		}
886881Sjohnny 		break;
887881Sjohnny 
888881Sjohnny 	case PCI_TOOL_INTR_MINOR_NUM:
889881Sjohnny 
890881Sjohnny 		switch (cmd) {
891881Sjohnny 		case PCITOOL_DEVICE_SET_INTR:
892881Sjohnny 
893881Sjohnny 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
894881Sjohnny 			if (secpolicy_ponline(credp)) {
895881Sjohnny 				rv = EPERM;
896881Sjohnny 				break;
897881Sjohnny 			}
898881Sjohnny 
899881Sjohnny 		/*FALLTHRU*/
900881Sjohnny 		/* These require no special privileges. */
901881Sjohnny 		case PCITOOL_DEVICE_GET_INTR:
902881Sjohnny 		case PCITOOL_DEVICE_NUM_INTR:
903881Sjohnny 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
904881Sjohnny 			break;
905881Sjohnny 		}
906881Sjohnny 		break;
907881Sjohnny 
908881Sjohnny 	/*
909881Sjohnny 	 * All non-PCItool ioctls go through here, including:
910881Sjohnny 	 *   devctl ioctls with minor number PCIHP_DEVCTL_MINOR and
911881Sjohnny 	 *   those for attachment points with where minor number is the
912881Sjohnny 	 *   device number.
913881Sjohnny 	 */
914881Sjohnny 	default:
915881Sjohnny 		rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
916881Sjohnny 		    credp, rvalp);
917881Sjohnny 		break;
918881Sjohnny 	}
919881Sjohnny 
920881Sjohnny 	return (rv);
921881Sjohnny }
9221083Sanish 
9231083Sanish 
9241865Sdilpreet int
9251865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
9261865Sdilpreet {
9271865Sdilpreet 	size_t size = in_args->size;
9281865Sdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
9291865Sdilpreet 	uintptr_t host_addr = in_args->host_addr;
9301865Sdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
9311865Sdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
9321865Sdilpreet 	size_t repcount = in_args->repcount;
9331865Sdilpreet 	uint_t flags = in_args->flags;
9341865Sdilpreet 	int err = DDI_SUCCESS;
9351865Sdilpreet 
9361865Sdilpreet 	/*
9371865Sdilpreet 	 * if no handle then this is a poke. We have to return failure here
9381865Sdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
9391865Sdilpreet 	 */
9401865Sdilpreet 	if (in_args->handle == NULL)
9411865Sdilpreet 		return (DDI_FAILURE);
9421865Sdilpreet 
9431865Sdilpreet 	/*
9441865Sdilpreet 	 * rest of this function is actually for cautious puts
9451865Sdilpreet 	 */
9461865Sdilpreet 	for (; repcount; repcount--) {
9471865Sdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
9481865Sdilpreet 			switch (size) {
9491865Sdilpreet 			case sizeof (uint8_t):
9501865Sdilpreet 				pci_config_wr8(hp, (uint8_t *)dev_addr,
9511865Sdilpreet 				    *(uint8_t *)host_addr);
9521865Sdilpreet 				break;
9531865Sdilpreet 			case sizeof (uint16_t):
9541865Sdilpreet 				pci_config_wr16(hp, (uint16_t *)dev_addr,
9551865Sdilpreet 				    *(uint16_t *)host_addr);
9561865Sdilpreet 				break;
9571865Sdilpreet 			case sizeof (uint32_t):
9581865Sdilpreet 				pci_config_wr32(hp, (uint32_t *)dev_addr,
9591865Sdilpreet 				    *(uint32_t *)host_addr);
9601865Sdilpreet 				break;
9611865Sdilpreet 			case sizeof (uint64_t):
9621865Sdilpreet 				pci_config_wr64(hp, (uint64_t *)dev_addr,
9631865Sdilpreet 				    *(uint64_t *)host_addr);
9641865Sdilpreet 				break;
9651865Sdilpreet 			default:
9661865Sdilpreet 				err = DDI_FAILURE;
9671865Sdilpreet 				break;
9681865Sdilpreet 			}
9691865Sdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
9701865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
9711865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
9721865Sdilpreet 				switch (size) {
9731865Sdilpreet 				case sizeof (uint8_t):
9741865Sdilpreet 					i_ddi_io_put8(hp,
9751865Sdilpreet 					    (uint8_t *)dev_addr,
9761865Sdilpreet 					    *(uint8_t *)host_addr);
9771865Sdilpreet 					break;
9781865Sdilpreet 				case sizeof (uint16_t):
9791865Sdilpreet 					i_ddi_io_swap_put16(hp,
9801865Sdilpreet 					    (uint16_t *)dev_addr,
9811865Sdilpreet 					    *(uint16_t *)host_addr);
9821865Sdilpreet 					break;
9831865Sdilpreet 				case sizeof (uint32_t):
9841865Sdilpreet 					i_ddi_io_swap_put32(hp,
9851865Sdilpreet 					    (uint32_t *)dev_addr,
9861865Sdilpreet 					    *(uint32_t *)host_addr);
9871865Sdilpreet 					break;
9881865Sdilpreet 				/*
9891865Sdilpreet 				 * note the 64-bit case is a dummy
9901865Sdilpreet 				 * function - so no need to swap
9911865Sdilpreet 				 */
9921865Sdilpreet 				case sizeof (uint64_t):
9931865Sdilpreet 					i_ddi_io_put64(hp,
9941865Sdilpreet 					    (uint64_t *)dev_addr,
9951865Sdilpreet 					    *(uint64_t *)host_addr);
9961865Sdilpreet 					break;
9971865Sdilpreet 				default:
9981865Sdilpreet 					err = DDI_FAILURE;
9991865Sdilpreet 					break;
10001865Sdilpreet 				}
10011865Sdilpreet 			} else {
10021865Sdilpreet 				switch (size) {
10031865Sdilpreet 				case sizeof (uint8_t):
10041865Sdilpreet 					i_ddi_io_put8(hp,
10051865Sdilpreet 					    (uint8_t *)dev_addr,
10061865Sdilpreet 					    *(uint8_t *)host_addr);
10071865Sdilpreet 					break;
10081865Sdilpreet 				case sizeof (uint16_t):
10091865Sdilpreet 					i_ddi_io_put16(hp,
10101865Sdilpreet 					    (uint16_t *)dev_addr,
10111865Sdilpreet 					    *(uint16_t *)host_addr);
10121865Sdilpreet 					break;
10131865Sdilpreet 				case sizeof (uint32_t):
10141865Sdilpreet 					i_ddi_io_put32(hp,
10151865Sdilpreet 					    (uint32_t *)dev_addr,
10161865Sdilpreet 					    *(uint32_t *)host_addr);
10171865Sdilpreet 					break;
10181865Sdilpreet 				case sizeof (uint64_t):
10191865Sdilpreet 					i_ddi_io_put64(hp,
10201865Sdilpreet 					    (uint64_t *)dev_addr,
10211865Sdilpreet 					    *(uint64_t *)host_addr);
10221865Sdilpreet 					break;
10231865Sdilpreet 				default:
10241865Sdilpreet 					err = DDI_FAILURE;
10251865Sdilpreet 					break;
10261865Sdilpreet 				}
10271865Sdilpreet 			}
10281865Sdilpreet 		} else {
10291865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
10301865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
10311865Sdilpreet 				switch (size) {
10321865Sdilpreet 				case sizeof (uint8_t):
10331865Sdilpreet 					*(uint8_t *)dev_addr =
10341865Sdilpreet 					    *(uint8_t *)host_addr;
10351865Sdilpreet 					break;
10361865Sdilpreet 				case sizeof (uint16_t):
10371865Sdilpreet 					*(uint16_t *)dev_addr =
10381865Sdilpreet 					    ddi_swap16(*(uint16_t *)host_addr);
10391865Sdilpreet 					break;
10401865Sdilpreet 				case sizeof (uint32_t):
10411865Sdilpreet 					*(uint32_t *)dev_addr =
10421865Sdilpreet 					    ddi_swap32(*(uint32_t *)host_addr);
10431865Sdilpreet 					break;
10441865Sdilpreet 				case sizeof (uint64_t):
10451865Sdilpreet 					*(uint64_t *)dev_addr =
10461865Sdilpreet 					    ddi_swap64(*(uint64_t *)host_addr);
10471865Sdilpreet 					break;
10481865Sdilpreet 				default:
10491865Sdilpreet 					err = DDI_FAILURE;
10501865Sdilpreet 					break;
10511865Sdilpreet 				}
10521865Sdilpreet 			} else {
10531865Sdilpreet 				switch (size) {
10541865Sdilpreet 				case sizeof (uint8_t):
10551865Sdilpreet 					*(uint8_t *)dev_addr =
10561865Sdilpreet 					    *(uint8_t *)host_addr;
10571865Sdilpreet 					break;
10581865Sdilpreet 				case sizeof (uint16_t):
10591865Sdilpreet 					*(uint16_t *)dev_addr =
10601865Sdilpreet 					    *(uint16_t *)host_addr;
10611865Sdilpreet 					break;
10621865Sdilpreet 				case sizeof (uint32_t):
10631865Sdilpreet 					*(uint32_t *)dev_addr =
10641865Sdilpreet 					    *(uint32_t *)host_addr;
10651865Sdilpreet 					break;
10661865Sdilpreet 				case sizeof (uint64_t):
10671865Sdilpreet 					*(uint64_t *)dev_addr =
10681865Sdilpreet 					    *(uint64_t *)host_addr;
10691865Sdilpreet 					break;
10701865Sdilpreet 				default:
10711865Sdilpreet 					err = DDI_FAILURE;
10721865Sdilpreet 					break;
10731865Sdilpreet 				}
10741865Sdilpreet 			}
10751865Sdilpreet 		}
10761865Sdilpreet 		host_addr += size;
10771865Sdilpreet 		if (flags == DDI_DEV_AUTOINCR)
10781865Sdilpreet 			dev_addr += size;
10791865Sdilpreet 	}
10801865Sdilpreet 	return (err);
10811865Sdilpreet }
10821865Sdilpreet 
10831865Sdilpreet 
10841865Sdilpreet int
10851865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
10861865Sdilpreet {
10871865Sdilpreet 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
10881865Sdilpreet 
10891865Sdilpreet 	/* endian-ness check */
10901865Sdilpreet 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
10911865Sdilpreet 		return (DDI_FAILURE);
10921865Sdilpreet 
10931865Sdilpreet 	/*
10941865Sdilpreet 	 * range check
10951865Sdilpreet 	 */
10961865Sdilpreet 	if ((offset >= PCI_CONF_HDR_SIZE) ||
10971865Sdilpreet 	    (len > PCI_CONF_HDR_SIZE) ||
10981865Sdilpreet 	    (offset + len > PCI_CONF_HDR_SIZE))
10991865Sdilpreet 		return (DDI_FAILURE);
11001865Sdilpreet 
11011865Sdilpreet 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
11021865Sdilpreet 	/*
11031865Sdilpreet 	 * always use cautious mechanism for config space gets
11041865Sdilpreet 	 */
11051865Sdilpreet 	ap->ahi_get8 = i_ddi_caut_get8;
11061865Sdilpreet 	ap->ahi_get16 = i_ddi_caut_get16;
11071865Sdilpreet 	ap->ahi_get32 = i_ddi_caut_get32;
11081865Sdilpreet 	ap->ahi_get64 = i_ddi_caut_get64;
11091865Sdilpreet 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
11101865Sdilpreet 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
11111865Sdilpreet 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
11121865Sdilpreet 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
11131865Sdilpreet 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
11141865Sdilpreet 		ap->ahi_put8 = i_ddi_caut_put8;
11151865Sdilpreet 		ap->ahi_put16 = i_ddi_caut_put16;
11161865Sdilpreet 		ap->ahi_put32 = i_ddi_caut_put32;
11171865Sdilpreet 		ap->ahi_put64 = i_ddi_caut_put64;
11181865Sdilpreet 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
11191865Sdilpreet 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
11201865Sdilpreet 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
11211865Sdilpreet 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
11221865Sdilpreet 	} else {
11231865Sdilpreet 		ap->ahi_put8 = pci_config_wr8;
11241865Sdilpreet 		ap->ahi_put16 = pci_config_wr16;
11251865Sdilpreet 		ap->ahi_put32 = pci_config_wr32;
11261865Sdilpreet 		ap->ahi_put64 = pci_config_wr64;
11271865Sdilpreet 		ap->ahi_rep_put8 = pci_config_rep_wr8;
11281865Sdilpreet 		ap->ahi_rep_put16 = pci_config_rep_wr16;
11291865Sdilpreet 		ap->ahi_rep_put32 = pci_config_rep_wr32;
11301865Sdilpreet 		ap->ahi_rep_put64 = pci_config_rep_wr64;
11311865Sdilpreet 	}
11321865Sdilpreet 
11331865Sdilpreet 	/* Initialize to default check/notify functions */
11341865Sdilpreet 	ap->ahi_fault_check = i_ddi_acc_fault_check;
11351865Sdilpreet 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
11361865Sdilpreet 	ap->ahi_fault = 0;
11371865Sdilpreet 	impl_acc_err_init(hp);
11381865Sdilpreet 	return (DDI_SUCCESS);
11391865Sdilpreet }
11401865Sdilpreet 
11411865Sdilpreet 
11421865Sdilpreet int
11431865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
11441865Sdilpreet {
11451865Sdilpreet 	size_t size = in_args->size;
11461865Sdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
11471865Sdilpreet 	uintptr_t host_addr = in_args->host_addr;
11481865Sdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
11491865Sdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
11501865Sdilpreet 	size_t repcount = in_args->repcount;
11511865Sdilpreet 	uint_t flags = in_args->flags;
11521865Sdilpreet 	int err = DDI_SUCCESS;
11531865Sdilpreet 
11541865Sdilpreet 	/*
11551865Sdilpreet 	 * if no handle then this is a peek. We have to return failure here
11561865Sdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
11571865Sdilpreet 	 */
11581865Sdilpreet 	if (in_args->handle == NULL)
11591865Sdilpreet 		return (DDI_FAILURE);
11601865Sdilpreet 
11611865Sdilpreet 	for (; repcount; repcount--) {
11621865Sdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
11631865Sdilpreet 			switch (size) {
11641865Sdilpreet 			case sizeof (uint8_t):
11651865Sdilpreet 				*(uint8_t *)host_addr = pci_config_rd8(hp,
11661865Sdilpreet 				    (uint8_t *)dev_addr);
11671865Sdilpreet 				break;
11681865Sdilpreet 			case sizeof (uint16_t):
11691865Sdilpreet 				*(uint16_t *)host_addr = pci_config_rd16(hp,
11701865Sdilpreet 				    (uint16_t *)dev_addr);
11711865Sdilpreet 				break;
11721865Sdilpreet 			case sizeof (uint32_t):
11731865Sdilpreet 				*(uint32_t *)host_addr = pci_config_rd32(hp,
11741865Sdilpreet 				    (uint32_t *)dev_addr);
11751865Sdilpreet 				break;
11761865Sdilpreet 			case sizeof (uint64_t):
11771865Sdilpreet 				*(uint64_t *)host_addr = pci_config_rd64(hp,
11781865Sdilpreet 				    (uint64_t *)dev_addr);
11791865Sdilpreet 				break;
11801865Sdilpreet 			default:
11811865Sdilpreet 				err = DDI_FAILURE;
11821865Sdilpreet 				break;
11831865Sdilpreet 			}
11841865Sdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
11851865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
11861865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
11871865Sdilpreet 				switch (size) {
11881865Sdilpreet 				case sizeof (uint8_t):
11891865Sdilpreet 					*(uint8_t *)host_addr =
11901865Sdilpreet 					    i_ddi_io_get8(hp,
11911865Sdilpreet 					    (uint8_t *)dev_addr);
11921865Sdilpreet 					break;
11931865Sdilpreet 				case sizeof (uint16_t):
11941865Sdilpreet 					*(uint16_t *)host_addr =
11951865Sdilpreet 					    i_ddi_io_swap_get16(hp,
11961865Sdilpreet 					    (uint16_t *)dev_addr);
11971865Sdilpreet 					break;
11981865Sdilpreet 				case sizeof (uint32_t):
11991865Sdilpreet 					*(uint32_t *)host_addr =
12001865Sdilpreet 					    i_ddi_io_swap_get32(hp,
12011865Sdilpreet 					    (uint32_t *)dev_addr);
12021865Sdilpreet 					break;
12031865Sdilpreet 				/*
12041865Sdilpreet 				 * note the 64-bit case is a dummy
12051865Sdilpreet 				 * function - so no need to swap
12061865Sdilpreet 				 */
12071865Sdilpreet 				case sizeof (uint64_t):
12081865Sdilpreet 					*(uint64_t *)host_addr =
12091865Sdilpreet 					    i_ddi_io_get64(hp,
12101865Sdilpreet 					    (uint64_t *)dev_addr);
12111865Sdilpreet 					break;
12121865Sdilpreet 				default:
12131865Sdilpreet 					err = DDI_FAILURE;
12141865Sdilpreet 					break;
12151865Sdilpreet 				}
12161865Sdilpreet 			} else {
12171865Sdilpreet 				switch (size) {
12181865Sdilpreet 				case sizeof (uint8_t):
12191865Sdilpreet 					*(uint8_t *)host_addr =
12201865Sdilpreet 					    i_ddi_io_get8(hp,
12211865Sdilpreet 					    (uint8_t *)dev_addr);
12221865Sdilpreet 					break;
12231865Sdilpreet 				case sizeof (uint16_t):
12241865Sdilpreet 					*(uint16_t *)host_addr =
12251865Sdilpreet 					    i_ddi_io_get16(hp,
12261865Sdilpreet 					    (uint16_t *)dev_addr);
12271865Sdilpreet 					break;
12281865Sdilpreet 				case sizeof (uint32_t):
12291865Sdilpreet 					*(uint32_t *)host_addr =
12301865Sdilpreet 					    i_ddi_io_get32(hp,
12311865Sdilpreet 					    (uint32_t *)dev_addr);
12321865Sdilpreet 					break;
12331865Sdilpreet 				case sizeof (uint64_t):
12341865Sdilpreet 					*(uint64_t *)host_addr =
12351865Sdilpreet 					    i_ddi_io_get64(hp,
12361865Sdilpreet 					    (uint64_t *)dev_addr);
12371865Sdilpreet 					break;
12381865Sdilpreet 				default:
12391865Sdilpreet 					err = DDI_FAILURE;
12401865Sdilpreet 					break;
12411865Sdilpreet 				}
12421865Sdilpreet 			}
12431865Sdilpreet 		} else {
12441865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
12451865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
12461865Sdilpreet 				switch (in_args->size) {
12471865Sdilpreet 				case sizeof (uint8_t):
12481865Sdilpreet 					*(uint8_t *)host_addr =
12491865Sdilpreet 					    *(uint8_t *)dev_addr;
12501865Sdilpreet 					break;
12511865Sdilpreet 				case sizeof (uint16_t):
12521865Sdilpreet 					*(uint16_t *)host_addr =
12531865Sdilpreet 					    ddi_swap16(*(uint16_t *)dev_addr);
12541865Sdilpreet 					break;
12551865Sdilpreet 				case sizeof (uint32_t):
12561865Sdilpreet 					*(uint32_t *)host_addr =
12571865Sdilpreet 					    ddi_swap32(*(uint32_t *)dev_addr);
12581865Sdilpreet 					break;
12591865Sdilpreet 				case sizeof (uint64_t):
12601865Sdilpreet 					*(uint64_t *)host_addr =
12611865Sdilpreet 					    ddi_swap64(*(uint64_t *)dev_addr);
12621865Sdilpreet 					break;
12631865Sdilpreet 				default:
12641865Sdilpreet 					err = DDI_FAILURE;
12651865Sdilpreet 					break;
12661865Sdilpreet 				}
12671865Sdilpreet 			} else {
12681865Sdilpreet 				switch (in_args->size) {
12691865Sdilpreet 				case sizeof (uint8_t):
12701865Sdilpreet 					*(uint8_t *)host_addr =
12711865Sdilpreet 					    *(uint8_t *)dev_addr;
12721865Sdilpreet 					break;
12731865Sdilpreet 				case sizeof (uint16_t):
12741865Sdilpreet 					*(uint16_t *)host_addr =
12751865Sdilpreet 					    *(uint16_t *)dev_addr;
12761865Sdilpreet 					break;
12771865Sdilpreet 				case sizeof (uint32_t):
12781865Sdilpreet 					*(uint32_t *)host_addr =
12791865Sdilpreet 					    *(uint32_t *)dev_addr;
12801865Sdilpreet 					break;
12811865Sdilpreet 				case sizeof (uint64_t):
12821865Sdilpreet 					*(uint64_t *)host_addr =
12831865Sdilpreet 					    *(uint64_t *)dev_addr;
12841865Sdilpreet 					break;
12851865Sdilpreet 				default:
12861865Sdilpreet 					err = DDI_FAILURE;
12871865Sdilpreet 					break;
12881865Sdilpreet 				}
12891865Sdilpreet 			}
12901865Sdilpreet 		}
12911865Sdilpreet 		host_addr += size;
12921865Sdilpreet 		if (flags == DDI_DEV_AUTOINCR)
12931865Sdilpreet 			dev_addr += size;
12941865Sdilpreet 	}
12951865Sdilpreet 	return (err);
12961865Sdilpreet }
12971865Sdilpreet 
12981865Sdilpreet /*ARGSUSED*/
12991865Sdilpreet int
13001865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
13011865Sdilpreet 	ddi_ctl_enum_t ctlop, void *arg, void *result)
13021865Sdilpreet {
13031865Sdilpreet 	if (ctlop == DDI_CTLOPS_PEEK)
13041865Sdilpreet 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
13051865Sdilpreet 	else
13061865Sdilpreet 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
13071865Sdilpreet }
13081865Sdilpreet 
13091083Sanish /*
13101083Sanish  * These are the get and put functions to be shared with drivers. The
13111083Sanish  * mutex locking is done inside the functions referenced, rather than
13121083Sanish  * here, and is thus shared across PCI child drivers and any other
13131083Sanish  * consumers of PCI config space (such as the ACPI subsystem).
13141083Sanish  *
13151083Sanish  * The configuration space addresses come in as pointers.  This is fine on
13161083Sanish  * a 32-bit system, where the VM space and configuration space are the same
13171083Sanish  * size.  It's not such a good idea on a 64-bit system, where memory
13181083Sanish  * addresses are twice as large as configuration space addresses.  At some
13191083Sanish  * point in the call tree we need to take a stand and say "you are 32-bit
13201083Sanish  * from this time forth", and this seems like a nice self-contained place.
13211083Sanish  */
13221083Sanish 
13231083Sanish uint8_t
13241083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
13251083Sanish {
13261083Sanish 	pci_acc_cfblk_t *cfp;
13271083Sanish 	uint8_t	rval;
13281083Sanish 	int reg;
13291083Sanish 
13301083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
13311083Sanish 
13321083Sanish 	reg = (int)(uintptr_t)addr;
13331083Sanish 
13341083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
13351083Sanish 
13361083Sanish 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
13371083Sanish 	    reg);
13381083Sanish 
13391083Sanish 	return (rval);
13401083Sanish }
13411083Sanish 
13421083Sanish void
13431083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
13441083Sanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
13451083Sanish {
13461083Sanish 	uint8_t *h, *d;
13471083Sanish 
13481083Sanish 	h = host_addr;
13491083Sanish 	d = dev_addr;
13501083Sanish 
13511083Sanish 	if (flags == DDI_DEV_AUTOINCR)
13521083Sanish 		for (; repcount; repcount--)
13531083Sanish 			*h++ = pci_config_rd8(hdlp, d++);
13541083Sanish 	else
13551083Sanish 		for (; repcount; repcount--)
13561083Sanish 			*h++ = pci_config_rd8(hdlp, d);
13571083Sanish }
13581083Sanish 
13591083Sanish uint16_t
13601083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
13611083Sanish {
13621083Sanish 	pci_acc_cfblk_t *cfp;
13631083Sanish 	uint16_t rval;
13641083Sanish 	int reg;
13651083Sanish 
13661083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
13671083Sanish 
13681083Sanish 	reg = (int)(uintptr_t)addr;
13691083Sanish 
13701083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
13711083Sanish 
13721083Sanish 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
13731083Sanish 	    reg);
13741083Sanish 
13751083Sanish 	return (rval);
13761083Sanish }
13771083Sanish 
13781083Sanish void
13791083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
13801083Sanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
13811083Sanish {
13821083Sanish 	uint16_t *h, *d;
13831083Sanish 
13841083Sanish 	h = host_addr;
13851083Sanish 	d = dev_addr;
13861083Sanish 
13871083Sanish 	if (flags == DDI_DEV_AUTOINCR)
13881083Sanish 		for (; repcount; repcount--)
13891083Sanish 			*h++ = pci_config_rd16(hdlp, d++);
13901083Sanish 	else
13911083Sanish 		for (; repcount; repcount--)
13921083Sanish 			*h++ = pci_config_rd16(hdlp, d);
13931083Sanish }
13941083Sanish 
13951083Sanish uint32_t
13961083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
13971083Sanish {
13981083Sanish 	pci_acc_cfblk_t *cfp;
13991083Sanish 	uint32_t rval;
14001083Sanish 	int reg;
14011083Sanish 
14021083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
14031083Sanish 
14041083Sanish 	reg = (int)(uintptr_t)addr;
14051083Sanish 
14061083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
14071083Sanish 
14081083Sanish 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
14091083Sanish 	    cfp->c_funcnum, reg);
14101083Sanish 
14111083Sanish 	return (rval);
14121083Sanish }
14131083Sanish 
14141083Sanish void
14151083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
14161083Sanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
14171083Sanish {
14181083Sanish 	uint32_t *h, *d;
14191083Sanish 
14201083Sanish 	h = host_addr;
14211083Sanish 	d = dev_addr;
14221083Sanish 
14231083Sanish 	if (flags == DDI_DEV_AUTOINCR)
14241083Sanish 		for (; repcount; repcount--)
14251083Sanish 			*h++ = pci_config_rd32(hdlp, d++);
14261083Sanish 	else
14271083Sanish 		for (; repcount; repcount--)
14281083Sanish 			*h++ = pci_config_rd32(hdlp, d);
14291083Sanish }
14301083Sanish 
14311083Sanish 
14321083Sanish void
14331083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
14341083Sanish {
14351083Sanish 	pci_acc_cfblk_t *cfp;
14361083Sanish 	int reg;
14371083Sanish 
14381083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
14391083Sanish 
14401083Sanish 	reg = (int)(uintptr_t)addr;
14411083Sanish 
14421083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
14431083Sanish 
14441083Sanish 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
14451083Sanish 	    cfp->c_funcnum, reg, value);
14461083Sanish }
14471083Sanish 
14481083Sanish void
14491083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
14501083Sanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
14511083Sanish {
14521083Sanish 	uint8_t *h, *d;
14531083Sanish 
14541083Sanish 	h = host_addr;
14551083Sanish 	d = dev_addr;
14561083Sanish 
14571083Sanish 	if (flags == DDI_DEV_AUTOINCR)
14581083Sanish 		for (; repcount; repcount--)
14591083Sanish 			pci_config_wr8(hdlp, d++, *h++);
14601083Sanish 	else
14611083Sanish 		for (; repcount; repcount--)
14621083Sanish 			pci_config_wr8(hdlp, d, *h++);
14631083Sanish }
14641083Sanish 
14651083Sanish void
14661083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
14671083Sanish {
14681083Sanish 	pci_acc_cfblk_t *cfp;
14691083Sanish 	int reg;
14701083Sanish 
14711083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
14721083Sanish 
14731083Sanish 	reg = (int)(uintptr_t)addr;
14741083Sanish 
14751083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
14761083Sanish 
14771083Sanish 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
14781083Sanish 	    cfp->c_funcnum, reg, value);
14791083Sanish }
14801083Sanish 
14811083Sanish void
14821083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
14831083Sanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
14841083Sanish {
14851083Sanish 	uint16_t *h, *d;
14861083Sanish 
14871083Sanish 	h = host_addr;
14881083Sanish 	d = dev_addr;
14891083Sanish 
14901083Sanish 	if (flags == DDI_DEV_AUTOINCR)
14911083Sanish 		for (; repcount; repcount--)
14921083Sanish 			pci_config_wr16(hdlp, d++, *h++);
14931083Sanish 	else
14941083Sanish 		for (; repcount; repcount--)
14951083Sanish 			pci_config_wr16(hdlp, d, *h++);
14961083Sanish }
14971083Sanish 
14981083Sanish void
14991083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
15001083Sanish {
15011083Sanish 	pci_acc_cfblk_t *cfp;
15021083Sanish 	int reg;
15031083Sanish 
15041083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
15051083Sanish 
15061083Sanish 	reg = (int)(uintptr_t)addr;
15071083Sanish 
15081083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15091083Sanish 
15101083Sanish 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
15111083Sanish 	    cfp->c_funcnum, reg, value);
15121083Sanish }
15131083Sanish 
15141083Sanish void
15151083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
15161083Sanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
15171083Sanish {
15181083Sanish 	uint32_t *h, *d;
15191083Sanish 
15201083Sanish 	h = host_addr;
15211083Sanish 	d = dev_addr;
15221083Sanish 
15231083Sanish 	if (flags == DDI_DEV_AUTOINCR)
15241083Sanish 		for (; repcount; repcount--)
15251083Sanish 			pci_config_wr32(hdlp, d++, *h++);
15261083Sanish 	else
15271083Sanish 		for (; repcount; repcount--)
15281083Sanish 			pci_config_wr32(hdlp, d, *h++);
15291083Sanish }
15301083Sanish 
15311083Sanish uint64_t
15321083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
15331083Sanish {
15341083Sanish 	uint32_t lw_val;
15351083Sanish 	uint32_t hi_val;
15361083Sanish 	uint32_t *dp;
15371083Sanish 	uint64_t val;
15381083Sanish 
15391083Sanish 	dp = (uint32_t *)addr;
15401083Sanish 	lw_val = pci_config_rd32(hdlp, dp);
15411083Sanish 	dp++;
15421083Sanish 	hi_val = pci_config_rd32(hdlp, dp);
15431083Sanish 	val = ((uint64_t)hi_val << 32) | lw_val;
15441083Sanish 	return (val);
15451083Sanish }
15461083Sanish 
15471083Sanish void
15481083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
15491083Sanish {
15501083Sanish 	uint32_t lw_val;
15511083Sanish 	uint32_t hi_val;
15521083Sanish 	uint32_t *dp;
15531083Sanish 
15541083Sanish 	dp = (uint32_t *)addr;
15551083Sanish 	lw_val = (uint32_t)(value & 0xffffffff);
15561083Sanish 	hi_val = (uint32_t)(value >> 32);
15571083Sanish 	pci_config_wr32(hdlp, dp, lw_val);
15581083Sanish 	dp++;
15591083Sanish 	pci_config_wr32(hdlp, dp, hi_val);
15601083Sanish }
15611083Sanish 
15621083Sanish void
15631083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
15641083Sanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
15651083Sanish {
15661083Sanish 	if (flags == DDI_DEV_AUTOINCR) {
15671083Sanish 		for (; repcount; repcount--)
15681083Sanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
15691083Sanish 	} else {
15701083Sanish 		for (; repcount; repcount--)
15711083Sanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
15721083Sanish 	}
15731083Sanish }
15741083Sanish 
15751083Sanish void
15761083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
15771083Sanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
15781083Sanish {
15791083Sanish 	if (flags == DDI_DEV_AUTOINCR) {
15801083Sanish 		for (; repcount; repcount--)
15811083Sanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
15821083Sanish 	} else {
15831083Sanish 		for (; repcount; repcount--)
15841083Sanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
15851083Sanish 	}
15861083Sanish }
15871083Sanish 
15881083Sanish 
15891083Sanish /*
15901083Sanish  * Enable Legacy PCI config space access for the following four north bridges
15911083Sanish  *	Host bridge: AMD HyperTransport Technology Configuration
15921083Sanish  *	Host bridge: AMD Address Map
15931083Sanish  *	Host bridge: AMD DRAM Controller
15941083Sanish  *	Host bridge: AMD Miscellaneous Control
15951083Sanish  */
15961083Sanish int
15971083Sanish is_amd_northbridge(dev_info_t *dip)
15981083Sanish {
15991083Sanish 	int vendor_id, device_id;
16001083Sanish 
16011083Sanish 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
16021083Sanish 			"vendor-id", -1);
16031083Sanish 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
16041083Sanish 			"device-id", -1);
16051083Sanish 
16061083Sanish 	if (IS_AMD_NTBRIDGE(vendor_id, device_id))
16071083Sanish 		return (0);
16081083Sanish 
16091083Sanish 	return (1);
16101083Sanish }
1611