xref: /onnv-gate/usr/src/uts/i86pc/io/pci/pci_common.c (revision 2580:f32d67e0b369)
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 /*
231542Sjohnny  * Copyright 2006 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>
48916Sschwartz #include <io/pcplusmp/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>
55881Sjohnny 
56881Sjohnny /*
57881Sjohnny  * Function prototypes
58881Sjohnny  */
59881Sjohnny static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
60881Sjohnny static int	pci_enable_intr(dev_info_t *, dev_info_t *,
61881Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
62881Sjohnny static void	pci_disable_intr(dev_info_t *, dev_info_t *,
63881Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
64881Sjohnny 
65881Sjohnny /* Extern decalration for pcplusmp module */
66881Sjohnny extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
67881Sjohnny 		    psm_intr_op_t, int *);
68881Sjohnny 
69881Sjohnny 
70881Sjohnny /*
71881Sjohnny  * pci_name_child:
72881Sjohnny  *
73881Sjohnny  *	Assign the address portion of the node name
74881Sjohnny  */
75881Sjohnny int
76881Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
77881Sjohnny {
78881Sjohnny 	int		dev, func, length;
79881Sjohnny 	char		**unit_addr;
80881Sjohnny 	uint_t		n;
81881Sjohnny 	pci_regspec_t	*pci_rp;
82881Sjohnny 
83881Sjohnny 	if (ndi_dev_is_persistent_node(child) == 0) {
84881Sjohnny 		/*
85881Sjohnny 		 * For .conf node, use "unit-address" property
86881Sjohnny 		 */
87881Sjohnny 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
88881Sjohnny 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
89881Sjohnny 		    DDI_PROP_SUCCESS) {
90881Sjohnny 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
91881Sjohnny 			    ddi_get_name(child));
92881Sjohnny 			return (DDI_FAILURE);
93881Sjohnny 		}
94881Sjohnny 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
95881Sjohnny 			cmn_err(CE_WARN, "unit-address property in %s.conf"
96881Sjohnny 			    " not well-formed", ddi_get_name(child));
97881Sjohnny 			ddi_prop_free(unit_addr);
98881Sjohnny 			return (DDI_FAILURE);
99881Sjohnny 		}
100881Sjohnny 		(void) snprintf(name, namelen, "%s", *unit_addr);
101881Sjohnny 		ddi_prop_free(unit_addr);
102881Sjohnny 		return (DDI_SUCCESS);
103881Sjohnny 	}
104881Sjohnny 
105881Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
106881Sjohnny 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
107881Sjohnny 		cmn_err(CE_WARN, "cannot find reg property in %s",
108881Sjohnny 		    ddi_get_name(child));
109881Sjohnny 		return (DDI_FAILURE);
110881Sjohnny 	}
111881Sjohnny 
112881Sjohnny 	/* copy the device identifications */
113881Sjohnny 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
114881Sjohnny 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
115881Sjohnny 
116881Sjohnny 	/*
117881Sjohnny 	 * free the memory allocated by ddi_prop_lookup_int_array
118881Sjohnny 	 */
119881Sjohnny 	ddi_prop_free(pci_rp);
120881Sjohnny 
121881Sjohnny 	if (func != 0) {
122881Sjohnny 		(void) snprintf(name, namelen, "%x,%x", dev, func);
123881Sjohnny 	} else {
124881Sjohnny 		(void) snprintf(name, namelen, "%x", dev);
125881Sjohnny 	}
126881Sjohnny 
127881Sjohnny 	return (DDI_SUCCESS);
128881Sjohnny }
129881Sjohnny 
130881Sjohnny /*
131881Sjohnny  * Interrupt related code:
132881Sjohnny  *
133881Sjohnny  * The following busop is common to npe and pci drivers
134881Sjohnny  *	bus_introp
135881Sjohnny  */
136881Sjohnny 
137881Sjohnny /*
138881Sjohnny  * Create the ddi_parent_private_data for a pseudo child.
139881Sjohnny  */
140881Sjohnny void
141881Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
142881Sjohnny {
143881Sjohnny 	struct ddi_parent_private_data *pdptr;
144881Sjohnny 
145881Sjohnny 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
146881Sjohnny 	    (sizeof (struct ddi_parent_private_data) +
147881Sjohnny 	sizeof (struct intrspec)), KM_SLEEP);
148881Sjohnny 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
149881Sjohnny 	pdptr->par_nintr = 1;
150881Sjohnny 	ddi_set_parent_data(dip, pdptr);
151881Sjohnny }
152881Sjohnny 
153881Sjohnny /*
154881Sjohnny  * pci_get_priority:
155881Sjohnny  *	Figure out the priority of the device
156881Sjohnny  */
157881Sjohnny static int
158881Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
159881Sjohnny {
160881Sjohnny 	struct intrspec *ispec;
161881Sjohnny 
162881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
163881Sjohnny 	    (void *)dip, (void *)hdlp));
164881Sjohnny 
165881Sjohnny 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
166881Sjohnny 	    hdlp->ih_inum)) == NULL) {
167881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
168881Sjohnny 			int class = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
169881Sjohnny 			    DDI_PROP_DONTPASS, "class-code", -1);
170881Sjohnny 
171881Sjohnny 			*pri = (class == -1) ? 1 : pci_devclass_to_ipl(class);
172881Sjohnny 			pci_common_set_parent_private_data(hdlp->ih_dip);
173881Sjohnny 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
174881Sjohnny 			    hdlp->ih_inum);
175881Sjohnny 			return (DDI_SUCCESS);
176881Sjohnny 		}
177881Sjohnny 		return (DDI_FAILURE);
178881Sjohnny 	}
179881Sjohnny 
180881Sjohnny 	*pri = ispec->intrspec_pri;
181881Sjohnny 	return (DDI_SUCCESS);
182881Sjohnny }
183881Sjohnny 
184881Sjohnny 
185881Sjohnny 
186881Sjohnny static int pcie_pci_intr_pri_counter = 0;
187881Sjohnny 
188881Sjohnny /*
189881Sjohnny  * pci_common_intr_ops: bus_intr_op() function for interrupt support
190881Sjohnny  */
191881Sjohnny int
192881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
193881Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
194881Sjohnny {
195881Sjohnny 	int			priority = 0;
196881Sjohnny 	int			psm_status = 0;
197881Sjohnny 	int			pci_status = 0;
198881Sjohnny 	int			pci_rval, psm_rval = PSM_FAILURE;
199881Sjohnny 	int			types = 0;
200881Sjohnny 	int			pciepci = 0;
2011542Sjohnny 	int			i, j, count;
202881Sjohnny 	int			behavior;
2031997Sanish 	int			cap_ptr;
204881Sjohnny 	ddi_intrspec_t		isp;
205881Sjohnny 	struct intrspec		*ispec;
206881Sjohnny 	ddi_intr_handle_impl_t	tmp_hdl;
207881Sjohnny 	ddi_intr_msix_t		*msix_p;
2081087Sschwartz 	ihdl_plat_t		*ihdl_plat_datap;
2091542Sjohnny 	ddi_intr_handle_t	*h_array;
2101997Sanish 	ddi_acc_handle_t	handle;
211881Sjohnny 
212881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT,
213881Sjohnny 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
214881Sjohnny 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
215881Sjohnny 
216881Sjohnny 	/* Process the request */
217881Sjohnny 	switch (intr_op) {
218881Sjohnny 	case DDI_INTROP_SUPPORTED_TYPES:
219881Sjohnny 		/* Fixed supported by default */
220881Sjohnny 		*(int *)result = DDI_INTR_TYPE_FIXED;
221881Sjohnny 
222881Sjohnny 		/* Figure out if MSI or MSI-X is supported? */
223881Sjohnny 		if (pci_msi_get_supported_type(rdip, &types) != DDI_SUCCESS)
224881Sjohnny 			return (DDI_SUCCESS);
225881Sjohnny 
226881Sjohnny 		if (psm_intr_ops != NULL) {
2271725Segillett 			/*
2281725Segillett 			 * Only support MSI for now, OR it in
2291725Segillett 			 */
2301725Segillett 			*(int *)result |= (types & DDI_INTR_TYPE_MSI);
231881Sjohnny 
232881Sjohnny 			tmp_hdl.ih_type = *(int *)result;
233881Sjohnny 			(void) (*psm_intr_ops)(rdip, &tmp_hdl,
234881Sjohnny 			    PSM_INTR_OP_CHECK_MSI, result);
235881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
236881Sjohnny 			    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
237881Sjohnny 			    *(int *)result));
238881Sjohnny 		}
239881Sjohnny 		break;
240*2580Sanish 	case DDI_INTROP_NAVAIL:
241881Sjohnny 	case DDI_INTROP_NINTRS:
242*2580Sanish 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
243*2580Sanish 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
244*2580Sanish 			    result) != DDI_SUCCESS)
245*2580Sanish 				return (DDI_FAILURE);
246*2580Sanish 		} else {
247*2580Sanish 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
248*2580Sanish 			if (*(int *)result == 0)
249*2580Sanish 				return (DDI_FAILURE);
250*2580Sanish 		}
251881Sjohnny 		break;
252881Sjohnny 	case DDI_INTROP_ALLOC:
253881Sjohnny 		/*
254881Sjohnny 		 * MSI or MSIX (figure out number of vectors available)
255881Sjohnny 		 * FIXED interrupts: just return available interrupts
256881Sjohnny 		 */
257881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
258881Sjohnny 		    (psm_intr_ops != NULL) &&
259881Sjohnny 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
260881Sjohnny 			/*
261881Sjohnny 			 * Following check is a special case for 'pcie_pci'.
262881Sjohnny 			 * This makes sure vectors with the right priority
263881Sjohnny 			 * are allocated for pcie_pci during ALLOC time.
264881Sjohnny 			 */
265881Sjohnny 			if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) {
266881Sjohnny 				hdlp->ih_pri =
267881Sjohnny 				    (pcie_pci_intr_pri_counter % 2) ? 4 : 7;
268881Sjohnny 				pciepci = 1;
269881Sjohnny 			} else
270881Sjohnny 				hdlp->ih_pri = priority;
2711717Swesolows 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
2721997Sanish 
2731997Sanish 			/*
2741997Sanish 			 * Cache in the config handle and cap_ptr
2751997Sanish 			 */
2761997Sanish 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
2771997Sanish 				if (pci_config_setup(rdip, &handle) !=
2781997Sanish 				    DDI_SUCCESS)
2791997Sanish 					return (DDI_FAILURE);
2801997Sanish 				i_ddi_set_pci_config_handle(rdip, handle);
2811997Sanish 			}
2821997Sanish 
2831997Sanish 			if (i_ddi_get_msi_msix_cap_ptr(rdip) == 0) {
2841997Sanish 				char *prop =
2851997Sanish 				    (hdlp->ih_type == DDI_INTR_TYPE_MSI) ?
2861997Sanish 				    "pci-msi-capid-pointer" :
2871997Sanish 				    "pci-msix-capid-pointer";
2881997Sanish 
2891997Sanish 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
2901997Sanish 				    DDI_PROP_DONTPASS, prop,
2911997Sanish 				    PCI_CAP_NEXT_PTR_NULL);
2921997Sanish 				i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
2931997Sanish 			}
2941997Sanish 
2951997Sanish 
296881Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
297881Sjohnny 			    PSM_INTR_OP_ALLOC_VECTORS, result);
298881Sjohnny 
299881Sjohnny 			/* verify behavior flag and take appropriate action */
300881Sjohnny 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
301881Sjohnny 			    (*(int *)result < hdlp->ih_scratch1)) {
302881Sjohnny 				DDI_INTR_NEXDBG((CE_CONT,
303881Sjohnny 				    "pci_common_intr_ops: behavior %x, "
304881Sjohnny 				    "couldn't get enough intrs\n", behavior));
305881Sjohnny 				hdlp->ih_scratch1 = *(int *)result;
306881Sjohnny 				(void) (*psm_intr_ops)(rdip, hdlp,
307881Sjohnny 				    PSM_INTR_OP_FREE_VECTORS, NULL);
308881Sjohnny 				return (DDI_EAGAIN);
309881Sjohnny 			}
310881Sjohnny 
311881Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
312881Sjohnny 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
313881Sjohnny 					msix_p = pci_msix_init(hdlp->ih_dip);
314881Sjohnny 					if (msix_p)
315881Sjohnny 						i_ddi_set_msix(hdlp->ih_dip,
316881Sjohnny 						    msix_p);
317881Sjohnny 				}
318881Sjohnny 			}
319881Sjohnny 
320881Sjohnny 			if (pciepci) {
321881Sjohnny 				/* update priority in ispec */
322881Sjohnny 				isp = pci_intx_get_ispec(pdip, rdip,
323881Sjohnny 					(int)hdlp->ih_inum);
324881Sjohnny 				ispec = (struct intrspec *)isp;
325881Sjohnny 				if (ispec)
326881Sjohnny 					ispec->intrspec_pri = hdlp->ih_pri;
327881Sjohnny 				++pcie_pci_intr_pri_counter;
328881Sjohnny 			}
329881Sjohnny 
330881Sjohnny 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
331881Sjohnny 			/* Figure out if this device supports MASKING */
332881Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
333881Sjohnny 			if (pci_rval == DDI_SUCCESS && pci_status)
334881Sjohnny 				hdlp->ih_cap |= pci_status;
335881Sjohnny 			*(int *)result = 1;	/* DDI_INTR_TYPE_FIXED */
336881Sjohnny 		} else
337881Sjohnny 			return (DDI_FAILURE);
338881Sjohnny 		break;
339881Sjohnny 	case DDI_INTROP_FREE:
340881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
341881Sjohnny 		    (psm_intr_ops != NULL)) {
3422018Sanish 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
3432018Sanish 			    0) {
3441997Sanish 				if (handle = i_ddi_get_pci_config_handle(
3451997Sanish 				    rdip)) {
3461997Sanish 					(void) pci_config_teardown(&handle);
3471997Sanish 					i_ddi_set_pci_config_handle(rdip, NULL);
3481997Sanish 				}
3491997Sanish 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
3501997Sanish 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
3511997Sanish 			}
3521997Sanish 
353881Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
354881Sjohnny 			    PSM_INTR_OP_FREE_VECTORS, NULL);
355881Sjohnny 
356881Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
357881Sjohnny 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
358881Sjohnny 				if (msix_p &&
3592018Sanish 				    (i_ddi_intr_get_current_nintrs(
3602018Sanish 					hdlp->ih_dip) - 1) == 0) {
361881Sjohnny 					pci_msix_fini(msix_p);
362881Sjohnny 					i_ddi_set_msix(hdlp->ih_dip, NULL);
363881Sjohnny 				}
364881Sjohnny 			}
365881Sjohnny 		}
366881Sjohnny 		break;
367881Sjohnny 	case DDI_INTROP_GETPRI:
368881Sjohnny 		/* Get the priority */
369881Sjohnny 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
370881Sjohnny 			return (DDI_FAILURE);
371881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
372881Sjohnny 		    "priority = 0x%x\n", priority));
373881Sjohnny 		*(int *)result = priority;
374881Sjohnny 		break;
375881Sjohnny 	case DDI_INTROP_SETPRI:
376881Sjohnny 		/* Validate the interrupt priority passed */
377881Sjohnny 		if (*(int *)result > LOCK_LEVEL)
378881Sjohnny 			return (DDI_FAILURE);
379881Sjohnny 
380881Sjohnny 		/* Ensure that PSM is all initialized */
381881Sjohnny 		if (psm_intr_ops == NULL)
382881Sjohnny 			return (DDI_FAILURE);
383881Sjohnny 
384881Sjohnny 		/* Change the priority */
385881Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
386881Sjohnny 		    PSM_FAILURE)
387881Sjohnny 			return (DDI_FAILURE);
388881Sjohnny 
389881Sjohnny 		/* update ispec */
390881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
391881Sjohnny 		ispec = (struct intrspec *)isp;
392881Sjohnny 		if (ispec)
393881Sjohnny 			ispec->intrspec_pri = *(int *)result;
394881Sjohnny 		break;
395881Sjohnny 	case DDI_INTROP_ADDISR:
396881Sjohnny 		/* update ispec */
397881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
398881Sjohnny 		ispec = (struct intrspec *)isp;
3991087Sschwartz 		if (ispec) {
400881Sjohnny 			ispec->intrspec_func = hdlp->ih_cb_func;
4011087Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
4021087Sschwartz 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
4031087Sschwartz 		}
404881Sjohnny 		break;
405881Sjohnny 	case DDI_INTROP_REMISR:
406881Sjohnny 		/* Get the interrupt structure pointer */
407881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
408881Sjohnny 		ispec = (struct intrspec *)isp;
4091087Sschwartz 		if (ispec) {
410881Sjohnny 			ispec->intrspec_func = (uint_t (*)()) 0;
4111087Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
4121087Sschwartz 			if (ihdl_plat_datap->ip_ksp != NULL)
4131087Sschwartz 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
4141087Sschwartz 		}
415881Sjohnny 		break;
416881Sjohnny 	case DDI_INTROP_GETCAP:
417881Sjohnny 		/*
418881Sjohnny 		 * First check the config space and/or
419881Sjohnny 		 * MSI capability register(s)
420881Sjohnny 		 */
421881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
422881Sjohnny 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
423881Sjohnny 			    &pci_status);
424881Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
425881Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
426881Sjohnny 
427881Sjohnny 		/* next check with pcplusmp */
428881Sjohnny 		if (psm_intr_ops != NULL)
429881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
430881Sjohnny 			    PSM_INTR_OP_GET_CAP, &psm_status);
431881Sjohnny 
432881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
433881Sjohnny 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
434881Sjohnny 		    psm_rval, psm_status, pci_rval, pci_status));
435881Sjohnny 
436881Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
437881Sjohnny 			*(int *)result = 0;
438881Sjohnny 			return (DDI_FAILURE);
439881Sjohnny 		}
440881Sjohnny 
441881Sjohnny 		if (psm_rval == PSM_SUCCESS)
442881Sjohnny 			*(int *)result = psm_status;
443881Sjohnny 
444881Sjohnny 		if (pci_rval == DDI_SUCCESS)
445881Sjohnny 			*(int *)result |= pci_status;
446881Sjohnny 
447881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
448881Sjohnny 		    *(int *)result));
449881Sjohnny 		break;
450881Sjohnny 	case DDI_INTROP_SETCAP:
451881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
452881Sjohnny 		    "SETCAP cap=0x%x\n", *(int *)result));
453881Sjohnny 		if (psm_intr_ops == NULL)
454881Sjohnny 			return (DDI_FAILURE);
455881Sjohnny 
456881Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
457881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
458881Sjohnny 			    " returned failure\n"));
459881Sjohnny 			return (DDI_FAILURE);
460881Sjohnny 		}
461881Sjohnny 		break;
462881Sjohnny 	case DDI_INTROP_ENABLE:
463881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
464881Sjohnny 		if (psm_intr_ops == NULL)
465881Sjohnny 			return (DDI_FAILURE);
466881Sjohnny 
467881Sjohnny 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
468881Sjohnny 		    DDI_SUCCESS)
469881Sjohnny 			return (DDI_FAILURE);
470881Sjohnny 
471881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
472881Sjohnny 		    "vector=0x%x\n", hdlp->ih_vector));
473881Sjohnny 		break;
474881Sjohnny 	case DDI_INTROP_DISABLE:
475881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
476881Sjohnny 		if (psm_intr_ops == NULL)
477881Sjohnny 			return (DDI_FAILURE);
478881Sjohnny 
479881Sjohnny 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
480881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
481881Sjohnny 		    "vector = %x\n", hdlp->ih_vector));
482881Sjohnny 		break;
483881Sjohnny 	case DDI_INTROP_BLOCKENABLE:
484881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
485881Sjohnny 		    "BLOCKENABLE\n"));
486881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
487881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
488881Sjohnny 			return (DDI_FAILURE);
489881Sjohnny 		}
490881Sjohnny 
491881Sjohnny 		/* Check if psm_intr_ops is NULL? */
492881Sjohnny 		if (psm_intr_ops == NULL)
493881Sjohnny 			return (DDI_FAILURE);
494881Sjohnny 
4951542Sjohnny 		count = hdlp->ih_scratch1;
4961542Sjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
4971542Sjohnny 		for (i = 0; i < count; i++) {
4981542Sjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
499881Sjohnny 			if (pci_enable_intr(pdip, rdip, hdlp,
5001542Sjohnny 			    hdlp->ih_inum) != DDI_SUCCESS) {
501881Sjohnny 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
502881Sjohnny 				    "pci_enable_intr failed for %d\n", i));
5031542Sjohnny 				for (j = 0; j < i; j++) {
5041542Sjohnny 				    hdlp = (ddi_intr_handle_impl_t *)h_array[j];
5051542Sjohnny 				    pci_disable_intr(pdip, rdip, hdlp,
5061542Sjohnny 					    hdlp->ih_inum);
5071542Sjohnny 				}
508881Sjohnny 				return (DDI_FAILURE);
509881Sjohnny 			}
510881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
5111542Sjohnny 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
512881Sjohnny 		}
513881Sjohnny 		break;
514881Sjohnny 	case DDI_INTROP_BLOCKDISABLE:
515881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
516881Sjohnny 		    "BLOCKDISABLE\n"));
517881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
518881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
519881Sjohnny 			return (DDI_FAILURE);
520881Sjohnny 		}
521881Sjohnny 
522881Sjohnny 		/* Check if psm_intr_ops is present */
523881Sjohnny 		if (psm_intr_ops == NULL)
524881Sjohnny 			return (DDI_FAILURE);
525881Sjohnny 
5261542Sjohnny 		count = hdlp->ih_scratch1;
5271542Sjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
5281542Sjohnny 		for (i = 0; i < count; i++) {
5291542Sjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
5301542Sjohnny 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
531881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
5321542Sjohnny 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
533881Sjohnny 		}
534881Sjohnny 		break;
535881Sjohnny 	case DDI_INTROP_SETMASK:
536881Sjohnny 	case DDI_INTROP_CLRMASK:
537881Sjohnny 		/*
538881Sjohnny 		 * First handle in the config space
539881Sjohnny 		 */
540881Sjohnny 		if (intr_op == DDI_INTROP_SETMASK) {
541881Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
542881Sjohnny 				pci_status = pci_msi_set_mask(rdip,
543881Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
544881Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
545881Sjohnny 				pci_status = pci_intx_set_mask(rdip);
546881Sjohnny 		} else {
547881Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
548881Sjohnny 				pci_status = pci_msi_clr_mask(rdip,
549881Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
550881Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
551881Sjohnny 				pci_status = pci_intx_clr_mask(rdip);
552881Sjohnny 		}
553881Sjohnny 
554881Sjohnny 		/* For MSI/X; no need to check with pcplusmp */
555881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
556881Sjohnny 			return (pci_status);
557881Sjohnny 
558881Sjohnny 		/* For fixed interrupts only: handle config space first */
559881Sjohnny 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
560881Sjohnny 		    pci_status == DDI_SUCCESS)
561881Sjohnny 			break;
562881Sjohnny 
563881Sjohnny 		/* For fixed interrupts only: confer with pcplusmp next */
564881Sjohnny 		if (psm_intr_ops != NULL) {
565881Sjohnny 			/* If interrupt is shared; do nothing */
566881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
567881Sjohnny 			    PSM_INTR_OP_GET_SHARED, &psm_status);
568881Sjohnny 
569881Sjohnny 			if (psm_rval == PSM_FAILURE || psm_status == 1)
570881Sjohnny 				return (pci_status);
571881Sjohnny 
572881Sjohnny 			/* Now, pcplusmp should try to set/clear the mask */
573881Sjohnny 			if (intr_op == DDI_INTROP_SETMASK)
574881Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
575881Sjohnny 				    PSM_INTR_OP_SET_MASK, NULL);
576881Sjohnny 			else
577881Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
578881Sjohnny 				    PSM_INTR_OP_CLEAR_MASK, NULL);
579881Sjohnny 		}
580881Sjohnny 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
581881Sjohnny 	case DDI_INTROP_GETPENDING:
582881Sjohnny 		/*
583881Sjohnny 		 * First check the config space and/or
584881Sjohnny 		 * MSI capability register(s)
585881Sjohnny 		 */
586881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
587881Sjohnny 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
588881Sjohnny 			    hdlp->ih_inum, &pci_status);
589881Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
590881Sjohnny 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
591881Sjohnny 
592881Sjohnny 		/* On failure; next try with pcplusmp */
593881Sjohnny 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
594881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
595881Sjohnny 			    PSM_INTR_OP_GET_PENDING, &psm_status);
596881Sjohnny 
597881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
598881Sjohnny 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
599881Sjohnny 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
600881Sjohnny 		    pci_status));
601881Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
602881Sjohnny 			*(int *)result = 0;
603881Sjohnny 			return (DDI_FAILURE);
604881Sjohnny 		}
605881Sjohnny 
606881Sjohnny 		if (psm_rval != PSM_FAILURE)
607881Sjohnny 			*(int *)result = psm_status;
608881Sjohnny 		else if (pci_rval != DDI_FAILURE)
609881Sjohnny 			*(int *)result = pci_status;
610881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
611881Sjohnny 		    *(int *)result));
612881Sjohnny 		break;
613881Sjohnny 	default:
614881Sjohnny 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
615881Sjohnny 	}
616881Sjohnny 
617881Sjohnny 	return (DDI_SUCCESS);
618881Sjohnny }
619881Sjohnny 
620916Sschwartz int
621916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
622916Sschwartz     int vecirq, boolean_t is_irq)
623916Sschwartz {
624916Sschwartz 	ddi_intr_handle_impl_t	get_info_ii_hdl;
625916Sschwartz 
626916Sschwartz 	if (is_irq)
627916Sschwartz 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
628916Sschwartz 
629916Sschwartz 	/*
630916Sschwartz 	 * For this locally-declared and used handle, ih_private will contain a
631916Sschwartz 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
632916Sschwartz 	 * global interrupt handling.
633916Sschwartz 	 */
634916Sschwartz 	get_info_ii_hdl.ih_private = intrinfo_p;
635916Sschwartz 	get_info_ii_hdl.ih_vector = (ushort_t)vecirq;
636916Sschwartz 
637916Sschwartz 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
638916Sschwartz 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
639916Sschwartz 		return (DDI_FAILURE);
640916Sschwartz 
641916Sschwartz 	return (DDI_SUCCESS);
642916Sschwartz }
643916Sschwartz 
644916Sschwartz 
645916Sschwartz int
646916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
647916Sschwartz {
648916Sschwartz 	int rval;
649916Sschwartz 
650916Sschwartz 	apic_get_intr_t	intrinfo;
651916Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
652916Sschwartz 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
653916Sschwartz 
654916Sschwartz 	if (rval == DDI_SUCCESS)
655916Sschwartz 		return (intrinfo.avgi_cpu_id);
656916Sschwartz 	else
657916Sschwartz 		return (-1);
658916Sschwartz }
659916Sschwartz 
660881Sjohnny 
661881Sjohnny static int
662881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
663881Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
664881Sjohnny {
665881Sjohnny 	struct intrspec	*ispec;
666916Sschwartz 	int		irq;
667916Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
668881Sjohnny 
669881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
670881Sjohnny 	    (void *)hdlp, inum));
671881Sjohnny 
672881Sjohnny 	/* Translate the interrupt if needed */
673881Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
6742288Sanish 	if (ispec == NULL)
6752288Sanish 		return (DDI_FAILURE);
6762288Sanish 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
677881Sjohnny 		ispec->intrspec_vec = inum;
678916Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
679881Sjohnny 
680881Sjohnny 	/* translate the interrupt if needed */
681916Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
682916Sschwartz 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
683916Sschwartz 	    hdlp->ih_pri, irq));
684881Sjohnny 
685881Sjohnny 	/* Add the interrupt handler */
686881Sjohnny 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
687916Sschwartz 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
688916Sschwartz 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
689881Sjohnny 		return (DDI_FAILURE);
690881Sjohnny 
691916Sschwartz 	/* Note this really is an irq. */
692916Sschwartz 	hdlp->ih_vector = (ushort_t)irq;
693916Sschwartz 
694881Sjohnny 	return (DDI_SUCCESS);
695881Sjohnny }
696881Sjohnny 
697881Sjohnny 
698881Sjohnny static void
699881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
700881Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
701881Sjohnny {
702916Sschwartz 	int		irq;
703881Sjohnny 	struct intrspec	*ispec;
704916Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
705881Sjohnny 
706881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
707881Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
7082288Sanish 	if (ispec == NULL)
7092288Sanish 		return;
7102288Sanish 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
711881Sjohnny 		ispec->intrspec_vec = inum;
712916Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
713881Sjohnny 
714881Sjohnny 	/* translate the interrupt if needed */
715916Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
716881Sjohnny 
717881Sjohnny 	/* Disable the interrupt handler */
718916Sschwartz 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
719916Sschwartz 	ihdl_plat_datap->ip_ispecp = NULL;
720881Sjohnny }
721881Sjohnny 
722881Sjohnny /*
723881Sjohnny  * Miscellaneous library function
724881Sjohnny  */
725881Sjohnny int
726881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
727881Sjohnny {
728881Sjohnny 	int		i;
729881Sjohnny 	int 		number;
730881Sjohnny 	int		assigned_addr_len;
731881Sjohnny 	uint_t		phys_hi = pci_rp->pci_phys_hi;
732881Sjohnny 	pci_regspec_t	*assigned_addr;
733881Sjohnny 
734881Sjohnny 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
735881Sjohnny 	    (phys_hi & PCI_RELOCAT_B))
736881Sjohnny 		return (DDI_SUCCESS);
737881Sjohnny 
738881Sjohnny 	/*
739881Sjohnny 	 * the "reg" property specifies relocatable, get and interpret the
740881Sjohnny 	 * "assigned-addresses" property.
741881Sjohnny 	 */
742881Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
743881Sjohnny 	    "assigned-addresses", (int **)&assigned_addr,
744881Sjohnny 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
745881Sjohnny 		return (DDI_FAILURE);
746881Sjohnny 
747881Sjohnny 	/*
748881Sjohnny 	 * Scan the "assigned-addresses" for one that matches the specified
749881Sjohnny 	 * "reg" property entry.
750881Sjohnny 	 */
751881Sjohnny 	phys_hi &= PCI_CONF_ADDR_MASK;
752881Sjohnny 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
753881Sjohnny 	for (i = 0; i < number; i++) {
754881Sjohnny 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
755881Sjohnny 		    phys_hi) {
756881Sjohnny 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
757881Sjohnny 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
758881Sjohnny 			ddi_prop_free(assigned_addr);
759881Sjohnny 			return (DDI_SUCCESS);
760881Sjohnny 		}
761881Sjohnny 	}
762881Sjohnny 
763881Sjohnny 	ddi_prop_free(assigned_addr);
764881Sjohnny 	return (DDI_FAILURE);
765881Sjohnny }
766881Sjohnny 
767881Sjohnny 
768881Sjohnny /*
769881Sjohnny  * For pci_tools
770881Sjohnny  */
771881Sjohnny 
772881Sjohnny int
773881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
774881Sjohnny     int mode, cred_t *credp, int *rvalp)
775881Sjohnny {
776881Sjohnny 	int rv = ENOTTY;
777881Sjohnny 
778881Sjohnny 	minor_t minor = getminor(dev);
779881Sjohnny 
780881Sjohnny 	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
781881Sjohnny 	case PCI_TOOL_REG_MINOR_NUM:
782881Sjohnny 
783881Sjohnny 		switch (cmd) {
784881Sjohnny 		case PCITOOL_DEVICE_SET_REG:
785881Sjohnny 		case PCITOOL_DEVICE_GET_REG:
786881Sjohnny 
787881Sjohnny 			/* Require full privileges. */
788881Sjohnny 			if (secpolicy_kmdb(credp))
789881Sjohnny 				rv = EPERM;
790881Sjohnny 			else
791881Sjohnny 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
792881Sjohnny 				    cmd, mode);
793881Sjohnny 			break;
794881Sjohnny 
795881Sjohnny 		case PCITOOL_NEXUS_SET_REG:
796881Sjohnny 		case PCITOOL_NEXUS_GET_REG:
797881Sjohnny 
798881Sjohnny 			/* Require full privileges. */
799881Sjohnny 			if (secpolicy_kmdb(credp))
800881Sjohnny 				rv = EPERM;
801881Sjohnny 			else
802881Sjohnny 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
803881Sjohnny 				    cmd, mode);
804881Sjohnny 			break;
805881Sjohnny 		}
806881Sjohnny 		break;
807881Sjohnny 
808881Sjohnny 	case PCI_TOOL_INTR_MINOR_NUM:
809881Sjohnny 
810881Sjohnny 		switch (cmd) {
811881Sjohnny 		case PCITOOL_DEVICE_SET_INTR:
812881Sjohnny 
813881Sjohnny 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
814881Sjohnny 			if (secpolicy_ponline(credp)) {
815881Sjohnny 				rv = EPERM;
816881Sjohnny 				break;
817881Sjohnny 			}
818881Sjohnny 
819881Sjohnny 		/*FALLTHRU*/
820881Sjohnny 		/* These require no special privileges. */
821881Sjohnny 		case PCITOOL_DEVICE_GET_INTR:
822881Sjohnny 		case PCITOOL_DEVICE_NUM_INTR:
823881Sjohnny 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
824881Sjohnny 			break;
825881Sjohnny 		}
826881Sjohnny 		break;
827881Sjohnny 
828881Sjohnny 	/*
829881Sjohnny 	 * All non-PCItool ioctls go through here, including:
830881Sjohnny 	 *   devctl ioctls with minor number PCIHP_DEVCTL_MINOR and
831881Sjohnny 	 *   those for attachment points with where minor number is the
832881Sjohnny 	 *   device number.
833881Sjohnny 	 */
834881Sjohnny 	default:
835881Sjohnny 		rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
836881Sjohnny 		    credp, rvalp);
837881Sjohnny 		break;
838881Sjohnny 	}
839881Sjohnny 
840881Sjohnny 	return (rv);
841881Sjohnny }
8421083Sanish 
8431083Sanish 
8441865Sdilpreet int
8451865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
8461865Sdilpreet {
8471865Sdilpreet 	size_t size = in_args->size;
8481865Sdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
8491865Sdilpreet 	uintptr_t host_addr = in_args->host_addr;
8501865Sdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
8511865Sdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
8521865Sdilpreet 	size_t repcount = in_args->repcount;
8531865Sdilpreet 	uint_t flags = in_args->flags;
8541865Sdilpreet 	int err = DDI_SUCCESS;
8551865Sdilpreet 
8561865Sdilpreet 	/*
8571865Sdilpreet 	 * if no handle then this is a poke. We have to return failure here
8581865Sdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
8591865Sdilpreet 	 */
8601865Sdilpreet 	if (in_args->handle == NULL)
8611865Sdilpreet 		return (DDI_FAILURE);
8621865Sdilpreet 
8631865Sdilpreet 	/*
8641865Sdilpreet 	 * rest of this function is actually for cautious puts
8651865Sdilpreet 	 */
8661865Sdilpreet 	for (; repcount; repcount--) {
8671865Sdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
8681865Sdilpreet 			switch (size) {
8691865Sdilpreet 			case sizeof (uint8_t):
8701865Sdilpreet 				pci_config_wr8(hp, (uint8_t *)dev_addr,
8711865Sdilpreet 				    *(uint8_t *)host_addr);
8721865Sdilpreet 				break;
8731865Sdilpreet 			case sizeof (uint16_t):
8741865Sdilpreet 				pci_config_wr16(hp, (uint16_t *)dev_addr,
8751865Sdilpreet 				    *(uint16_t *)host_addr);
8761865Sdilpreet 				break;
8771865Sdilpreet 			case sizeof (uint32_t):
8781865Sdilpreet 				pci_config_wr32(hp, (uint32_t *)dev_addr,
8791865Sdilpreet 				    *(uint32_t *)host_addr);
8801865Sdilpreet 				break;
8811865Sdilpreet 			case sizeof (uint64_t):
8821865Sdilpreet 				pci_config_wr64(hp, (uint64_t *)dev_addr,
8831865Sdilpreet 				    *(uint64_t *)host_addr);
8841865Sdilpreet 				break;
8851865Sdilpreet 			default:
8861865Sdilpreet 				err = DDI_FAILURE;
8871865Sdilpreet 				break;
8881865Sdilpreet 			}
8891865Sdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
8901865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
8911865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
8921865Sdilpreet 				switch (size) {
8931865Sdilpreet 				case sizeof (uint8_t):
8941865Sdilpreet 					i_ddi_io_put8(hp,
8951865Sdilpreet 					    (uint8_t *)dev_addr,
8961865Sdilpreet 					    *(uint8_t *)host_addr);
8971865Sdilpreet 					break;
8981865Sdilpreet 				case sizeof (uint16_t):
8991865Sdilpreet 					i_ddi_io_swap_put16(hp,
9001865Sdilpreet 					    (uint16_t *)dev_addr,
9011865Sdilpreet 					    *(uint16_t *)host_addr);
9021865Sdilpreet 					break;
9031865Sdilpreet 				case sizeof (uint32_t):
9041865Sdilpreet 					i_ddi_io_swap_put32(hp,
9051865Sdilpreet 					    (uint32_t *)dev_addr,
9061865Sdilpreet 					    *(uint32_t *)host_addr);
9071865Sdilpreet 					break;
9081865Sdilpreet 				/*
9091865Sdilpreet 				 * note the 64-bit case is a dummy
9101865Sdilpreet 				 * function - so no need to swap
9111865Sdilpreet 				 */
9121865Sdilpreet 				case sizeof (uint64_t):
9131865Sdilpreet 					i_ddi_io_put64(hp,
9141865Sdilpreet 					    (uint64_t *)dev_addr,
9151865Sdilpreet 					    *(uint64_t *)host_addr);
9161865Sdilpreet 					break;
9171865Sdilpreet 				default:
9181865Sdilpreet 					err = DDI_FAILURE;
9191865Sdilpreet 					break;
9201865Sdilpreet 				}
9211865Sdilpreet 			} else {
9221865Sdilpreet 				switch (size) {
9231865Sdilpreet 				case sizeof (uint8_t):
9241865Sdilpreet 					i_ddi_io_put8(hp,
9251865Sdilpreet 					    (uint8_t *)dev_addr,
9261865Sdilpreet 					    *(uint8_t *)host_addr);
9271865Sdilpreet 					break;
9281865Sdilpreet 				case sizeof (uint16_t):
9291865Sdilpreet 					i_ddi_io_put16(hp,
9301865Sdilpreet 					    (uint16_t *)dev_addr,
9311865Sdilpreet 					    *(uint16_t *)host_addr);
9321865Sdilpreet 					break;
9331865Sdilpreet 				case sizeof (uint32_t):
9341865Sdilpreet 					i_ddi_io_put32(hp,
9351865Sdilpreet 					    (uint32_t *)dev_addr,
9361865Sdilpreet 					    *(uint32_t *)host_addr);
9371865Sdilpreet 					break;
9381865Sdilpreet 				case sizeof (uint64_t):
9391865Sdilpreet 					i_ddi_io_put64(hp,
9401865Sdilpreet 					    (uint64_t *)dev_addr,
9411865Sdilpreet 					    *(uint64_t *)host_addr);
9421865Sdilpreet 					break;
9431865Sdilpreet 				default:
9441865Sdilpreet 					err = DDI_FAILURE;
9451865Sdilpreet 					break;
9461865Sdilpreet 				}
9471865Sdilpreet 			}
9481865Sdilpreet 		} else {
9491865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
9501865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
9511865Sdilpreet 				switch (size) {
9521865Sdilpreet 				case sizeof (uint8_t):
9531865Sdilpreet 					*(uint8_t *)dev_addr =
9541865Sdilpreet 					    *(uint8_t *)host_addr;
9551865Sdilpreet 					break;
9561865Sdilpreet 				case sizeof (uint16_t):
9571865Sdilpreet 					*(uint16_t *)dev_addr =
9581865Sdilpreet 					    ddi_swap16(*(uint16_t *)host_addr);
9591865Sdilpreet 					break;
9601865Sdilpreet 				case sizeof (uint32_t):
9611865Sdilpreet 					*(uint32_t *)dev_addr =
9621865Sdilpreet 					    ddi_swap32(*(uint32_t *)host_addr);
9631865Sdilpreet 					break;
9641865Sdilpreet 				case sizeof (uint64_t):
9651865Sdilpreet 					*(uint64_t *)dev_addr =
9661865Sdilpreet 					    ddi_swap64(*(uint64_t *)host_addr);
9671865Sdilpreet 					break;
9681865Sdilpreet 				default:
9691865Sdilpreet 					err = DDI_FAILURE;
9701865Sdilpreet 					break;
9711865Sdilpreet 				}
9721865Sdilpreet 			} else {
9731865Sdilpreet 				switch (size) {
9741865Sdilpreet 				case sizeof (uint8_t):
9751865Sdilpreet 					*(uint8_t *)dev_addr =
9761865Sdilpreet 					    *(uint8_t *)host_addr;
9771865Sdilpreet 					break;
9781865Sdilpreet 				case sizeof (uint16_t):
9791865Sdilpreet 					*(uint16_t *)dev_addr =
9801865Sdilpreet 					    *(uint16_t *)host_addr;
9811865Sdilpreet 					break;
9821865Sdilpreet 				case sizeof (uint32_t):
9831865Sdilpreet 					*(uint32_t *)dev_addr =
9841865Sdilpreet 					    *(uint32_t *)host_addr;
9851865Sdilpreet 					break;
9861865Sdilpreet 				case sizeof (uint64_t):
9871865Sdilpreet 					*(uint64_t *)dev_addr =
9881865Sdilpreet 					    *(uint64_t *)host_addr;
9891865Sdilpreet 					break;
9901865Sdilpreet 				default:
9911865Sdilpreet 					err = DDI_FAILURE;
9921865Sdilpreet 					break;
9931865Sdilpreet 				}
9941865Sdilpreet 			}
9951865Sdilpreet 		}
9961865Sdilpreet 		host_addr += size;
9971865Sdilpreet 		if (flags == DDI_DEV_AUTOINCR)
9981865Sdilpreet 			dev_addr += size;
9991865Sdilpreet 	}
10001865Sdilpreet 	return (err);
10011865Sdilpreet }
10021865Sdilpreet 
10031865Sdilpreet 
10041865Sdilpreet int
10051865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
10061865Sdilpreet {
10071865Sdilpreet 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
10081865Sdilpreet 
10091865Sdilpreet 	/* endian-ness check */
10101865Sdilpreet 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
10111865Sdilpreet 		return (DDI_FAILURE);
10121865Sdilpreet 
10131865Sdilpreet 	/*
10141865Sdilpreet 	 * range check
10151865Sdilpreet 	 */
10161865Sdilpreet 	if ((offset >= PCI_CONF_HDR_SIZE) ||
10171865Sdilpreet 	    (len > PCI_CONF_HDR_SIZE) ||
10181865Sdilpreet 	    (offset + len > PCI_CONF_HDR_SIZE))
10191865Sdilpreet 		return (DDI_FAILURE);
10201865Sdilpreet 
10211865Sdilpreet 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
10221865Sdilpreet 	/*
10231865Sdilpreet 	 * always use cautious mechanism for config space gets
10241865Sdilpreet 	 */
10251865Sdilpreet 	ap->ahi_get8 = i_ddi_caut_get8;
10261865Sdilpreet 	ap->ahi_get16 = i_ddi_caut_get16;
10271865Sdilpreet 	ap->ahi_get32 = i_ddi_caut_get32;
10281865Sdilpreet 	ap->ahi_get64 = i_ddi_caut_get64;
10291865Sdilpreet 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
10301865Sdilpreet 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
10311865Sdilpreet 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
10321865Sdilpreet 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
10331865Sdilpreet 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
10341865Sdilpreet 		ap->ahi_put8 = i_ddi_caut_put8;
10351865Sdilpreet 		ap->ahi_put16 = i_ddi_caut_put16;
10361865Sdilpreet 		ap->ahi_put32 = i_ddi_caut_put32;
10371865Sdilpreet 		ap->ahi_put64 = i_ddi_caut_put64;
10381865Sdilpreet 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
10391865Sdilpreet 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
10401865Sdilpreet 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
10411865Sdilpreet 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
10421865Sdilpreet 	} else {
10431865Sdilpreet 		ap->ahi_put8 = pci_config_wr8;
10441865Sdilpreet 		ap->ahi_put16 = pci_config_wr16;
10451865Sdilpreet 		ap->ahi_put32 = pci_config_wr32;
10461865Sdilpreet 		ap->ahi_put64 = pci_config_wr64;
10471865Sdilpreet 		ap->ahi_rep_put8 = pci_config_rep_wr8;
10481865Sdilpreet 		ap->ahi_rep_put16 = pci_config_rep_wr16;
10491865Sdilpreet 		ap->ahi_rep_put32 = pci_config_rep_wr32;
10501865Sdilpreet 		ap->ahi_rep_put64 = pci_config_rep_wr64;
10511865Sdilpreet 	}
10521865Sdilpreet 
10531865Sdilpreet 	/* Initialize to default check/notify functions */
10541865Sdilpreet 	ap->ahi_fault_check = i_ddi_acc_fault_check;
10551865Sdilpreet 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
10561865Sdilpreet 	ap->ahi_fault = 0;
10571865Sdilpreet 	impl_acc_err_init(hp);
10581865Sdilpreet 	return (DDI_SUCCESS);
10591865Sdilpreet }
10601865Sdilpreet 
10611865Sdilpreet 
10621865Sdilpreet int
10631865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
10641865Sdilpreet {
10651865Sdilpreet 	size_t size = in_args->size;
10661865Sdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
10671865Sdilpreet 	uintptr_t host_addr = in_args->host_addr;
10681865Sdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
10691865Sdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
10701865Sdilpreet 	size_t repcount = in_args->repcount;
10711865Sdilpreet 	uint_t flags = in_args->flags;
10721865Sdilpreet 	int err = DDI_SUCCESS;
10731865Sdilpreet 
10741865Sdilpreet 	/*
10751865Sdilpreet 	 * if no handle then this is a peek. We have to return failure here
10761865Sdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
10771865Sdilpreet 	 */
10781865Sdilpreet 	if (in_args->handle == NULL)
10791865Sdilpreet 		return (DDI_FAILURE);
10801865Sdilpreet 
10811865Sdilpreet 	for (; repcount; repcount--) {
10821865Sdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
10831865Sdilpreet 			switch (size) {
10841865Sdilpreet 			case sizeof (uint8_t):
10851865Sdilpreet 				*(uint8_t *)host_addr = pci_config_rd8(hp,
10861865Sdilpreet 				    (uint8_t *)dev_addr);
10871865Sdilpreet 				break;
10881865Sdilpreet 			case sizeof (uint16_t):
10891865Sdilpreet 				*(uint16_t *)host_addr = pci_config_rd16(hp,
10901865Sdilpreet 				    (uint16_t *)dev_addr);
10911865Sdilpreet 				break;
10921865Sdilpreet 			case sizeof (uint32_t):
10931865Sdilpreet 				*(uint32_t *)host_addr = pci_config_rd32(hp,
10941865Sdilpreet 				    (uint32_t *)dev_addr);
10951865Sdilpreet 				break;
10961865Sdilpreet 			case sizeof (uint64_t):
10971865Sdilpreet 				*(uint64_t *)host_addr = pci_config_rd64(hp,
10981865Sdilpreet 				    (uint64_t *)dev_addr);
10991865Sdilpreet 				break;
11001865Sdilpreet 			default:
11011865Sdilpreet 				err = DDI_FAILURE;
11021865Sdilpreet 				break;
11031865Sdilpreet 			}
11041865Sdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
11051865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
11061865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
11071865Sdilpreet 				switch (size) {
11081865Sdilpreet 				case sizeof (uint8_t):
11091865Sdilpreet 					*(uint8_t *)host_addr =
11101865Sdilpreet 					    i_ddi_io_get8(hp,
11111865Sdilpreet 					    (uint8_t *)dev_addr);
11121865Sdilpreet 					break;
11131865Sdilpreet 				case sizeof (uint16_t):
11141865Sdilpreet 					*(uint16_t *)host_addr =
11151865Sdilpreet 					    i_ddi_io_swap_get16(hp,
11161865Sdilpreet 					    (uint16_t *)dev_addr);
11171865Sdilpreet 					break;
11181865Sdilpreet 				case sizeof (uint32_t):
11191865Sdilpreet 					*(uint32_t *)host_addr =
11201865Sdilpreet 					    i_ddi_io_swap_get32(hp,
11211865Sdilpreet 					    (uint32_t *)dev_addr);
11221865Sdilpreet 					break;
11231865Sdilpreet 				/*
11241865Sdilpreet 				 * note the 64-bit case is a dummy
11251865Sdilpreet 				 * function - so no need to swap
11261865Sdilpreet 				 */
11271865Sdilpreet 				case sizeof (uint64_t):
11281865Sdilpreet 					*(uint64_t *)host_addr =
11291865Sdilpreet 					    i_ddi_io_get64(hp,
11301865Sdilpreet 					    (uint64_t *)dev_addr);
11311865Sdilpreet 					break;
11321865Sdilpreet 				default:
11331865Sdilpreet 					err = DDI_FAILURE;
11341865Sdilpreet 					break;
11351865Sdilpreet 				}
11361865Sdilpreet 			} else {
11371865Sdilpreet 				switch (size) {
11381865Sdilpreet 				case sizeof (uint8_t):
11391865Sdilpreet 					*(uint8_t *)host_addr =
11401865Sdilpreet 					    i_ddi_io_get8(hp,
11411865Sdilpreet 					    (uint8_t *)dev_addr);
11421865Sdilpreet 					break;
11431865Sdilpreet 				case sizeof (uint16_t):
11441865Sdilpreet 					*(uint16_t *)host_addr =
11451865Sdilpreet 					    i_ddi_io_get16(hp,
11461865Sdilpreet 					    (uint16_t *)dev_addr);
11471865Sdilpreet 					break;
11481865Sdilpreet 				case sizeof (uint32_t):
11491865Sdilpreet 					*(uint32_t *)host_addr =
11501865Sdilpreet 					    i_ddi_io_get32(hp,
11511865Sdilpreet 					    (uint32_t *)dev_addr);
11521865Sdilpreet 					break;
11531865Sdilpreet 				case sizeof (uint64_t):
11541865Sdilpreet 					*(uint64_t *)host_addr =
11551865Sdilpreet 					    i_ddi_io_get64(hp,
11561865Sdilpreet 					    (uint64_t *)dev_addr);
11571865Sdilpreet 					break;
11581865Sdilpreet 				default:
11591865Sdilpreet 					err = DDI_FAILURE;
11601865Sdilpreet 					break;
11611865Sdilpreet 				}
11621865Sdilpreet 			}
11631865Sdilpreet 		} else {
11641865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
11651865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
11661865Sdilpreet 				switch (in_args->size) {
11671865Sdilpreet 				case sizeof (uint8_t):
11681865Sdilpreet 					*(uint8_t *)host_addr =
11691865Sdilpreet 					    *(uint8_t *)dev_addr;
11701865Sdilpreet 					break;
11711865Sdilpreet 				case sizeof (uint16_t):
11721865Sdilpreet 					*(uint16_t *)host_addr =
11731865Sdilpreet 					    ddi_swap16(*(uint16_t *)dev_addr);
11741865Sdilpreet 					break;
11751865Sdilpreet 				case sizeof (uint32_t):
11761865Sdilpreet 					*(uint32_t *)host_addr =
11771865Sdilpreet 					    ddi_swap32(*(uint32_t *)dev_addr);
11781865Sdilpreet 					break;
11791865Sdilpreet 				case sizeof (uint64_t):
11801865Sdilpreet 					*(uint64_t *)host_addr =
11811865Sdilpreet 					    ddi_swap64(*(uint64_t *)dev_addr);
11821865Sdilpreet 					break;
11831865Sdilpreet 				default:
11841865Sdilpreet 					err = DDI_FAILURE;
11851865Sdilpreet 					break;
11861865Sdilpreet 				}
11871865Sdilpreet 			} else {
11881865Sdilpreet 				switch (in_args->size) {
11891865Sdilpreet 				case sizeof (uint8_t):
11901865Sdilpreet 					*(uint8_t *)host_addr =
11911865Sdilpreet 					    *(uint8_t *)dev_addr;
11921865Sdilpreet 					break;
11931865Sdilpreet 				case sizeof (uint16_t):
11941865Sdilpreet 					*(uint16_t *)host_addr =
11951865Sdilpreet 					    *(uint16_t *)dev_addr;
11961865Sdilpreet 					break;
11971865Sdilpreet 				case sizeof (uint32_t):
11981865Sdilpreet 					*(uint32_t *)host_addr =
11991865Sdilpreet 					    *(uint32_t *)dev_addr;
12001865Sdilpreet 					break;
12011865Sdilpreet 				case sizeof (uint64_t):
12021865Sdilpreet 					*(uint64_t *)host_addr =
12031865Sdilpreet 					    *(uint64_t *)dev_addr;
12041865Sdilpreet 					break;
12051865Sdilpreet 				default:
12061865Sdilpreet 					err = DDI_FAILURE;
12071865Sdilpreet 					break;
12081865Sdilpreet 				}
12091865Sdilpreet 			}
12101865Sdilpreet 		}
12111865Sdilpreet 		host_addr += size;
12121865Sdilpreet 		if (flags == DDI_DEV_AUTOINCR)
12131865Sdilpreet 			dev_addr += size;
12141865Sdilpreet 	}
12151865Sdilpreet 	return (err);
12161865Sdilpreet }
12171865Sdilpreet 
12181865Sdilpreet /*ARGSUSED*/
12191865Sdilpreet int
12201865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
12211865Sdilpreet 	ddi_ctl_enum_t ctlop, void *arg, void *result)
12221865Sdilpreet {
12231865Sdilpreet 	if (ctlop == DDI_CTLOPS_PEEK)
12241865Sdilpreet 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
12251865Sdilpreet 	else
12261865Sdilpreet 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
12271865Sdilpreet }
12281865Sdilpreet 
12291083Sanish /*
12301083Sanish  * These are the get and put functions to be shared with drivers. The
12311083Sanish  * mutex locking is done inside the functions referenced, rather than
12321083Sanish  * here, and is thus shared across PCI child drivers and any other
12331083Sanish  * consumers of PCI config space (such as the ACPI subsystem).
12341083Sanish  *
12351083Sanish  * The configuration space addresses come in as pointers.  This is fine on
12361083Sanish  * a 32-bit system, where the VM space and configuration space are the same
12371083Sanish  * size.  It's not such a good idea on a 64-bit system, where memory
12381083Sanish  * addresses are twice as large as configuration space addresses.  At some
12391083Sanish  * point in the call tree we need to take a stand and say "you are 32-bit
12401083Sanish  * from this time forth", and this seems like a nice self-contained place.
12411083Sanish  */
12421083Sanish 
12431083Sanish uint8_t
12441083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
12451083Sanish {
12461083Sanish 	pci_acc_cfblk_t *cfp;
12471083Sanish 	uint8_t	rval;
12481083Sanish 	int reg;
12491083Sanish 
12501083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
12511083Sanish 
12521083Sanish 	reg = (int)(uintptr_t)addr;
12531083Sanish 
12541083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
12551083Sanish 
12561083Sanish 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
12571083Sanish 	    reg);
12581083Sanish 
12591083Sanish 	return (rval);
12601083Sanish }
12611083Sanish 
12621083Sanish void
12631083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
12641083Sanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
12651083Sanish {
12661083Sanish 	uint8_t *h, *d;
12671083Sanish 
12681083Sanish 	h = host_addr;
12691083Sanish 	d = dev_addr;
12701083Sanish 
12711083Sanish 	if (flags == DDI_DEV_AUTOINCR)
12721083Sanish 		for (; repcount; repcount--)
12731083Sanish 			*h++ = pci_config_rd8(hdlp, d++);
12741083Sanish 	else
12751083Sanish 		for (; repcount; repcount--)
12761083Sanish 			*h++ = pci_config_rd8(hdlp, d);
12771083Sanish }
12781083Sanish 
12791083Sanish uint16_t
12801083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
12811083Sanish {
12821083Sanish 	pci_acc_cfblk_t *cfp;
12831083Sanish 	uint16_t rval;
12841083Sanish 	int reg;
12851083Sanish 
12861083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
12871083Sanish 
12881083Sanish 	reg = (int)(uintptr_t)addr;
12891083Sanish 
12901083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
12911083Sanish 
12921083Sanish 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
12931083Sanish 	    reg);
12941083Sanish 
12951083Sanish 	return (rval);
12961083Sanish }
12971083Sanish 
12981083Sanish void
12991083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
13001083Sanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
13011083Sanish {
13021083Sanish 	uint16_t *h, *d;
13031083Sanish 
13041083Sanish 	h = host_addr;
13051083Sanish 	d = dev_addr;
13061083Sanish 
13071083Sanish 	if (flags == DDI_DEV_AUTOINCR)
13081083Sanish 		for (; repcount; repcount--)
13091083Sanish 			*h++ = pci_config_rd16(hdlp, d++);
13101083Sanish 	else
13111083Sanish 		for (; repcount; repcount--)
13121083Sanish 			*h++ = pci_config_rd16(hdlp, d);
13131083Sanish }
13141083Sanish 
13151083Sanish uint32_t
13161083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
13171083Sanish {
13181083Sanish 	pci_acc_cfblk_t *cfp;
13191083Sanish 	uint32_t rval;
13201083Sanish 	int reg;
13211083Sanish 
13221083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
13231083Sanish 
13241083Sanish 	reg = (int)(uintptr_t)addr;
13251083Sanish 
13261083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
13271083Sanish 
13281083Sanish 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
13291083Sanish 	    cfp->c_funcnum, reg);
13301083Sanish 
13311083Sanish 	return (rval);
13321083Sanish }
13331083Sanish 
13341083Sanish void
13351083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
13361083Sanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
13371083Sanish {
13381083Sanish 	uint32_t *h, *d;
13391083Sanish 
13401083Sanish 	h = host_addr;
13411083Sanish 	d = dev_addr;
13421083Sanish 
13431083Sanish 	if (flags == DDI_DEV_AUTOINCR)
13441083Sanish 		for (; repcount; repcount--)
13451083Sanish 			*h++ = pci_config_rd32(hdlp, d++);
13461083Sanish 	else
13471083Sanish 		for (; repcount; repcount--)
13481083Sanish 			*h++ = pci_config_rd32(hdlp, d);
13491083Sanish }
13501083Sanish 
13511083Sanish 
13521083Sanish void
13531083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
13541083Sanish {
13551083Sanish 	pci_acc_cfblk_t *cfp;
13561083Sanish 	int reg;
13571083Sanish 
13581083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
13591083Sanish 
13601083Sanish 	reg = (int)(uintptr_t)addr;
13611083Sanish 
13621083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
13631083Sanish 
13641083Sanish 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
13651083Sanish 	    cfp->c_funcnum, reg, value);
13661083Sanish }
13671083Sanish 
13681083Sanish void
13691083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
13701083Sanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
13711083Sanish {
13721083Sanish 	uint8_t *h, *d;
13731083Sanish 
13741083Sanish 	h = host_addr;
13751083Sanish 	d = dev_addr;
13761083Sanish 
13771083Sanish 	if (flags == DDI_DEV_AUTOINCR)
13781083Sanish 		for (; repcount; repcount--)
13791083Sanish 			pci_config_wr8(hdlp, d++, *h++);
13801083Sanish 	else
13811083Sanish 		for (; repcount; repcount--)
13821083Sanish 			pci_config_wr8(hdlp, d, *h++);
13831083Sanish }
13841083Sanish 
13851083Sanish void
13861083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
13871083Sanish {
13881083Sanish 	pci_acc_cfblk_t *cfp;
13891083Sanish 	int reg;
13901083Sanish 
13911083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
13921083Sanish 
13931083Sanish 	reg = (int)(uintptr_t)addr;
13941083Sanish 
13951083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
13961083Sanish 
13971083Sanish 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
13981083Sanish 	    cfp->c_funcnum, reg, value);
13991083Sanish }
14001083Sanish 
14011083Sanish void
14021083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
14031083Sanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
14041083Sanish {
14051083Sanish 	uint16_t *h, *d;
14061083Sanish 
14071083Sanish 	h = host_addr;
14081083Sanish 	d = dev_addr;
14091083Sanish 
14101083Sanish 	if (flags == DDI_DEV_AUTOINCR)
14111083Sanish 		for (; repcount; repcount--)
14121083Sanish 			pci_config_wr16(hdlp, d++, *h++);
14131083Sanish 	else
14141083Sanish 		for (; repcount; repcount--)
14151083Sanish 			pci_config_wr16(hdlp, d, *h++);
14161083Sanish }
14171083Sanish 
14181083Sanish void
14191083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
14201083Sanish {
14211083Sanish 	pci_acc_cfblk_t *cfp;
14221083Sanish 	int reg;
14231083Sanish 
14241083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
14251083Sanish 
14261083Sanish 	reg = (int)(uintptr_t)addr;
14271083Sanish 
14281083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
14291083Sanish 
14301083Sanish 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
14311083Sanish 	    cfp->c_funcnum, reg, value);
14321083Sanish }
14331083Sanish 
14341083Sanish void
14351083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
14361083Sanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
14371083Sanish {
14381083Sanish 	uint32_t *h, *d;
14391083Sanish 
14401083Sanish 	h = host_addr;
14411083Sanish 	d = dev_addr;
14421083Sanish 
14431083Sanish 	if (flags == DDI_DEV_AUTOINCR)
14441083Sanish 		for (; repcount; repcount--)
14451083Sanish 			pci_config_wr32(hdlp, d++, *h++);
14461083Sanish 	else
14471083Sanish 		for (; repcount; repcount--)
14481083Sanish 			pci_config_wr32(hdlp, d, *h++);
14491083Sanish }
14501083Sanish 
14511083Sanish uint64_t
14521083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
14531083Sanish {
14541083Sanish 	uint32_t lw_val;
14551083Sanish 	uint32_t hi_val;
14561083Sanish 	uint32_t *dp;
14571083Sanish 	uint64_t val;
14581083Sanish 
14591083Sanish 	dp = (uint32_t *)addr;
14601083Sanish 	lw_val = pci_config_rd32(hdlp, dp);
14611083Sanish 	dp++;
14621083Sanish 	hi_val = pci_config_rd32(hdlp, dp);
14631083Sanish 	val = ((uint64_t)hi_val << 32) | lw_val;
14641083Sanish 	return (val);
14651083Sanish }
14661083Sanish 
14671083Sanish void
14681083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
14691083Sanish {
14701083Sanish 	uint32_t lw_val;
14711083Sanish 	uint32_t hi_val;
14721083Sanish 	uint32_t *dp;
14731083Sanish 
14741083Sanish 	dp = (uint32_t *)addr;
14751083Sanish 	lw_val = (uint32_t)(value & 0xffffffff);
14761083Sanish 	hi_val = (uint32_t)(value >> 32);
14771083Sanish 	pci_config_wr32(hdlp, dp, lw_val);
14781083Sanish 	dp++;
14791083Sanish 	pci_config_wr32(hdlp, dp, hi_val);
14801083Sanish }
14811083Sanish 
14821083Sanish void
14831083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
14841083Sanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
14851083Sanish {
14861083Sanish 	if (flags == DDI_DEV_AUTOINCR) {
14871083Sanish 		for (; repcount; repcount--)
14881083Sanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
14891083Sanish 	} else {
14901083Sanish 		for (; repcount; repcount--)
14911083Sanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
14921083Sanish 	}
14931083Sanish }
14941083Sanish 
14951083Sanish void
14961083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
14971083Sanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
14981083Sanish {
14991083Sanish 	if (flags == DDI_DEV_AUTOINCR) {
15001083Sanish 		for (; repcount; repcount--)
15011083Sanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
15021083Sanish 	} else {
15031083Sanish 		for (; repcount; repcount--)
15041083Sanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
15051083Sanish 	}
15061083Sanish }
15071083Sanish 
15081083Sanish 
15091083Sanish /*
15101083Sanish  * Enable Legacy PCI config space access for the following four north bridges
15111083Sanish  *	Host bridge: AMD HyperTransport Technology Configuration
15121083Sanish  *	Host bridge: AMD Address Map
15131083Sanish  *	Host bridge: AMD DRAM Controller
15141083Sanish  *	Host bridge: AMD Miscellaneous Control
15151083Sanish  */
15161083Sanish int
15171083Sanish is_amd_northbridge(dev_info_t *dip)
15181083Sanish {
15191083Sanish 	int vendor_id, device_id;
15201083Sanish 
15211083Sanish 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
15221083Sanish 			"vendor-id", -1);
15231083Sanish 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
15241083Sanish 			"device-id", -1);
15251083Sanish 
15261083Sanish 	if (IS_AMD_NTBRIDGE(vendor_id, device_id))
15271083Sanish 		return (0);
15281083Sanish 
15291083Sanish 	return (1);
15301083Sanish }
1531