xref: /onnv-gate/usr/src/uts/i86pc/io/pci/pci_common.c (revision 11465:ec77021cc782)
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 /*
23*11465SKerry.Shu@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24881Sjohnny  * Use is subject to license terms.
25881Sjohnny  */
26881Sjohnny 
27881Sjohnny /*
28881Sjohnny  *	File that has code which is common between pci(7d) and npe(7d)
29881Sjohnny  *	It shares the following:
30881Sjohnny  *	- interrupt code
31881Sjohnny  *	- pci_tools ioctl code
32881Sjohnny  *	- name_child code
33881Sjohnny  *	- set_parent_private_data code
34881Sjohnny  */
35881Sjohnny 
36881Sjohnny #include <sys/conf.h>
37881Sjohnny #include <sys/pci.h>
38881Sjohnny #include <sys/sunndi.h>
39916Sschwartz #include <sys/mach_intr.h>
40881Sjohnny #include <sys/pci_intr_lib.h>
41881Sjohnny #include <sys/psm.h>
42881Sjohnny #include <sys/policy.h>
43881Sjohnny #include <sys/sysmacros.h>
44916Sschwartz #include <sys/clock.h>
453446Smrj #include <sys/apic.h>
46881Sjohnny #include <sys/pci_tools.h>
47881Sjohnny #include <io/pci/pci_var.h>
48881Sjohnny #include <io/pci/pci_tools_ext.h>
49881Sjohnny #include <io/pci/pci_common.h>
501083Sanish #include <sys/pci_cfgspace.h>
511083Sanish #include <sys/pci_impl.h>
524160Sjveta #include <sys/pci_cap.h>
53881Sjohnny 
54881Sjohnny /*
55881Sjohnny  * Function prototypes
56881Sjohnny  */
57881Sjohnny static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
58881Sjohnny static int	pci_enable_intr(dev_info_t *, dev_info_t *,
59881Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
60881Sjohnny static void	pci_disable_intr(dev_info_t *, dev_info_t *,
61881Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
62881Sjohnny 
63881Sjohnny /* Extern decalration for pcplusmp module */
64881Sjohnny extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
65881Sjohnny 		    psm_intr_op_t, int *);
66881Sjohnny 
67881Sjohnny /*
68881Sjohnny  * pci_name_child:
69881Sjohnny  *
70881Sjohnny  *	Assign the address portion of the node name
71881Sjohnny  */
72881Sjohnny int
73881Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
74881Sjohnny {
75881Sjohnny 	int		dev, func, length;
76881Sjohnny 	char		**unit_addr;
77881Sjohnny 	uint_t		n;
78881Sjohnny 	pci_regspec_t	*pci_rp;
79881Sjohnny 
80881Sjohnny 	if (ndi_dev_is_persistent_node(child) == 0) {
81881Sjohnny 		/*
82881Sjohnny 		 * For .conf node, use "unit-address" property
83881Sjohnny 		 */
84881Sjohnny 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
85881Sjohnny 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
86881Sjohnny 		    DDI_PROP_SUCCESS) {
87881Sjohnny 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
88881Sjohnny 			    ddi_get_name(child));
89881Sjohnny 			return (DDI_FAILURE);
90881Sjohnny 		}
91881Sjohnny 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
92881Sjohnny 			cmn_err(CE_WARN, "unit-address property in %s.conf"
93881Sjohnny 			    " not well-formed", ddi_get_name(child));
94881Sjohnny 			ddi_prop_free(unit_addr);
95881Sjohnny 			return (DDI_FAILURE);
96881Sjohnny 		}
97881Sjohnny 		(void) snprintf(name, namelen, "%s", *unit_addr);
98881Sjohnny 		ddi_prop_free(unit_addr);
99881Sjohnny 		return (DDI_SUCCESS);
100881Sjohnny 	}
101881Sjohnny 
102881Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
103881Sjohnny 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
104881Sjohnny 		cmn_err(CE_WARN, "cannot find reg property in %s",
105881Sjohnny 		    ddi_get_name(child));
106881Sjohnny 		return (DDI_FAILURE);
107881Sjohnny 	}
108881Sjohnny 
109881Sjohnny 	/* copy the device identifications */
110881Sjohnny 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
111881Sjohnny 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
112881Sjohnny 
113881Sjohnny 	/*
114881Sjohnny 	 * free the memory allocated by ddi_prop_lookup_int_array
115881Sjohnny 	 */
116881Sjohnny 	ddi_prop_free(pci_rp);
117881Sjohnny 
118881Sjohnny 	if (func != 0) {
119881Sjohnny 		(void) snprintf(name, namelen, "%x,%x", dev, func);
120881Sjohnny 	} else {
121881Sjohnny 		(void) snprintf(name, namelen, "%x", dev);
122881Sjohnny 	}
123881Sjohnny 
124881Sjohnny 	return (DDI_SUCCESS);
125881Sjohnny }
126881Sjohnny 
127881Sjohnny /*
128881Sjohnny  * Interrupt related code:
129881Sjohnny  *
130881Sjohnny  * The following busop is common to npe and pci drivers
131881Sjohnny  *	bus_introp
132881Sjohnny  */
133881Sjohnny 
134881Sjohnny /*
135881Sjohnny  * Create the ddi_parent_private_data for a pseudo child.
136881Sjohnny  */
137881Sjohnny void
138881Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
139881Sjohnny {
140881Sjohnny 	struct ddi_parent_private_data *pdptr;
141881Sjohnny 
142881Sjohnny 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
143881Sjohnny 	    (sizeof (struct ddi_parent_private_data) +
1444397Sschwartz 	    sizeof (struct intrspec)), KM_SLEEP);
145881Sjohnny 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
146881Sjohnny 	pdptr->par_nintr = 1;
147881Sjohnny 	ddi_set_parent_data(dip, pdptr);
148881Sjohnny }
149881Sjohnny 
150881Sjohnny /*
151881Sjohnny  * pci_get_priority:
152881Sjohnny  *	Figure out the priority of the device
153881Sjohnny  */
154881Sjohnny static int
155881Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
156881Sjohnny {
157881Sjohnny 	struct intrspec *ispec;
158881Sjohnny 
159881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
160881Sjohnny 	    (void *)dip, (void *)hdlp));
161881Sjohnny 
162881Sjohnny 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
163881Sjohnny 	    hdlp->ih_inum)) == NULL) {
164881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
1658535Sevan.yan@sun.com 			*pri = pci_class_to_pil(dip);
166881Sjohnny 			pci_common_set_parent_private_data(hdlp->ih_dip);
167881Sjohnny 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
168881Sjohnny 			    hdlp->ih_inum);
169881Sjohnny 			return (DDI_SUCCESS);
170881Sjohnny 		}
171881Sjohnny 		return (DDI_FAILURE);
172881Sjohnny 	}
173881Sjohnny 
174881Sjohnny 	*pri = ispec->intrspec_pri;
175881Sjohnny 	return (DDI_SUCCESS);
176881Sjohnny }
177881Sjohnny 
178881Sjohnny 
179881Sjohnny 
18010187SKrishna.Elango@Sun.COM static int pcieb_intr_pri_counter = 0;
181881Sjohnny 
182881Sjohnny /*
183881Sjohnny  * pci_common_intr_ops: bus_intr_op() function for interrupt support
184881Sjohnny  */
185881Sjohnny int
186881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
187881Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
188881Sjohnny {
189881Sjohnny 	int			priority = 0;
190881Sjohnny 	int			psm_status = 0;
191881Sjohnny 	int			pci_status = 0;
192881Sjohnny 	int			pci_rval, psm_rval = PSM_FAILURE;
193881Sjohnny 	int			types = 0;
194881Sjohnny 	int			pciepci = 0;
1951542Sjohnny 	int			i, j, count;
1964160Sjveta 	int			rv;
197881Sjohnny 	int			behavior;
1981997Sanish 	int			cap_ptr;
1994160Sjveta 	uint16_t		msi_cap_base, msix_cap_base, cap_ctrl;
2004160Sjveta 	char			*prop;
201881Sjohnny 	ddi_intrspec_t		isp;
202881Sjohnny 	struct intrspec		*ispec;
203881Sjohnny 	ddi_intr_handle_impl_t	tmp_hdl;
204881Sjohnny 	ddi_intr_msix_t		*msix_p;
2051087Sschwartz 	ihdl_plat_t		*ihdl_plat_datap;
2061542Sjohnny 	ddi_intr_handle_t	*h_array;
2071997Sanish 	ddi_acc_handle_t	handle;
208881Sjohnny 
209881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT,
210881Sjohnny 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
211881Sjohnny 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
212881Sjohnny 
213881Sjohnny 	/* Process the request */
214881Sjohnny 	switch (intr_op) {
215881Sjohnny 	case DDI_INTROP_SUPPORTED_TYPES:
2164160Sjveta 		/*
2174160Sjveta 		 * First we determine the interrupt types supported by the
2184160Sjveta 		 * device itself, then we filter them through what the OS
2194160Sjveta 		 * and system supports.  We determine system-level
2204160Sjveta 		 * interrupt type support for anything other than fixed intrs
2214160Sjveta 		 * through the psm_intr_ops vector
2224160Sjveta 		 */
2234160Sjveta 		rv = DDI_FAILURE;
2244160Sjveta 
225881Sjohnny 		/* Fixed supported by default */
2264160Sjveta 		types = DDI_INTR_TYPE_FIXED;
2274160Sjveta 
2284160Sjveta 		if (psm_intr_ops == NULL) {
2294160Sjveta 			*(int *)result = types;
2304160Sjveta 			return (DDI_SUCCESS);
2314160Sjveta 		}
2324160Sjveta 		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
2334160Sjveta 			return (DDI_FAILURE);
234881Sjohnny 
2354160Sjveta 		/* Sanity test cap control values if found */
2364160Sjveta 
2374160Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
2384160Sjveta 		    DDI_SUCCESS) {
2394160Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
2404160Sjveta 			    PCI_MSI_CTRL);
2414160Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
2424160Sjveta 				goto SUPPORTED_TYPES_OUT;
2434160Sjveta 
2444160Sjveta 			types |= DDI_INTR_TYPE_MSI;
2454160Sjveta 		}
2464160Sjveta 
2474160Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
2484160Sjveta 		    DDI_SUCCESS) {
2494160Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
2504160Sjveta 			    PCI_MSIX_CTRL);
2514160Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
2524160Sjveta 				goto SUPPORTED_TYPES_OUT;
253881Sjohnny 
2544160Sjveta 			types |= DDI_INTR_TYPE_MSIX;
2554160Sjveta 		}
2564160Sjveta 
2574160Sjveta 		/*
2584160Sjveta 		 * Filter device-level types through system-level support
2594160Sjveta 		 */
2604160Sjveta 		tmp_hdl.ih_type = types;
2614160Sjveta 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
2624160Sjveta 		    &types) != PSM_SUCCESS)
2634160Sjveta 			goto SUPPORTED_TYPES_OUT;
2644160Sjveta 
2654160Sjveta 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
2664160Sjveta 		    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
2674160Sjveta 		    *(int *)result));
268881Sjohnny 
2694160Sjveta 		/*
2704160Sjveta 		 * Export any MSI/MSI-X cap locations via properties
2714160Sjveta 		 */
2724160Sjveta 		if (types & DDI_INTR_TYPE_MSI) {
2734160Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
2744160Sjveta 			    "pci-msi-capid-pointer", (int)msi_cap_base) !=
2754160Sjveta 			    DDI_PROP_SUCCESS)
2764160Sjveta 				goto SUPPORTED_TYPES_OUT;
277881Sjohnny 		}
2784160Sjveta 		if (types & DDI_INTR_TYPE_MSIX) {
2794160Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
2804160Sjveta 			    "pci-msix-capid-pointer", (int)msix_cap_base) !=
2814160Sjveta 			    DDI_PROP_SUCCESS)
2824160Sjveta 				goto SUPPORTED_TYPES_OUT;
2834160Sjveta 		}
2844160Sjveta 
2854160Sjveta 		rv = DDI_SUCCESS;
2864160Sjveta 
2874160Sjveta SUPPORTED_TYPES_OUT:
2884160Sjveta 		*(int *)result = types;
2894160Sjveta 		pci_config_teardown(&handle);
2904160Sjveta 		return (rv);
2914160Sjveta 
2922580Sanish 	case DDI_INTROP_NAVAIL:
293881Sjohnny 	case DDI_INTROP_NINTRS:
2942580Sanish 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
2952580Sanish 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
2962580Sanish 			    result) != DDI_SUCCESS)
2972580Sanish 				return (DDI_FAILURE);
2982580Sanish 		} else {
2992580Sanish 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
3002580Sanish 			if (*(int *)result == 0)
3012580Sanish 				return (DDI_FAILURE);
3022580Sanish 		}
303881Sjohnny 		break;
304881Sjohnny 	case DDI_INTROP_ALLOC:
305881Sjohnny 		/*
306881Sjohnny 		 * MSI or MSIX (figure out number of vectors available)
307881Sjohnny 		 * FIXED interrupts: just return available interrupts
308881Sjohnny 		 */
309881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
310881Sjohnny 		    (psm_intr_ops != NULL) &&
311881Sjohnny 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
312881Sjohnny 			/*
31310187SKrishna.Elango@Sun.COM 			 * Following check is a special case for 'pcieb'.
314881Sjohnny 			 * This makes sure vectors with the right priority
31510187SKrishna.Elango@Sun.COM 			 * are allocated for pcieb during ALLOC time.
316881Sjohnny 			 */
31710187SKrishna.Elango@Sun.COM 			if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) {
318881Sjohnny 				hdlp->ih_pri =
31910187SKrishna.Elango@Sun.COM 				    (pcieb_intr_pri_counter % 2) ? 4 : 7;
320881Sjohnny 				pciepci = 1;
321881Sjohnny 			} else
322881Sjohnny 				hdlp->ih_pri = priority;
3231717Swesolows 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
3241997Sanish 
3251997Sanish 			/*
3261997Sanish 			 * Cache in the config handle and cap_ptr
3271997Sanish 			 */
3281997Sanish 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
3291997Sanish 				if (pci_config_setup(rdip, &handle) !=
3301997Sanish 				    DDI_SUCCESS)
3311997Sanish 					return (DDI_FAILURE);
3321997Sanish 				i_ddi_set_pci_config_handle(rdip, handle);
3331997Sanish 			}
3341997Sanish 
3354160Sjveta 			prop = NULL;
3364160Sjveta 			cap_ptr = 0;
3374160Sjveta 			if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
3384160Sjveta 				prop = "pci-msi-capid-pointer";
3394160Sjveta 			else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
3404160Sjveta 				prop = "pci-msix-capid-pointer";
3411997Sanish 
3424160Sjveta 			/*
3434160Sjveta 			 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
3444160Sjveta 			 * for MSI(X) before allocation
3454160Sjveta 			 */
3464160Sjveta 			if (prop != NULL) {
3471997Sanish 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
3484160Sjveta 				    DDI_PROP_DONTPASS, prop, 0);
3494160Sjveta 				if (cap_ptr == 0) {
3504160Sjveta 					DDI_INTR_NEXDBG((CE_CONT,
3514160Sjveta 					    "pci_common_intr_ops: rdip: 0x%p "
3524160Sjveta 					    "attempted MSI(X) alloc without "
3534160Sjveta 					    "cap property\n", (void *)rdip));
3544160Sjveta 					return (DDI_FAILURE);
3554160Sjveta 				}
3561997Sanish 			}
3574160Sjveta 			i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
3581997Sanish 
3594160Sjveta 			/*
3604160Sjveta 			 * Allocate interrupt vectors
3614160Sjveta 			 */
362881Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
363881Sjohnny 			    PSM_INTR_OP_ALLOC_VECTORS, result);
364881Sjohnny 
3653112Sanish 			if (*(int *)result == 0)
3663112Sanish 				return (DDI_INTR_NOTFOUND);
3673112Sanish 
368881Sjohnny 			/* verify behavior flag and take appropriate action */
369881Sjohnny 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
370881Sjohnny 			    (*(int *)result < hdlp->ih_scratch1)) {
371881Sjohnny 				DDI_INTR_NEXDBG((CE_CONT,
372881Sjohnny 				    "pci_common_intr_ops: behavior %x, "
373881Sjohnny 				    "couldn't get enough intrs\n", behavior));
374881Sjohnny 				hdlp->ih_scratch1 = *(int *)result;
375881Sjohnny 				(void) (*psm_intr_ops)(rdip, hdlp,
376881Sjohnny 				    PSM_INTR_OP_FREE_VECTORS, NULL);
377881Sjohnny 				return (DDI_EAGAIN);
378881Sjohnny 			}
379881Sjohnny 
380881Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
381881Sjohnny 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
382881Sjohnny 					msix_p = pci_msix_init(hdlp->ih_dip);
38310647SLipeng.Sang@Sun.COM 					if (msix_p) {
384881Sjohnny 						i_ddi_set_msix(hdlp->ih_dip,
385881Sjohnny 						    msix_p);
38610647SLipeng.Sang@Sun.COM 					} else {
38710647SLipeng.Sang@Sun.COM 						DDI_INTR_NEXDBG((CE_CONT,
38810647SLipeng.Sang@Sun.COM 						    "pci_common_intr_ops: MSI-X"
38910647SLipeng.Sang@Sun.COM 						    "table initilization failed"
39010647SLipeng.Sang@Sun.COM 						    ", rdip 0x%p inum 0x%x\n",
39110647SLipeng.Sang@Sun.COM 						    (void *)rdip,
39210647SLipeng.Sang@Sun.COM 						    hdlp->ih_inum));
39310647SLipeng.Sang@Sun.COM 
39410647SLipeng.Sang@Sun.COM 						(void) (*psm_intr_ops)(rdip,
39510647SLipeng.Sang@Sun.COM 						    hdlp,
39610647SLipeng.Sang@Sun.COM 						    PSM_INTR_OP_FREE_VECTORS,
39710647SLipeng.Sang@Sun.COM 						    NULL);
39810647SLipeng.Sang@Sun.COM 
39910647SLipeng.Sang@Sun.COM 						return (DDI_FAILURE);
40010647SLipeng.Sang@Sun.COM 					}
401881Sjohnny 				}
402881Sjohnny 			}
403881Sjohnny 
404881Sjohnny 			if (pciepci) {
405881Sjohnny 				/* update priority in ispec */
406881Sjohnny 				isp = pci_intx_get_ispec(pdip, rdip,
4074397Sschwartz 				    (int)hdlp->ih_inum);
408881Sjohnny 				ispec = (struct intrspec *)isp;
409881Sjohnny 				if (ispec)
410881Sjohnny 					ispec->intrspec_pri = hdlp->ih_pri;
41110187SKrishna.Elango@Sun.COM 				++pcieb_intr_pri_counter;
412881Sjohnny 			}
413881Sjohnny 
414881Sjohnny 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
415881Sjohnny 			/* Figure out if this device supports MASKING */
416881Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
417881Sjohnny 			if (pci_rval == DDI_SUCCESS && pci_status)
418881Sjohnny 				hdlp->ih_cap |= pci_status;
419881Sjohnny 			*(int *)result = 1;	/* DDI_INTR_TYPE_FIXED */
420881Sjohnny 		} else
421881Sjohnny 			return (DDI_FAILURE);
422881Sjohnny 		break;
423881Sjohnny 	case DDI_INTROP_FREE:
424881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
425881Sjohnny 		    (psm_intr_ops != NULL)) {
4262018Sanish 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
4272018Sanish 			    0) {
4281997Sanish 				if (handle = i_ddi_get_pci_config_handle(
4291997Sanish 				    rdip)) {
4301997Sanish 					(void) pci_config_teardown(&handle);
4311997Sanish 					i_ddi_set_pci_config_handle(rdip, NULL);
4321997Sanish 				}
4331997Sanish 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
4341997Sanish 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
4351997Sanish 			}
4361997Sanish 
437881Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
438881Sjohnny 			    PSM_INTR_OP_FREE_VECTORS, NULL);
439881Sjohnny 
440881Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
441881Sjohnny 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
442881Sjohnny 				if (msix_p &&
4432018Sanish 				    (i_ddi_intr_get_current_nintrs(
4444397Sschwartz 				    hdlp->ih_dip) - 1) == 0) {
445881Sjohnny 					pci_msix_fini(msix_p);
446881Sjohnny 					i_ddi_set_msix(hdlp->ih_dip, NULL);
447881Sjohnny 				}
448881Sjohnny 			}
449881Sjohnny 		}
450881Sjohnny 		break;
451881Sjohnny 	case DDI_INTROP_GETPRI:
452881Sjohnny 		/* Get the priority */
453881Sjohnny 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
454881Sjohnny 			return (DDI_FAILURE);
455881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
456881Sjohnny 		    "priority = 0x%x\n", priority));
457881Sjohnny 		*(int *)result = priority;
458881Sjohnny 		break;
459881Sjohnny 	case DDI_INTROP_SETPRI:
460881Sjohnny 		/* Validate the interrupt priority passed */
461881Sjohnny 		if (*(int *)result > LOCK_LEVEL)
462881Sjohnny 			return (DDI_FAILURE);
463881Sjohnny 
464881Sjohnny 		/* Ensure that PSM is all initialized */
465881Sjohnny 		if (psm_intr_ops == NULL)
466881Sjohnny 			return (DDI_FAILURE);
467881Sjohnny 
46810190SSophia.Li@Sun.COM 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
46910190SSophia.Li@Sun.COM 		ispec = (struct intrspec *)isp;
47010190SSophia.Li@Sun.COM 		if (ispec == NULL)
47110190SSophia.Li@Sun.COM 			return (DDI_FAILURE);
47210190SSophia.Li@Sun.COM 
47310190SSophia.Li@Sun.COM 		/* For fixed interrupts */
47410190SSophia.Li@Sun.COM 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
47510190SSophia.Li@Sun.COM 			/* if interrupt is shared, return failure */
47610190SSophia.Li@Sun.COM 			((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
47710190SSophia.Li@Sun.COM 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
47810190SSophia.Li@Sun.COM 			    PSM_INTR_OP_GET_SHARED, &psm_status);
47910190SSophia.Li@Sun.COM 			/*
48010190SSophia.Li@Sun.COM 			 * For fixed interrupts, the irq may not have been
48110190SSophia.Li@Sun.COM 			 * allocated when SET_PRI is called, and the above
48210190SSophia.Li@Sun.COM 			 * GET_SHARED op may return PSM_FAILURE. This is not
48310190SSophia.Li@Sun.COM 			 * a real error and is ignored below.
48410190SSophia.Li@Sun.COM 			 */
48510190SSophia.Li@Sun.COM 			if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) {
48610190SSophia.Li@Sun.COM 				DDI_INTR_NEXDBG((CE_CONT,
48710190SSophia.Li@Sun.COM 				    "pci_common_intr_ops: "
48810190SSophia.Li@Sun.COM 				    "dip 0x%p cannot setpri, psm_rval=%d,"
48910190SSophia.Li@Sun.COM 				    "psm_status=%d\n", (void *)rdip, psm_rval,
49010190SSophia.Li@Sun.COM 				    psm_status));
49110190SSophia.Li@Sun.COM 				return (DDI_FAILURE);
49210190SSophia.Li@Sun.COM 			}
49310190SSophia.Li@Sun.COM 		}
49410190SSophia.Li@Sun.COM 
495881Sjohnny 		/* Change the priority */
496881Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
497881Sjohnny 		    PSM_FAILURE)
498881Sjohnny 			return (DDI_FAILURE);
499881Sjohnny 
500881Sjohnny 		/* update ispec */
50110190SSophia.Li@Sun.COM 		ispec->intrspec_pri = *(int *)result;
502881Sjohnny 		break;
503881Sjohnny 	case DDI_INTROP_ADDISR:
504881Sjohnny 		/* update ispec */
505881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
506881Sjohnny 		ispec = (struct intrspec *)isp;
5071087Sschwartz 		if (ispec) {
508881Sjohnny 			ispec->intrspec_func = hdlp->ih_cb_func;
5091087Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
5101087Sschwartz 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
5111087Sschwartz 		}
512881Sjohnny 		break;
513881Sjohnny 	case DDI_INTROP_REMISR:
514881Sjohnny 		/* Get the interrupt structure pointer */
515881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
516881Sjohnny 		ispec = (struct intrspec *)isp;
5171087Sschwartz 		if (ispec) {
518881Sjohnny 			ispec->intrspec_func = (uint_t (*)()) 0;
5191087Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
5201087Sschwartz 			if (ihdl_plat_datap->ip_ksp != NULL)
5211087Sschwartz 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
5221087Sschwartz 		}
523881Sjohnny 		break;
524881Sjohnny 	case DDI_INTROP_GETCAP:
525881Sjohnny 		/*
526881Sjohnny 		 * First check the config space and/or
527881Sjohnny 		 * MSI capability register(s)
528881Sjohnny 		 */
529881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
530881Sjohnny 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
531881Sjohnny 			    &pci_status);
532881Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
533881Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
534881Sjohnny 
535881Sjohnny 		/* next check with pcplusmp */
536881Sjohnny 		if (psm_intr_ops != NULL)
537881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
538881Sjohnny 			    PSM_INTR_OP_GET_CAP, &psm_status);
539881Sjohnny 
540881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
541881Sjohnny 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
542881Sjohnny 		    psm_rval, psm_status, pci_rval, pci_status));
543881Sjohnny 
544881Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
545881Sjohnny 			*(int *)result = 0;
546881Sjohnny 			return (DDI_FAILURE);
547881Sjohnny 		}
548881Sjohnny 
549881Sjohnny 		if (psm_rval == PSM_SUCCESS)
550881Sjohnny 			*(int *)result = psm_status;
551881Sjohnny 
552881Sjohnny 		if (pci_rval == DDI_SUCCESS)
553881Sjohnny 			*(int *)result |= pci_status;
554881Sjohnny 
555881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
556881Sjohnny 		    *(int *)result));
557881Sjohnny 		break;
558881Sjohnny 	case DDI_INTROP_SETCAP:
559881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
560881Sjohnny 		    "SETCAP cap=0x%x\n", *(int *)result));
561881Sjohnny 		if (psm_intr_ops == NULL)
562881Sjohnny 			return (DDI_FAILURE);
563881Sjohnny 
564881Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
565881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
566881Sjohnny 			    " returned failure\n"));
567881Sjohnny 			return (DDI_FAILURE);
568881Sjohnny 		}
569881Sjohnny 		break;
570881Sjohnny 	case DDI_INTROP_ENABLE:
571881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
572881Sjohnny 		if (psm_intr_ops == NULL)
573881Sjohnny 			return (DDI_FAILURE);
574881Sjohnny 
575881Sjohnny 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
576881Sjohnny 		    DDI_SUCCESS)
577881Sjohnny 			return (DDI_FAILURE);
578881Sjohnny 
579881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
580881Sjohnny 		    "vector=0x%x\n", hdlp->ih_vector));
581881Sjohnny 		break;
582881Sjohnny 	case DDI_INTROP_DISABLE:
583881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
584881Sjohnny 		if (psm_intr_ops == NULL)
585881Sjohnny 			return (DDI_FAILURE);
586881Sjohnny 
587881Sjohnny 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
588881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
589881Sjohnny 		    "vector = %x\n", hdlp->ih_vector));
590881Sjohnny 		break;
591881Sjohnny 	case DDI_INTROP_BLOCKENABLE:
592881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
593881Sjohnny 		    "BLOCKENABLE\n"));
594881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
595881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
596881Sjohnny 			return (DDI_FAILURE);
597881Sjohnny 		}
598881Sjohnny 
599881Sjohnny 		/* Check if psm_intr_ops is NULL? */
600881Sjohnny 		if (psm_intr_ops == NULL)
601881Sjohnny 			return (DDI_FAILURE);
602881Sjohnny 
6031542Sjohnny 		count = hdlp->ih_scratch1;
6041542Sjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
6051542Sjohnny 		for (i = 0; i < count; i++) {
6061542Sjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
607881Sjohnny 			if (pci_enable_intr(pdip, rdip, hdlp,
6081542Sjohnny 			    hdlp->ih_inum) != DDI_SUCCESS) {
609881Sjohnny 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
610881Sjohnny 				    "pci_enable_intr failed for %d\n", i));
6111542Sjohnny 				for (j = 0; j < i; j++) {
6124397Sschwartz 					hdlp = (ddi_intr_handle_impl_t *)
6134397Sschwartz 					    h_array[j];
6144397Sschwartz 					pci_disable_intr(pdip, rdip, hdlp,
6151542Sjohnny 					    hdlp->ih_inum);
6161542Sjohnny 				}
617881Sjohnny 				return (DDI_FAILURE);
618881Sjohnny 			}
619881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
6201542Sjohnny 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
621881Sjohnny 		}
622881Sjohnny 		break;
623881Sjohnny 	case DDI_INTROP_BLOCKDISABLE:
624881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
625881Sjohnny 		    "BLOCKDISABLE\n"));
626881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
627881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
628881Sjohnny 			return (DDI_FAILURE);
629881Sjohnny 		}
630881Sjohnny 
631881Sjohnny 		/* Check if psm_intr_ops is present */
632881Sjohnny 		if (psm_intr_ops == NULL)
633881Sjohnny 			return (DDI_FAILURE);
634881Sjohnny 
6351542Sjohnny 		count = hdlp->ih_scratch1;
6361542Sjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
6371542Sjohnny 		for (i = 0; i < count; i++) {
6381542Sjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
6391542Sjohnny 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
640881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
6411542Sjohnny 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
642881Sjohnny 		}
643881Sjohnny 		break;
644881Sjohnny 	case DDI_INTROP_SETMASK:
645881Sjohnny 	case DDI_INTROP_CLRMASK:
646881Sjohnny 		/*
647881Sjohnny 		 * First handle in the config space
648881Sjohnny 		 */
649881Sjohnny 		if (intr_op == DDI_INTROP_SETMASK) {
650881Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
651881Sjohnny 				pci_status = pci_msi_set_mask(rdip,
652881Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
653881Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
654881Sjohnny 				pci_status = pci_intx_set_mask(rdip);
655881Sjohnny 		} else {
656881Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
657881Sjohnny 				pci_status = pci_msi_clr_mask(rdip,
658881Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
659881Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
660881Sjohnny 				pci_status = pci_intx_clr_mask(rdip);
661881Sjohnny 		}
662881Sjohnny 
663881Sjohnny 		/* For MSI/X; no need to check with pcplusmp */
664881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
665881Sjohnny 			return (pci_status);
666881Sjohnny 
667881Sjohnny 		/* For fixed interrupts only: handle config space first */
668881Sjohnny 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
669881Sjohnny 		    pci_status == DDI_SUCCESS)
670881Sjohnny 			break;
671881Sjohnny 
672881Sjohnny 		/* For fixed interrupts only: confer with pcplusmp next */
673881Sjohnny 		if (psm_intr_ops != NULL) {
674881Sjohnny 			/* If interrupt is shared; do nothing */
675881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
676881Sjohnny 			    PSM_INTR_OP_GET_SHARED, &psm_status);
677881Sjohnny 
678881Sjohnny 			if (psm_rval == PSM_FAILURE || psm_status == 1)
679881Sjohnny 				return (pci_status);
680881Sjohnny 
681881Sjohnny 			/* Now, pcplusmp should try to set/clear the mask */
682881Sjohnny 			if (intr_op == DDI_INTROP_SETMASK)
683881Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
684881Sjohnny 				    PSM_INTR_OP_SET_MASK, NULL);
685881Sjohnny 			else
686881Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
687881Sjohnny 				    PSM_INTR_OP_CLEAR_MASK, NULL);
688881Sjohnny 		}
689881Sjohnny 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
690881Sjohnny 	case DDI_INTROP_GETPENDING:
691881Sjohnny 		/*
692881Sjohnny 		 * First check the config space and/or
693881Sjohnny 		 * MSI capability register(s)
694881Sjohnny 		 */
695881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
696881Sjohnny 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
697881Sjohnny 			    hdlp->ih_inum, &pci_status);
698881Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
699881Sjohnny 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
700881Sjohnny 
701881Sjohnny 		/* On failure; next try with pcplusmp */
702881Sjohnny 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
703881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
704881Sjohnny 			    PSM_INTR_OP_GET_PENDING, &psm_status);
705881Sjohnny 
706881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
707881Sjohnny 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
708881Sjohnny 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
709881Sjohnny 		    pci_status));
710881Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
711881Sjohnny 			*(int *)result = 0;
712881Sjohnny 			return (DDI_FAILURE);
713881Sjohnny 		}
714881Sjohnny 
715881Sjohnny 		if (psm_rval != PSM_FAILURE)
716881Sjohnny 			*(int *)result = psm_status;
717881Sjohnny 		else if (pci_rval != DDI_FAILURE)
718881Sjohnny 			*(int *)result = pci_status;
719881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
720881Sjohnny 		    *(int *)result));
721881Sjohnny 		break;
72210053SEvan.Yan@Sun.COM 	case DDI_INTROP_GETTARGET:
72310053SEvan.Yan@Sun.COM 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n"));
72410053SEvan.Yan@Sun.COM 
72510053SEvan.Yan@Sun.COM 		/* Note hdlp->ih_vector is actually an irq */
72610053SEvan.Yan@Sun.COM 		if ((rv = pci_get_cpu_from_vecirq(hdlp->ih_vector, IS_IRQ)) ==
72710053SEvan.Yan@Sun.COM 		    -1)
72810053SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
72910053SEvan.Yan@Sun.COM 		*(int *)result = rv;
73010053SEvan.Yan@Sun.COM 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET "
73110053SEvan.Yan@Sun.COM 		    "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector, rv));
73210053SEvan.Yan@Sun.COM 		break;
73310053SEvan.Yan@Sun.COM 	case DDI_INTROP_SETTARGET:
73410053SEvan.Yan@Sun.COM 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n"));
73510053SEvan.Yan@Sun.COM 
73610053SEvan.Yan@Sun.COM 		/* hdlp->ih_vector is actually an irq */
73710053SEvan.Yan@Sun.COM 		tmp_hdl.ih_vector = hdlp->ih_vector;
73810053SEvan.Yan@Sun.COM 		tmp_hdl.ih_flags = PSMGI_INTRBY_IRQ;
73910053SEvan.Yan@Sun.COM 		tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result;
74010053SEvan.Yan@Sun.COM 		psm_rval = (*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU,
74110053SEvan.Yan@Sun.COM 		    &psm_status);
74210053SEvan.Yan@Sun.COM 
74310053SEvan.Yan@Sun.COM 		if (psm_rval != PSM_SUCCESS)
74410053SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
74510053SEvan.Yan@Sun.COM 		break;
746881Sjohnny 	default:
747881Sjohnny 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
748881Sjohnny 	}
749881Sjohnny 
750881Sjohnny 	return (DDI_SUCCESS);
751881Sjohnny }
752881Sjohnny 
753916Sschwartz int
754916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
755916Sschwartz     int vecirq, boolean_t is_irq)
756916Sschwartz {
757916Sschwartz 	ddi_intr_handle_impl_t	get_info_ii_hdl;
758916Sschwartz 
759916Sschwartz 	if (is_irq)
760916Sschwartz 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
761916Sschwartz 
762916Sschwartz 	/*
763916Sschwartz 	 * For this locally-declared and used handle, ih_private will contain a
764916Sschwartz 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
765916Sschwartz 	 * global interrupt handling.
766916Sschwartz 	 */
767916Sschwartz 	get_info_ii_hdl.ih_private = intrinfo_p;
768916Sschwartz 	get_info_ii_hdl.ih_vector = (ushort_t)vecirq;
769916Sschwartz 
770916Sschwartz 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
771916Sschwartz 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
772916Sschwartz 		return (DDI_FAILURE);
773916Sschwartz 
774916Sschwartz 	return (DDI_SUCCESS);
775916Sschwartz }
776916Sschwartz 
777916Sschwartz 
778916Sschwartz int
779916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
780916Sschwartz {
781916Sschwartz 	int rval;
782916Sschwartz 
783916Sschwartz 	apic_get_intr_t	intrinfo;
784916Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
785916Sschwartz 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
786916Sschwartz 
787916Sschwartz 	if (rval == DDI_SUCCESS)
788916Sschwartz 		return (intrinfo.avgi_cpu_id);
789916Sschwartz 	else
790916Sschwartz 		return (-1);
791916Sschwartz }
792916Sschwartz 
793881Sjohnny 
794881Sjohnny static int
795881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
796881Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
797881Sjohnny {
798881Sjohnny 	struct intrspec	*ispec;
799916Sschwartz 	int		irq;
800916Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
801881Sjohnny 
802881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
803881Sjohnny 	    (void *)hdlp, inum));
804881Sjohnny 
805881Sjohnny 	/* Translate the interrupt if needed */
806881Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
8072288Sanish 	if (ispec == NULL)
8082288Sanish 		return (DDI_FAILURE);
80910190SSophia.Li@Sun.COM 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
810881Sjohnny 		ispec->intrspec_vec = inum;
81110190SSophia.Li@Sun.COM 		ispec->intrspec_pri = hdlp->ih_pri;
81210190SSophia.Li@Sun.COM 	}
813916Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
814881Sjohnny 
815881Sjohnny 	/* translate the interrupt if needed */
816*11465SKerry.Shu@Sun.COM 	if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) ==
817*11465SKerry.Shu@Sun.COM 	    PSM_FAILURE)
818*11465SKerry.Shu@Sun.COM 		return (DDI_FAILURE);
819916Sschwartz 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
820916Sschwartz 	    hdlp->ih_pri, irq));
821881Sjohnny 
822881Sjohnny 	/* Add the interrupt handler */
823881Sjohnny 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
824916Sschwartz 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
825916Sschwartz 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
826881Sjohnny 		return (DDI_FAILURE);
827881Sjohnny 
828916Sschwartz 	/* Note this really is an irq. */
829916Sschwartz 	hdlp->ih_vector = (ushort_t)irq;
830916Sschwartz 
831881Sjohnny 	return (DDI_SUCCESS);
832881Sjohnny }
833881Sjohnny 
834881Sjohnny 
835881Sjohnny static void
836881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
837881Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
838881Sjohnny {
839916Sschwartz 	int		irq;
840881Sjohnny 	struct intrspec	*ispec;
841916Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
842881Sjohnny 
843881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
844881Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
8452288Sanish 	if (ispec == NULL)
8462288Sanish 		return;
84710190SSophia.Li@Sun.COM 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
848881Sjohnny 		ispec->intrspec_vec = inum;
84910190SSophia.Li@Sun.COM 		ispec->intrspec_pri = hdlp->ih_pri;
85010190SSophia.Li@Sun.COM 	}
851916Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
852881Sjohnny 
853881Sjohnny 	/* translate the interrupt if needed */
854916Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
855881Sjohnny 
856881Sjohnny 	/* Disable the interrupt handler */
857916Sschwartz 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
858916Sschwartz 	ihdl_plat_datap->ip_ispecp = NULL;
859881Sjohnny }
860881Sjohnny 
861881Sjohnny /*
862881Sjohnny  * Miscellaneous library function
863881Sjohnny  */
864881Sjohnny int
865881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
866881Sjohnny {
867881Sjohnny 	int		i;
868881Sjohnny 	int 		number;
869881Sjohnny 	int		assigned_addr_len;
870881Sjohnny 	uint_t		phys_hi = pci_rp->pci_phys_hi;
871881Sjohnny 	pci_regspec_t	*assigned_addr;
872881Sjohnny 
873881Sjohnny 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
874881Sjohnny 	    (phys_hi & PCI_RELOCAT_B))
875881Sjohnny 		return (DDI_SUCCESS);
876881Sjohnny 
877881Sjohnny 	/*
878881Sjohnny 	 * the "reg" property specifies relocatable, get and interpret the
879881Sjohnny 	 * "assigned-addresses" property.
880881Sjohnny 	 */
881881Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
882881Sjohnny 	    "assigned-addresses", (int **)&assigned_addr,
883881Sjohnny 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
884881Sjohnny 		return (DDI_FAILURE);
885881Sjohnny 
886881Sjohnny 	/*
887881Sjohnny 	 * Scan the "assigned-addresses" for one that matches the specified
888881Sjohnny 	 * "reg" property entry.
889881Sjohnny 	 */
890881Sjohnny 	phys_hi &= PCI_CONF_ADDR_MASK;
891881Sjohnny 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
892881Sjohnny 	for (i = 0; i < number; i++) {
893881Sjohnny 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
894881Sjohnny 		    phys_hi) {
895881Sjohnny 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
896881Sjohnny 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
897881Sjohnny 			ddi_prop_free(assigned_addr);
898881Sjohnny 			return (DDI_SUCCESS);
899881Sjohnny 		}
900881Sjohnny 	}
901881Sjohnny 
902881Sjohnny 	ddi_prop_free(assigned_addr);
903881Sjohnny 	return (DDI_FAILURE);
904881Sjohnny }
905881Sjohnny 
906881Sjohnny 
907881Sjohnny /*
90810923SEvan.Yan@Sun.COM  * To handle PCI tool ioctls
909881Sjohnny  */
910881Sjohnny 
91110923SEvan.Yan@Sun.COM /*ARGSUSED*/
912881Sjohnny int
913881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
914881Sjohnny     int mode, cred_t *credp, int *rvalp)
915881Sjohnny {
91610923SEvan.Yan@Sun.COM 	minor_t	minor = getminor(dev);
91710923SEvan.Yan@Sun.COM 	int	rv = ENOTTY;
918881Sjohnny 
91910923SEvan.Yan@Sun.COM 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
920881Sjohnny 	case PCI_TOOL_REG_MINOR_NUM:
921881Sjohnny 
922881Sjohnny 		switch (cmd) {
923881Sjohnny 		case PCITOOL_DEVICE_SET_REG:
924881Sjohnny 		case PCITOOL_DEVICE_GET_REG:
925881Sjohnny 
926881Sjohnny 			/* Require full privileges. */
927881Sjohnny 			if (secpolicy_kmdb(credp))
928881Sjohnny 				rv = EPERM;
929881Sjohnny 			else
930881Sjohnny 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
931881Sjohnny 				    cmd, mode);
932881Sjohnny 			break;
933881Sjohnny 
934881Sjohnny 		case PCITOOL_NEXUS_SET_REG:
935881Sjohnny 		case PCITOOL_NEXUS_GET_REG:
936881Sjohnny 
937881Sjohnny 			/* Require full privileges. */
938881Sjohnny 			if (secpolicy_kmdb(credp))
939881Sjohnny 				rv = EPERM;
940881Sjohnny 			else
941881Sjohnny 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
942881Sjohnny 				    cmd, mode);
943881Sjohnny 			break;
944881Sjohnny 		}
945881Sjohnny 		break;
946881Sjohnny 
947881Sjohnny 	case PCI_TOOL_INTR_MINOR_NUM:
948881Sjohnny 
949881Sjohnny 		switch (cmd) {
950881Sjohnny 		case PCITOOL_DEVICE_SET_INTR:
951881Sjohnny 
952881Sjohnny 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
953881Sjohnny 			if (secpolicy_ponline(credp)) {
954881Sjohnny 				rv = EPERM;
955881Sjohnny 				break;
956881Sjohnny 			}
957881Sjohnny 
958881Sjohnny 		/*FALLTHRU*/
959881Sjohnny 		/* These require no special privileges. */
960881Sjohnny 		case PCITOOL_DEVICE_GET_INTR:
9614397Sschwartz 		case PCITOOL_SYSTEM_INTR_INFO:
962881Sjohnny 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
963881Sjohnny 			break;
964881Sjohnny 		}
965881Sjohnny 		break;
966881Sjohnny 
967881Sjohnny 	default:
968881Sjohnny 		break;
969881Sjohnny 	}
970881Sjohnny 
971881Sjohnny 	return (rv);
972881Sjohnny }
9731083Sanish 
9741083Sanish 
9751865Sdilpreet int
9761865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
9771865Sdilpreet {
9781865Sdilpreet 	size_t size = in_args->size;
9791865Sdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
9801865Sdilpreet 	uintptr_t host_addr = in_args->host_addr;
9811865Sdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
9821865Sdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
9831865Sdilpreet 	size_t repcount = in_args->repcount;
9841865Sdilpreet 	uint_t flags = in_args->flags;
9851865Sdilpreet 	int err = DDI_SUCCESS;
9861865Sdilpreet 
9871865Sdilpreet 	/*
9881865Sdilpreet 	 * if no handle then this is a poke. We have to return failure here
9891865Sdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
9901865Sdilpreet 	 */
9911865Sdilpreet 	if (in_args->handle == NULL)
9921865Sdilpreet 		return (DDI_FAILURE);
9931865Sdilpreet 
9941865Sdilpreet 	/*
9951865Sdilpreet 	 * rest of this function is actually for cautious puts
9961865Sdilpreet 	 */
9971865Sdilpreet 	for (; repcount; repcount--) {
9981865Sdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
9991865Sdilpreet 			switch (size) {
10001865Sdilpreet 			case sizeof (uint8_t):
10011865Sdilpreet 				pci_config_wr8(hp, (uint8_t *)dev_addr,
10021865Sdilpreet 				    *(uint8_t *)host_addr);
10031865Sdilpreet 				break;
10041865Sdilpreet 			case sizeof (uint16_t):
10051865Sdilpreet 				pci_config_wr16(hp, (uint16_t *)dev_addr,
10061865Sdilpreet 				    *(uint16_t *)host_addr);
10071865Sdilpreet 				break;
10081865Sdilpreet 			case sizeof (uint32_t):
10091865Sdilpreet 				pci_config_wr32(hp, (uint32_t *)dev_addr,
10101865Sdilpreet 				    *(uint32_t *)host_addr);
10111865Sdilpreet 				break;
10121865Sdilpreet 			case sizeof (uint64_t):
10131865Sdilpreet 				pci_config_wr64(hp, (uint64_t *)dev_addr,
10141865Sdilpreet 				    *(uint64_t *)host_addr);
10151865Sdilpreet 				break;
10161865Sdilpreet 			default:
10171865Sdilpreet 				err = DDI_FAILURE;
10181865Sdilpreet 				break;
10191865Sdilpreet 			}
10201865Sdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
10211865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
10221865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
10231865Sdilpreet 				switch (size) {
10241865Sdilpreet 				case sizeof (uint8_t):
10251865Sdilpreet 					i_ddi_io_put8(hp,
10261865Sdilpreet 					    (uint8_t *)dev_addr,
10271865Sdilpreet 					    *(uint8_t *)host_addr);
10281865Sdilpreet 					break;
10291865Sdilpreet 				case sizeof (uint16_t):
10301865Sdilpreet 					i_ddi_io_swap_put16(hp,
10311865Sdilpreet 					    (uint16_t *)dev_addr,
10321865Sdilpreet 					    *(uint16_t *)host_addr);
10331865Sdilpreet 					break;
10341865Sdilpreet 				case sizeof (uint32_t):
10351865Sdilpreet 					i_ddi_io_swap_put32(hp,
10361865Sdilpreet 					    (uint32_t *)dev_addr,
10371865Sdilpreet 					    *(uint32_t *)host_addr);
10381865Sdilpreet 					break;
10391865Sdilpreet 				/*
10401865Sdilpreet 				 * note the 64-bit case is a dummy
10411865Sdilpreet 				 * function - so no need to swap
10421865Sdilpreet 				 */
10431865Sdilpreet 				case sizeof (uint64_t):
10441865Sdilpreet 					i_ddi_io_put64(hp,
10451865Sdilpreet 					    (uint64_t *)dev_addr,
10461865Sdilpreet 					    *(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 					i_ddi_io_put8(hp,
10561865Sdilpreet 					    (uint8_t *)dev_addr,
10571865Sdilpreet 					    *(uint8_t *)host_addr);
10581865Sdilpreet 					break;
10591865Sdilpreet 				case sizeof (uint16_t):
10601865Sdilpreet 					i_ddi_io_put16(hp,
10611865Sdilpreet 					    (uint16_t *)dev_addr,
10621865Sdilpreet 					    *(uint16_t *)host_addr);
10631865Sdilpreet 					break;
10641865Sdilpreet 				case sizeof (uint32_t):
10651865Sdilpreet 					i_ddi_io_put32(hp,
10661865Sdilpreet 					    (uint32_t *)dev_addr,
10671865Sdilpreet 					    *(uint32_t *)host_addr);
10681865Sdilpreet 					break;
10691865Sdilpreet 				case sizeof (uint64_t):
10701865Sdilpreet 					i_ddi_io_put64(hp,
10711865Sdilpreet 					    (uint64_t *)dev_addr,
10721865Sdilpreet 					    *(uint64_t *)host_addr);
10731865Sdilpreet 					break;
10741865Sdilpreet 				default:
10751865Sdilpreet 					err = DDI_FAILURE;
10761865Sdilpreet 					break;
10771865Sdilpreet 				}
10781865Sdilpreet 			}
10791865Sdilpreet 		} else {
10801865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
10811865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
10821865Sdilpreet 				switch (size) {
10831865Sdilpreet 				case sizeof (uint8_t):
10841865Sdilpreet 					*(uint8_t *)dev_addr =
10851865Sdilpreet 					    *(uint8_t *)host_addr;
10861865Sdilpreet 					break;
10871865Sdilpreet 				case sizeof (uint16_t):
10881865Sdilpreet 					*(uint16_t *)dev_addr =
10891865Sdilpreet 					    ddi_swap16(*(uint16_t *)host_addr);
10901865Sdilpreet 					break;
10911865Sdilpreet 				case sizeof (uint32_t):
10921865Sdilpreet 					*(uint32_t *)dev_addr =
10931865Sdilpreet 					    ddi_swap32(*(uint32_t *)host_addr);
10941865Sdilpreet 					break;
10951865Sdilpreet 				case sizeof (uint64_t):
10961865Sdilpreet 					*(uint64_t *)dev_addr =
10971865Sdilpreet 					    ddi_swap64(*(uint64_t *)host_addr);
10981865Sdilpreet 					break;
10991865Sdilpreet 				default:
11001865Sdilpreet 					err = DDI_FAILURE;
11011865Sdilpreet 					break;
11021865Sdilpreet 				}
11031865Sdilpreet 			} else {
11041865Sdilpreet 				switch (size) {
11051865Sdilpreet 				case sizeof (uint8_t):
11061865Sdilpreet 					*(uint8_t *)dev_addr =
11071865Sdilpreet 					    *(uint8_t *)host_addr;
11081865Sdilpreet 					break;
11091865Sdilpreet 				case sizeof (uint16_t):
11101865Sdilpreet 					*(uint16_t *)dev_addr =
11111865Sdilpreet 					    *(uint16_t *)host_addr;
11121865Sdilpreet 					break;
11131865Sdilpreet 				case sizeof (uint32_t):
11141865Sdilpreet 					*(uint32_t *)dev_addr =
11151865Sdilpreet 					    *(uint32_t *)host_addr;
11161865Sdilpreet 					break;
11171865Sdilpreet 				case sizeof (uint64_t):
11181865Sdilpreet 					*(uint64_t *)dev_addr =
11191865Sdilpreet 					    *(uint64_t *)host_addr;
11201865Sdilpreet 					break;
11211865Sdilpreet 				default:
11221865Sdilpreet 					err = DDI_FAILURE;
11231865Sdilpreet 					break;
11241865Sdilpreet 				}
11251865Sdilpreet 			}
11261865Sdilpreet 		}
11271865Sdilpreet 		host_addr += size;
11281865Sdilpreet 		if (flags == DDI_DEV_AUTOINCR)
11291865Sdilpreet 			dev_addr += size;
11301865Sdilpreet 	}
11311865Sdilpreet 	return (err);
11321865Sdilpreet }
11331865Sdilpreet 
11341865Sdilpreet 
11351865Sdilpreet int
11361865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
11371865Sdilpreet {
11381865Sdilpreet 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
11391865Sdilpreet 
11401865Sdilpreet 	/* endian-ness check */
11411865Sdilpreet 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
11421865Sdilpreet 		return (DDI_FAILURE);
11431865Sdilpreet 
11441865Sdilpreet 	/*
11451865Sdilpreet 	 * range check
11461865Sdilpreet 	 */
11471865Sdilpreet 	if ((offset >= PCI_CONF_HDR_SIZE) ||
11481865Sdilpreet 	    (len > PCI_CONF_HDR_SIZE) ||
11491865Sdilpreet 	    (offset + len > PCI_CONF_HDR_SIZE))
11501865Sdilpreet 		return (DDI_FAILURE);
11511865Sdilpreet 
11521865Sdilpreet 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
11531865Sdilpreet 	/*
11541865Sdilpreet 	 * always use cautious mechanism for config space gets
11551865Sdilpreet 	 */
11561865Sdilpreet 	ap->ahi_get8 = i_ddi_caut_get8;
11571865Sdilpreet 	ap->ahi_get16 = i_ddi_caut_get16;
11581865Sdilpreet 	ap->ahi_get32 = i_ddi_caut_get32;
11591865Sdilpreet 	ap->ahi_get64 = i_ddi_caut_get64;
11601865Sdilpreet 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
11611865Sdilpreet 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
11621865Sdilpreet 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
11631865Sdilpreet 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
11641865Sdilpreet 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
11651865Sdilpreet 		ap->ahi_put8 = i_ddi_caut_put8;
11661865Sdilpreet 		ap->ahi_put16 = i_ddi_caut_put16;
11671865Sdilpreet 		ap->ahi_put32 = i_ddi_caut_put32;
11681865Sdilpreet 		ap->ahi_put64 = i_ddi_caut_put64;
11691865Sdilpreet 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
11701865Sdilpreet 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
11711865Sdilpreet 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
11721865Sdilpreet 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
11731865Sdilpreet 	} else {
11741865Sdilpreet 		ap->ahi_put8 = pci_config_wr8;
11751865Sdilpreet 		ap->ahi_put16 = pci_config_wr16;
11761865Sdilpreet 		ap->ahi_put32 = pci_config_wr32;
11771865Sdilpreet 		ap->ahi_put64 = pci_config_wr64;
11781865Sdilpreet 		ap->ahi_rep_put8 = pci_config_rep_wr8;
11791865Sdilpreet 		ap->ahi_rep_put16 = pci_config_rep_wr16;
11801865Sdilpreet 		ap->ahi_rep_put32 = pci_config_rep_wr32;
11811865Sdilpreet 		ap->ahi_rep_put64 = pci_config_rep_wr64;
11821865Sdilpreet 	}
11831865Sdilpreet 
11841865Sdilpreet 	/* Initialize to default check/notify functions */
11851865Sdilpreet 	ap->ahi_fault_check = i_ddi_acc_fault_check;
11861865Sdilpreet 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
11871865Sdilpreet 	ap->ahi_fault = 0;
11881865Sdilpreet 	impl_acc_err_init(hp);
11891865Sdilpreet 	return (DDI_SUCCESS);
11901865Sdilpreet }
11911865Sdilpreet 
11921865Sdilpreet 
11931865Sdilpreet int
11941865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
11951865Sdilpreet {
11961865Sdilpreet 	size_t size = in_args->size;
11971865Sdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
11981865Sdilpreet 	uintptr_t host_addr = in_args->host_addr;
11991865Sdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
12001865Sdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
12011865Sdilpreet 	size_t repcount = in_args->repcount;
12021865Sdilpreet 	uint_t flags = in_args->flags;
12031865Sdilpreet 	int err = DDI_SUCCESS;
12041865Sdilpreet 
12051865Sdilpreet 	/*
12061865Sdilpreet 	 * if no handle then this is a peek. We have to return failure here
12071865Sdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
12081865Sdilpreet 	 */
12091865Sdilpreet 	if (in_args->handle == NULL)
12101865Sdilpreet 		return (DDI_FAILURE);
12111865Sdilpreet 
12121865Sdilpreet 	for (; repcount; repcount--) {
12131865Sdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
12141865Sdilpreet 			switch (size) {
12151865Sdilpreet 			case sizeof (uint8_t):
12161865Sdilpreet 				*(uint8_t *)host_addr = pci_config_rd8(hp,
12171865Sdilpreet 				    (uint8_t *)dev_addr);
12181865Sdilpreet 				break;
12191865Sdilpreet 			case sizeof (uint16_t):
12201865Sdilpreet 				*(uint16_t *)host_addr = pci_config_rd16(hp,
12211865Sdilpreet 				    (uint16_t *)dev_addr);
12221865Sdilpreet 				break;
12231865Sdilpreet 			case sizeof (uint32_t):
12241865Sdilpreet 				*(uint32_t *)host_addr = pci_config_rd32(hp,
12251865Sdilpreet 				    (uint32_t *)dev_addr);
12261865Sdilpreet 				break;
12271865Sdilpreet 			case sizeof (uint64_t):
12281865Sdilpreet 				*(uint64_t *)host_addr = pci_config_rd64(hp,
12291865Sdilpreet 				    (uint64_t *)dev_addr);
12301865Sdilpreet 				break;
12311865Sdilpreet 			default:
12321865Sdilpreet 				err = DDI_FAILURE;
12331865Sdilpreet 				break;
12341865Sdilpreet 			}
12351865Sdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
12361865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
12371865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
12381865Sdilpreet 				switch (size) {
12391865Sdilpreet 				case sizeof (uint8_t):
12401865Sdilpreet 					*(uint8_t *)host_addr =
12411865Sdilpreet 					    i_ddi_io_get8(hp,
12421865Sdilpreet 					    (uint8_t *)dev_addr);
12431865Sdilpreet 					break;
12441865Sdilpreet 				case sizeof (uint16_t):
12451865Sdilpreet 					*(uint16_t *)host_addr =
12461865Sdilpreet 					    i_ddi_io_swap_get16(hp,
12471865Sdilpreet 					    (uint16_t *)dev_addr);
12481865Sdilpreet 					break;
12491865Sdilpreet 				case sizeof (uint32_t):
12501865Sdilpreet 					*(uint32_t *)host_addr =
12511865Sdilpreet 					    i_ddi_io_swap_get32(hp,
12521865Sdilpreet 					    (uint32_t *)dev_addr);
12531865Sdilpreet 					break;
12541865Sdilpreet 				/*
12551865Sdilpreet 				 * note the 64-bit case is a dummy
12561865Sdilpreet 				 * function - so no need to swap
12571865Sdilpreet 				 */
12581865Sdilpreet 				case sizeof (uint64_t):
12591865Sdilpreet 					*(uint64_t *)host_addr =
12601865Sdilpreet 					    i_ddi_io_get64(hp,
12611865Sdilpreet 					    (uint64_t *)dev_addr);
12621865Sdilpreet 					break;
12631865Sdilpreet 				default:
12641865Sdilpreet 					err = DDI_FAILURE;
12651865Sdilpreet 					break;
12661865Sdilpreet 				}
12671865Sdilpreet 			} else {
12681865Sdilpreet 				switch (size) {
12691865Sdilpreet 				case sizeof (uint8_t):
12701865Sdilpreet 					*(uint8_t *)host_addr =
12711865Sdilpreet 					    i_ddi_io_get8(hp,
12721865Sdilpreet 					    (uint8_t *)dev_addr);
12731865Sdilpreet 					break;
12741865Sdilpreet 				case sizeof (uint16_t):
12751865Sdilpreet 					*(uint16_t *)host_addr =
12761865Sdilpreet 					    i_ddi_io_get16(hp,
12771865Sdilpreet 					    (uint16_t *)dev_addr);
12781865Sdilpreet 					break;
12791865Sdilpreet 				case sizeof (uint32_t):
12801865Sdilpreet 					*(uint32_t *)host_addr =
12811865Sdilpreet 					    i_ddi_io_get32(hp,
12821865Sdilpreet 					    (uint32_t *)dev_addr);
12831865Sdilpreet 					break;
12841865Sdilpreet 				case sizeof (uint64_t):
12851865Sdilpreet 					*(uint64_t *)host_addr =
12861865Sdilpreet 					    i_ddi_io_get64(hp,
12871865Sdilpreet 					    (uint64_t *)dev_addr);
12881865Sdilpreet 					break;
12891865Sdilpreet 				default:
12901865Sdilpreet 					err = DDI_FAILURE;
12911865Sdilpreet 					break;
12921865Sdilpreet 				}
12931865Sdilpreet 			}
12941865Sdilpreet 		} else {
12951865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
12961865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
12971865Sdilpreet 				switch (in_args->size) {
12981865Sdilpreet 				case sizeof (uint8_t):
12991865Sdilpreet 					*(uint8_t *)host_addr =
13001865Sdilpreet 					    *(uint8_t *)dev_addr;
13011865Sdilpreet 					break;
13021865Sdilpreet 				case sizeof (uint16_t):
13031865Sdilpreet 					*(uint16_t *)host_addr =
13041865Sdilpreet 					    ddi_swap16(*(uint16_t *)dev_addr);
13051865Sdilpreet 					break;
13061865Sdilpreet 				case sizeof (uint32_t):
13071865Sdilpreet 					*(uint32_t *)host_addr =
13081865Sdilpreet 					    ddi_swap32(*(uint32_t *)dev_addr);
13091865Sdilpreet 					break;
13101865Sdilpreet 				case sizeof (uint64_t):
13111865Sdilpreet 					*(uint64_t *)host_addr =
13121865Sdilpreet 					    ddi_swap64(*(uint64_t *)dev_addr);
13131865Sdilpreet 					break;
13141865Sdilpreet 				default:
13151865Sdilpreet 					err = DDI_FAILURE;
13161865Sdilpreet 					break;
13171865Sdilpreet 				}
13181865Sdilpreet 			} else {
13191865Sdilpreet 				switch (in_args->size) {
13201865Sdilpreet 				case sizeof (uint8_t):
13211865Sdilpreet 					*(uint8_t *)host_addr =
13221865Sdilpreet 					    *(uint8_t *)dev_addr;
13231865Sdilpreet 					break;
13241865Sdilpreet 				case sizeof (uint16_t):
13251865Sdilpreet 					*(uint16_t *)host_addr =
13261865Sdilpreet 					    *(uint16_t *)dev_addr;
13271865Sdilpreet 					break;
13281865Sdilpreet 				case sizeof (uint32_t):
13291865Sdilpreet 					*(uint32_t *)host_addr =
13301865Sdilpreet 					    *(uint32_t *)dev_addr;
13311865Sdilpreet 					break;
13321865Sdilpreet 				case sizeof (uint64_t):
13331865Sdilpreet 					*(uint64_t *)host_addr =
13341865Sdilpreet 					    *(uint64_t *)dev_addr;
13351865Sdilpreet 					break;
13361865Sdilpreet 				default:
13371865Sdilpreet 					err = DDI_FAILURE;
13381865Sdilpreet 					break;
13391865Sdilpreet 				}
13401865Sdilpreet 			}
13411865Sdilpreet 		}
13421865Sdilpreet 		host_addr += size;
13431865Sdilpreet 		if (flags == DDI_DEV_AUTOINCR)
13441865Sdilpreet 			dev_addr += size;
13451865Sdilpreet 	}
13461865Sdilpreet 	return (err);
13471865Sdilpreet }
13481865Sdilpreet 
13491865Sdilpreet /*ARGSUSED*/
13501865Sdilpreet int
13511865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
13521865Sdilpreet 	ddi_ctl_enum_t ctlop, void *arg, void *result)
13531865Sdilpreet {
13541865Sdilpreet 	if (ctlop == DDI_CTLOPS_PEEK)
13551865Sdilpreet 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
13561865Sdilpreet 	else
13571865Sdilpreet 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
13581865Sdilpreet }
13591865Sdilpreet 
13601083Sanish /*
13611083Sanish  * These are the get and put functions to be shared with drivers. The
13621083Sanish  * mutex locking is done inside the functions referenced, rather than
13631083Sanish  * here, and is thus shared across PCI child drivers and any other
13641083Sanish  * consumers of PCI config space (such as the ACPI subsystem).
13651083Sanish  *
13661083Sanish  * The configuration space addresses come in as pointers.  This is fine on
13671083Sanish  * a 32-bit system, where the VM space and configuration space are the same
13681083Sanish  * size.  It's not such a good idea on a 64-bit system, where memory
13691083Sanish  * addresses are twice as large as configuration space addresses.  At some
13701083Sanish  * point in the call tree we need to take a stand and say "you are 32-bit
13711083Sanish  * from this time forth", and this seems like a nice self-contained place.
13721083Sanish  */
13731083Sanish 
13741083Sanish uint8_t
13751083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
13761083Sanish {
13771083Sanish 	pci_acc_cfblk_t *cfp;
13781083Sanish 	uint8_t	rval;
13791083Sanish 	int reg;
13801083Sanish 
13811083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
13821083Sanish 
13831083Sanish 	reg = (int)(uintptr_t)addr;
13841083Sanish 
13851083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
13861083Sanish 
13871083Sanish 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
13881083Sanish 	    reg);
13891083Sanish 
13901083Sanish 	return (rval);
13911083Sanish }
13921083Sanish 
13931083Sanish void
13941083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
13951083Sanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
13961083Sanish {
13971083Sanish 	uint8_t *h, *d;
13981083Sanish 
13991083Sanish 	h = host_addr;
14001083Sanish 	d = dev_addr;
14011083Sanish 
14021083Sanish 	if (flags == DDI_DEV_AUTOINCR)
14031083Sanish 		for (; repcount; repcount--)
14041083Sanish 			*h++ = pci_config_rd8(hdlp, d++);
14051083Sanish 	else
14061083Sanish 		for (; repcount; repcount--)
14071083Sanish 			*h++ = pci_config_rd8(hdlp, d);
14081083Sanish }
14091083Sanish 
14101083Sanish uint16_t
14111083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
14121083Sanish {
14131083Sanish 	pci_acc_cfblk_t *cfp;
14141083Sanish 	uint16_t rval;
14151083Sanish 	int reg;
14161083Sanish 
14171083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
14181083Sanish 
14191083Sanish 	reg = (int)(uintptr_t)addr;
14201083Sanish 
14211083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
14221083Sanish 
14231083Sanish 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
14241083Sanish 	    reg);
14251083Sanish 
14261083Sanish 	return (rval);
14271083Sanish }
14281083Sanish 
14291083Sanish void
14301083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
14311083Sanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
14321083Sanish {
14331083Sanish 	uint16_t *h, *d;
14341083Sanish 
14351083Sanish 	h = host_addr;
14361083Sanish 	d = dev_addr;
14371083Sanish 
14381083Sanish 	if (flags == DDI_DEV_AUTOINCR)
14391083Sanish 		for (; repcount; repcount--)
14401083Sanish 			*h++ = pci_config_rd16(hdlp, d++);
14411083Sanish 	else
14421083Sanish 		for (; repcount; repcount--)
14431083Sanish 			*h++ = pci_config_rd16(hdlp, d);
14441083Sanish }
14451083Sanish 
14461083Sanish uint32_t
14471083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
14481083Sanish {
14491083Sanish 	pci_acc_cfblk_t *cfp;
14501083Sanish 	uint32_t rval;
14511083Sanish 	int reg;
14521083Sanish 
14531083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
14541083Sanish 
14551083Sanish 	reg = (int)(uintptr_t)addr;
14561083Sanish 
14571083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
14581083Sanish 
14591083Sanish 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
14601083Sanish 	    cfp->c_funcnum, reg);
14611083Sanish 
14621083Sanish 	return (rval);
14631083Sanish }
14641083Sanish 
14651083Sanish void
14661083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
14671083Sanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
14681083Sanish {
14691083Sanish 	uint32_t *h, *d;
14701083Sanish 
14711083Sanish 	h = host_addr;
14721083Sanish 	d = dev_addr;
14731083Sanish 
14741083Sanish 	if (flags == DDI_DEV_AUTOINCR)
14751083Sanish 		for (; repcount; repcount--)
14761083Sanish 			*h++ = pci_config_rd32(hdlp, d++);
14771083Sanish 	else
14781083Sanish 		for (; repcount; repcount--)
14791083Sanish 			*h++ = pci_config_rd32(hdlp, d);
14801083Sanish }
14811083Sanish 
14821083Sanish 
14831083Sanish void
14841083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
14851083Sanish {
14861083Sanish 	pci_acc_cfblk_t *cfp;
14871083Sanish 	int reg;
14881083Sanish 
14891083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
14901083Sanish 
14911083Sanish 	reg = (int)(uintptr_t)addr;
14921083Sanish 
14931083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
14941083Sanish 
14951083Sanish 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
14961083Sanish 	    cfp->c_funcnum, reg, value);
14971083Sanish }
14981083Sanish 
14991083Sanish void
15001083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
15011083Sanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
15021083Sanish {
15031083Sanish 	uint8_t *h, *d;
15041083Sanish 
15051083Sanish 	h = host_addr;
15061083Sanish 	d = dev_addr;
15071083Sanish 
15081083Sanish 	if (flags == DDI_DEV_AUTOINCR)
15091083Sanish 		for (; repcount; repcount--)
15101083Sanish 			pci_config_wr8(hdlp, d++, *h++);
15111083Sanish 	else
15121083Sanish 		for (; repcount; repcount--)
15131083Sanish 			pci_config_wr8(hdlp, d, *h++);
15141083Sanish }
15151083Sanish 
15161083Sanish void
15171083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
15181083Sanish {
15191083Sanish 	pci_acc_cfblk_t *cfp;
15201083Sanish 	int reg;
15211083Sanish 
15221083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
15231083Sanish 
15241083Sanish 	reg = (int)(uintptr_t)addr;
15251083Sanish 
15261083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15271083Sanish 
15281083Sanish 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
15291083Sanish 	    cfp->c_funcnum, reg, value);
15301083Sanish }
15311083Sanish 
15321083Sanish void
15331083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
15341083Sanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
15351083Sanish {
15361083Sanish 	uint16_t *h, *d;
15371083Sanish 
15381083Sanish 	h = host_addr;
15391083Sanish 	d = dev_addr;
15401083Sanish 
15411083Sanish 	if (flags == DDI_DEV_AUTOINCR)
15421083Sanish 		for (; repcount; repcount--)
15431083Sanish 			pci_config_wr16(hdlp, d++, *h++);
15441083Sanish 	else
15451083Sanish 		for (; repcount; repcount--)
15461083Sanish 			pci_config_wr16(hdlp, d, *h++);
15471083Sanish }
15481083Sanish 
15491083Sanish void
15501083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
15511083Sanish {
15521083Sanish 	pci_acc_cfblk_t *cfp;
15531083Sanish 	int reg;
15541083Sanish 
15551083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
15561083Sanish 
15571083Sanish 	reg = (int)(uintptr_t)addr;
15581083Sanish 
15591083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15601083Sanish 
15611083Sanish 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
15621083Sanish 	    cfp->c_funcnum, reg, value);
15631083Sanish }
15641083Sanish 
15651083Sanish void
15661083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
15671083Sanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
15681083Sanish {
15691083Sanish 	uint32_t *h, *d;
15701083Sanish 
15711083Sanish 	h = host_addr;
15721083Sanish 	d = dev_addr;
15731083Sanish 
15741083Sanish 	if (flags == DDI_DEV_AUTOINCR)
15751083Sanish 		for (; repcount; repcount--)
15761083Sanish 			pci_config_wr32(hdlp, d++, *h++);
15771083Sanish 	else
15781083Sanish 		for (; repcount; repcount--)
15791083Sanish 			pci_config_wr32(hdlp, d, *h++);
15801083Sanish }
15811083Sanish 
15821083Sanish uint64_t
15831083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
15841083Sanish {
15851083Sanish 	uint32_t lw_val;
15861083Sanish 	uint32_t hi_val;
15871083Sanish 	uint32_t *dp;
15881083Sanish 	uint64_t val;
15891083Sanish 
15901083Sanish 	dp = (uint32_t *)addr;
15911083Sanish 	lw_val = pci_config_rd32(hdlp, dp);
15921083Sanish 	dp++;
15931083Sanish 	hi_val = pci_config_rd32(hdlp, dp);
15941083Sanish 	val = ((uint64_t)hi_val << 32) | lw_val;
15951083Sanish 	return (val);
15961083Sanish }
15971083Sanish 
15981083Sanish void
15991083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
16001083Sanish {
16011083Sanish 	uint32_t lw_val;
16021083Sanish 	uint32_t hi_val;
16031083Sanish 	uint32_t *dp;
16041083Sanish 
16051083Sanish 	dp = (uint32_t *)addr;
16061083Sanish 	lw_val = (uint32_t)(value & 0xffffffff);
16071083Sanish 	hi_val = (uint32_t)(value >> 32);
16081083Sanish 	pci_config_wr32(hdlp, dp, lw_val);
16091083Sanish 	dp++;
16101083Sanish 	pci_config_wr32(hdlp, dp, hi_val);
16111083Sanish }
16121083Sanish 
16131083Sanish void
16141083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
16151083Sanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
16161083Sanish {
16171083Sanish 	if (flags == DDI_DEV_AUTOINCR) {
16181083Sanish 		for (; repcount; repcount--)
16191083Sanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
16201083Sanish 	} else {
16211083Sanish 		for (; repcount; repcount--)
16221083Sanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
16231083Sanish 	}
16241083Sanish }
16251083Sanish 
16261083Sanish void
16271083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
16281083Sanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
16291083Sanish {
16301083Sanish 	if (flags == DDI_DEV_AUTOINCR) {
16311083Sanish 		for (; repcount; repcount--)
16321083Sanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
16331083Sanish 	} else {
16341083Sanish 		for (; repcount; repcount--)
16351083Sanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
16361083Sanish 	}
16371083Sanish }
1638