xref: /onnv-gate/usr/src/uts/i86pc/io/pci/pci_common.c (revision 12825:e35468461453)
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*12825SJimmy.Vetayases@oracle.com  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24881Sjohnny  */
25881Sjohnny 
26881Sjohnny /*
27881Sjohnny  *	File that has code which is common between pci(7d) and npe(7d)
28881Sjohnny  *	It shares the following:
29881Sjohnny  *	- interrupt code
30881Sjohnny  *	- pci_tools ioctl code
31881Sjohnny  *	- name_child code
32881Sjohnny  *	- set_parent_private_data code
33881Sjohnny  */
34881Sjohnny 
35881Sjohnny #include <sys/conf.h>
36881Sjohnny #include <sys/pci.h>
37881Sjohnny #include <sys/sunndi.h>
38916Sschwartz #include <sys/mach_intr.h>
39881Sjohnny #include <sys/pci_intr_lib.h>
40881Sjohnny #include <sys/psm.h>
41881Sjohnny #include <sys/policy.h>
42881Sjohnny #include <sys/sysmacros.h>
43916Sschwartz #include <sys/clock.h>
443446Smrj #include <sys/apic.h>
45881Sjohnny #include <sys/pci_tools.h>
46881Sjohnny #include <io/pci/pci_var.h>
47881Sjohnny #include <io/pci/pci_tools_ext.h>
48881Sjohnny #include <io/pci/pci_common.h>
491083Sanish #include <sys/pci_cfgspace.h>
501083Sanish #include <sys/pci_impl.h>
514160Sjveta #include <sys/pci_cap.h>
52881Sjohnny 
53881Sjohnny /*
54881Sjohnny  * Function prototypes
55881Sjohnny  */
56881Sjohnny static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
57881Sjohnny static int	pci_enable_intr(dev_info_t *, dev_info_t *,
58881Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
59881Sjohnny static void	pci_disable_intr(dev_info_t *, dev_info_t *,
60881Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
6112683SJimmy.Vetayases@oracle.com static int	pci_alloc_intr_fixed(dev_info_t *, dev_info_t *,
6212683SJimmy.Vetayases@oracle.com 		    ddi_intr_handle_impl_t *, void *);
6312683SJimmy.Vetayases@oracle.com static int	pci_free_intr_fixed(dev_info_t *, dev_info_t *,
6412683SJimmy.Vetayases@oracle.com 		    ddi_intr_handle_impl_t *);
65881Sjohnny 
6612683SJimmy.Vetayases@oracle.com /* Extern declarations for PSM module */
67881Sjohnny extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
68881Sjohnny 		    psm_intr_op_t, int *);
6912683SJimmy.Vetayases@oracle.com extern ddi_irm_pool_t *apix_irm_pool_p;
70881Sjohnny 
71881Sjohnny /*
72881Sjohnny  * pci_name_child:
73881Sjohnny  *
74881Sjohnny  *	Assign the address portion of the node name
75881Sjohnny  */
76881Sjohnny int
pci_common_name_child(dev_info_t * child,char * name,int namelen)77881Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
78881Sjohnny {
79881Sjohnny 	int		dev, func, length;
80881Sjohnny 	char		**unit_addr;
81881Sjohnny 	uint_t		n;
82881Sjohnny 	pci_regspec_t	*pci_rp;
83881Sjohnny 
84881Sjohnny 	if (ndi_dev_is_persistent_node(child) == 0) {
85881Sjohnny 		/*
86881Sjohnny 		 * For .conf node, use "unit-address" property
87881Sjohnny 		 */
88881Sjohnny 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
89881Sjohnny 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
90881Sjohnny 		    DDI_PROP_SUCCESS) {
91881Sjohnny 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
92881Sjohnny 			    ddi_get_name(child));
93881Sjohnny 			return (DDI_FAILURE);
94881Sjohnny 		}
95881Sjohnny 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
96881Sjohnny 			cmn_err(CE_WARN, "unit-address property in %s.conf"
97881Sjohnny 			    " not well-formed", ddi_get_name(child));
98881Sjohnny 			ddi_prop_free(unit_addr);
99881Sjohnny 			return (DDI_FAILURE);
100881Sjohnny 		}
101881Sjohnny 		(void) snprintf(name, namelen, "%s", *unit_addr);
102881Sjohnny 		ddi_prop_free(unit_addr);
103881Sjohnny 		return (DDI_SUCCESS);
104881Sjohnny 	}
105881Sjohnny 
106881Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
107881Sjohnny 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
108881Sjohnny 		cmn_err(CE_WARN, "cannot find reg property in %s",
109881Sjohnny 		    ddi_get_name(child));
110881Sjohnny 		return (DDI_FAILURE);
111881Sjohnny 	}
112881Sjohnny 
113881Sjohnny 	/* copy the device identifications */
114881Sjohnny 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
115881Sjohnny 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
116881Sjohnny 
117881Sjohnny 	/*
118881Sjohnny 	 * free the memory allocated by ddi_prop_lookup_int_array
119881Sjohnny 	 */
120881Sjohnny 	ddi_prop_free(pci_rp);
121881Sjohnny 
122881Sjohnny 	if (func != 0) {
123881Sjohnny 		(void) snprintf(name, namelen, "%x,%x", dev, func);
124881Sjohnny 	} else {
125881Sjohnny 		(void) snprintf(name, namelen, "%x", dev);
126881Sjohnny 	}
127881Sjohnny 
128881Sjohnny 	return (DDI_SUCCESS);
129881Sjohnny }
130881Sjohnny 
131881Sjohnny /*
132881Sjohnny  * Interrupt related code:
133881Sjohnny  *
134881Sjohnny  * The following busop is common to npe and pci drivers
135881Sjohnny  *	bus_introp
136881Sjohnny  */
137881Sjohnny 
138881Sjohnny /*
139881Sjohnny  * Create the ddi_parent_private_data for a pseudo child.
140881Sjohnny  */
141881Sjohnny void
pci_common_set_parent_private_data(dev_info_t * dip)142881Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
143881Sjohnny {
144881Sjohnny 	struct ddi_parent_private_data *pdptr;
145881Sjohnny 
146881Sjohnny 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
147881Sjohnny 	    (sizeof (struct ddi_parent_private_data) +
1484397Sschwartz 	    sizeof (struct intrspec)), KM_SLEEP);
149881Sjohnny 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
150881Sjohnny 	pdptr->par_nintr = 1;
151881Sjohnny 	ddi_set_parent_data(dip, pdptr);
152881Sjohnny }
153881Sjohnny 
154881Sjohnny /*
155881Sjohnny  * pci_get_priority:
156881Sjohnny  *	Figure out the priority of the device
157881Sjohnny  */
158881Sjohnny static int
pci_get_priority(dev_info_t * dip,ddi_intr_handle_impl_t * hdlp,int * pri)159881Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
160881Sjohnny {
161881Sjohnny 	struct intrspec *ispec;
162881Sjohnny 
163881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
164881Sjohnny 	    (void *)dip, (void *)hdlp));
165881Sjohnny 
166881Sjohnny 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
167881Sjohnny 	    hdlp->ih_inum)) == NULL) {
168881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
1698535Sevan.yan@sun.com 			*pri = pci_class_to_pil(dip);
170881Sjohnny 			pci_common_set_parent_private_data(hdlp->ih_dip);
171881Sjohnny 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
172881Sjohnny 			    hdlp->ih_inum);
173881Sjohnny 			return (DDI_SUCCESS);
174881Sjohnny 		}
175881Sjohnny 		return (DDI_FAILURE);
176881Sjohnny 	}
177881Sjohnny 
178881Sjohnny 	*pri = ispec->intrspec_pri;
179881Sjohnny 	return (DDI_SUCCESS);
180881Sjohnny }
181881Sjohnny 
182881Sjohnny 
183881Sjohnny 
18410187SKrishna.Elango@Sun.COM static int pcieb_intr_pri_counter = 0;
185881Sjohnny 
186881Sjohnny /*
187881Sjohnny  * pci_common_intr_ops: bus_intr_op() function for interrupt support
188881Sjohnny  */
189881Sjohnny int
pci_common_intr_ops(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)190881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
191881Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
192881Sjohnny {
193881Sjohnny 	int			priority = 0;
194881Sjohnny 	int			psm_status = 0;
195881Sjohnny 	int			pci_status = 0;
196881Sjohnny 	int			pci_rval, psm_rval = PSM_FAILURE;
197881Sjohnny 	int			types = 0;
198881Sjohnny 	int			pciepci = 0;
1991542Sjohnny 	int			i, j, count;
2004160Sjveta 	int			rv;
201881Sjohnny 	int			behavior;
2021997Sanish 	int			cap_ptr;
2034160Sjveta 	uint16_t		msi_cap_base, msix_cap_base, cap_ctrl;
2044160Sjveta 	char			*prop;
205881Sjohnny 	ddi_intrspec_t		isp;
206881Sjohnny 	struct intrspec		*ispec;
207881Sjohnny 	ddi_intr_handle_impl_t	tmp_hdl;
208881Sjohnny 	ddi_intr_msix_t		*msix_p;
2091087Sschwartz 	ihdl_plat_t		*ihdl_plat_datap;
2101542Sjohnny 	ddi_intr_handle_t	*h_array;
2111997Sanish 	ddi_acc_handle_t	handle;
21212683SJimmy.Vetayases@oracle.com 	apic_get_intr_t		intrinfo;
213881Sjohnny 
214881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT,
215881Sjohnny 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
216881Sjohnny 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
217881Sjohnny 
218881Sjohnny 	/* Process the request */
219881Sjohnny 	switch (intr_op) {
220881Sjohnny 	case DDI_INTROP_SUPPORTED_TYPES:
2214160Sjveta 		/*
2224160Sjveta 		 * First we determine the interrupt types supported by the
2234160Sjveta 		 * device itself, then we filter them through what the OS
2244160Sjveta 		 * and system supports.  We determine system-level
2254160Sjveta 		 * interrupt type support for anything other than fixed intrs
2264160Sjveta 		 * through the psm_intr_ops vector
2274160Sjveta 		 */
2284160Sjveta 		rv = DDI_FAILURE;
2294160Sjveta 
230881Sjohnny 		/* Fixed supported by default */
2314160Sjveta 		types = DDI_INTR_TYPE_FIXED;
2324160Sjveta 
2334160Sjveta 		if (psm_intr_ops == NULL) {
2344160Sjveta 			*(int *)result = types;
2354160Sjveta 			return (DDI_SUCCESS);
2364160Sjveta 		}
2374160Sjveta 		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
2384160Sjveta 			return (DDI_FAILURE);
239881Sjohnny 
2404160Sjveta 		/* Sanity test cap control values if found */
2414160Sjveta 
2424160Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
2434160Sjveta 		    DDI_SUCCESS) {
2444160Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
2454160Sjveta 			    PCI_MSI_CTRL);
2464160Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
2474160Sjveta 				goto SUPPORTED_TYPES_OUT;
2484160Sjveta 
2494160Sjveta 			types |= DDI_INTR_TYPE_MSI;
2504160Sjveta 		}
2514160Sjveta 
2524160Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
2534160Sjveta 		    DDI_SUCCESS) {
2544160Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
2554160Sjveta 			    PCI_MSIX_CTRL);
2564160Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
2574160Sjveta 				goto SUPPORTED_TYPES_OUT;
258881Sjohnny 
2594160Sjveta 			types |= DDI_INTR_TYPE_MSIX;
2604160Sjveta 		}
2614160Sjveta 
2624160Sjveta 		/*
2634160Sjveta 		 * Filter device-level types through system-level support
2644160Sjveta 		 */
2654160Sjveta 		tmp_hdl.ih_type = types;
2664160Sjveta 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
2674160Sjveta 		    &types) != PSM_SUCCESS)
2684160Sjveta 			goto SUPPORTED_TYPES_OUT;
2694160Sjveta 
2704160Sjveta 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
2714160Sjveta 		    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
27212683SJimmy.Vetayases@oracle.com 		    types));
273881Sjohnny 
2744160Sjveta 		/*
2754160Sjveta 		 * Export any MSI/MSI-X cap locations via properties
2764160Sjveta 		 */
2774160Sjveta 		if (types & DDI_INTR_TYPE_MSI) {
2784160Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
2794160Sjveta 			    "pci-msi-capid-pointer", (int)msi_cap_base) !=
2804160Sjveta 			    DDI_PROP_SUCCESS)
2814160Sjveta 				goto SUPPORTED_TYPES_OUT;
282881Sjohnny 		}
2834160Sjveta 		if (types & DDI_INTR_TYPE_MSIX) {
2844160Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
2854160Sjveta 			    "pci-msix-capid-pointer", (int)msix_cap_base) !=
2864160Sjveta 			    DDI_PROP_SUCCESS)
2874160Sjveta 				goto SUPPORTED_TYPES_OUT;
2884160Sjveta 		}
2894160Sjveta 
2904160Sjveta 		rv = DDI_SUCCESS;
2914160Sjveta 
2924160Sjveta SUPPORTED_TYPES_OUT:
2934160Sjveta 		*(int *)result = types;
2944160Sjveta 		pci_config_teardown(&handle);
2954160Sjveta 		return (rv);
2964160Sjveta 
2972580Sanish 	case DDI_INTROP_NAVAIL:
298881Sjohnny 	case DDI_INTROP_NINTRS:
2992580Sanish 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
3002580Sanish 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
3012580Sanish 			    result) != DDI_SUCCESS)
3022580Sanish 				return (DDI_FAILURE);
3032580Sanish 		} else {
3042580Sanish 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
3052580Sanish 			if (*(int *)result == 0)
3062580Sanish 				return (DDI_FAILURE);
3072580Sanish 		}
308881Sjohnny 		break;
309881Sjohnny 	case DDI_INTROP_ALLOC:
31012683SJimmy.Vetayases@oracle.com 
31112683SJimmy.Vetayases@oracle.com 		/*
31212683SJimmy.Vetayases@oracle.com 		 * FIXED type
31312683SJimmy.Vetayases@oracle.com 		 */
31412683SJimmy.Vetayases@oracle.com 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
31512683SJimmy.Vetayases@oracle.com 			return (pci_alloc_intr_fixed(pdip, rdip, hdlp, result));
316881Sjohnny 		/*
317881Sjohnny 		 * MSI or MSIX (figure out number of vectors available)
318881Sjohnny 		 */
319881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
320881Sjohnny 		    (psm_intr_ops != NULL) &&
321881Sjohnny 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
322881Sjohnny 			/*
32310187SKrishna.Elango@Sun.COM 			 * Following check is a special case for 'pcieb'.
324881Sjohnny 			 * This makes sure vectors with the right priority
32510187SKrishna.Elango@Sun.COM 			 * are allocated for pcieb during ALLOC time.
326881Sjohnny 			 */
32710187SKrishna.Elango@Sun.COM 			if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) {
328881Sjohnny 				hdlp->ih_pri =
32910187SKrishna.Elango@Sun.COM 				    (pcieb_intr_pri_counter % 2) ? 4 : 7;
330881Sjohnny 				pciepci = 1;
331881Sjohnny 			} else
332881Sjohnny 				hdlp->ih_pri = priority;
3331717Swesolows 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
3341997Sanish 
3351997Sanish 			/*
3361997Sanish 			 * Cache in the config handle and cap_ptr
3371997Sanish 			 */
3381997Sanish 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
3391997Sanish 				if (pci_config_setup(rdip, &handle) !=
3401997Sanish 				    DDI_SUCCESS)
3411997Sanish 					return (DDI_FAILURE);
3421997Sanish 				i_ddi_set_pci_config_handle(rdip, handle);
3431997Sanish 			}
3441997Sanish 
3454160Sjveta 			prop = NULL;
3464160Sjveta 			cap_ptr = 0;
3474160Sjveta 			if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
3484160Sjveta 				prop = "pci-msi-capid-pointer";
3494160Sjveta 			else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
3504160Sjveta 				prop = "pci-msix-capid-pointer";
3511997Sanish 
3524160Sjveta 			/*
3534160Sjveta 			 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
3544160Sjveta 			 * for MSI(X) before allocation
3554160Sjveta 			 */
3564160Sjveta 			if (prop != NULL) {
3571997Sanish 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
3584160Sjveta 				    DDI_PROP_DONTPASS, prop, 0);
3594160Sjveta 				if (cap_ptr == 0) {
3604160Sjveta 					DDI_INTR_NEXDBG((CE_CONT,
3614160Sjveta 					    "pci_common_intr_ops: rdip: 0x%p "
3624160Sjveta 					    "attempted MSI(X) alloc without "
3634160Sjveta 					    "cap property\n", (void *)rdip));
3644160Sjveta 					return (DDI_FAILURE);
3654160Sjveta 				}
3661997Sanish 			}
3674160Sjveta 			i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
3681997Sanish 
3694160Sjveta 			/*
3704160Sjveta 			 * Allocate interrupt vectors
3714160Sjveta 			 */
372881Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
373881Sjohnny 			    PSM_INTR_OP_ALLOC_VECTORS, result);
374881Sjohnny 
3753112Sanish 			if (*(int *)result == 0)
3763112Sanish 				return (DDI_INTR_NOTFOUND);
3773112Sanish 
378881Sjohnny 			/* verify behavior flag and take appropriate action */
379881Sjohnny 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
380881Sjohnny 			    (*(int *)result < hdlp->ih_scratch1)) {
381881Sjohnny 				DDI_INTR_NEXDBG((CE_CONT,
382881Sjohnny 				    "pci_common_intr_ops: behavior %x, "
383881Sjohnny 				    "couldn't get enough intrs\n", behavior));
384881Sjohnny 				hdlp->ih_scratch1 = *(int *)result;
385881Sjohnny 				(void) (*psm_intr_ops)(rdip, hdlp,
386881Sjohnny 				    PSM_INTR_OP_FREE_VECTORS, NULL);
387881Sjohnny 				return (DDI_EAGAIN);
388881Sjohnny 			}
389881Sjohnny 
390881Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
391881Sjohnny 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
392881Sjohnny 					msix_p = pci_msix_init(hdlp->ih_dip);
39310647SLipeng.Sang@Sun.COM 					if (msix_p) {
394881Sjohnny 						i_ddi_set_msix(hdlp->ih_dip,
395881Sjohnny 						    msix_p);
39610647SLipeng.Sang@Sun.COM 					} else {
39710647SLipeng.Sang@Sun.COM 						DDI_INTR_NEXDBG((CE_CONT,
39810647SLipeng.Sang@Sun.COM 						    "pci_common_intr_ops: MSI-X"
39910647SLipeng.Sang@Sun.COM 						    "table initilization failed"
40010647SLipeng.Sang@Sun.COM 						    ", rdip 0x%p inum 0x%x\n",
40110647SLipeng.Sang@Sun.COM 						    (void *)rdip,
40210647SLipeng.Sang@Sun.COM 						    hdlp->ih_inum));
40310647SLipeng.Sang@Sun.COM 
40410647SLipeng.Sang@Sun.COM 						(void) (*psm_intr_ops)(rdip,
40510647SLipeng.Sang@Sun.COM 						    hdlp,
40610647SLipeng.Sang@Sun.COM 						    PSM_INTR_OP_FREE_VECTORS,
40710647SLipeng.Sang@Sun.COM 						    NULL);
40810647SLipeng.Sang@Sun.COM 
40910647SLipeng.Sang@Sun.COM 						return (DDI_FAILURE);
41010647SLipeng.Sang@Sun.COM 					}
411881Sjohnny 				}
412881Sjohnny 			}
413881Sjohnny 
414881Sjohnny 			if (pciepci) {
415881Sjohnny 				/* update priority in ispec */
416881Sjohnny 				isp = pci_intx_get_ispec(pdip, rdip,
4174397Sschwartz 				    (int)hdlp->ih_inum);
418881Sjohnny 				ispec = (struct intrspec *)isp;
419881Sjohnny 				if (ispec)
420881Sjohnny 					ispec->intrspec_pri = hdlp->ih_pri;
42110187SKrishna.Elango@Sun.COM 				++pcieb_intr_pri_counter;
422881Sjohnny 			}
423881Sjohnny 
424881Sjohnny 		} else
425881Sjohnny 			return (DDI_FAILURE);
426881Sjohnny 		break;
427881Sjohnny 	case DDI_INTROP_FREE:
428881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
429881Sjohnny 		    (psm_intr_ops != NULL)) {
4302018Sanish 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
4312018Sanish 			    0) {
4321997Sanish 				if (handle = i_ddi_get_pci_config_handle(
4331997Sanish 				    rdip)) {
4341997Sanish 					(void) pci_config_teardown(&handle);
4351997Sanish 					i_ddi_set_pci_config_handle(rdip, NULL);
4361997Sanish 				}
4371997Sanish 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
4381997Sanish 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
4391997Sanish 			}
4401997Sanish 
441881Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
442881Sjohnny 			    PSM_INTR_OP_FREE_VECTORS, NULL);
443881Sjohnny 
444881Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
445881Sjohnny 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
446881Sjohnny 				if (msix_p &&
4472018Sanish 				    (i_ddi_intr_get_current_nintrs(
4484397Sschwartz 				    hdlp->ih_dip) - 1) == 0) {
449881Sjohnny 					pci_msix_fini(msix_p);
450881Sjohnny 					i_ddi_set_msix(hdlp->ih_dip, NULL);
451881Sjohnny 				}
452881Sjohnny 			}
45312683SJimmy.Vetayases@oracle.com 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
45412683SJimmy.Vetayases@oracle.com 			return (pci_free_intr_fixed(pdip, rdip, hdlp));
45512683SJimmy.Vetayases@oracle.com 		} else
45612683SJimmy.Vetayases@oracle.com 			return (DDI_FAILURE);
457881Sjohnny 		break;
458881Sjohnny 	case DDI_INTROP_GETPRI:
459881Sjohnny 		/* Get the priority */
460881Sjohnny 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
461881Sjohnny 			return (DDI_FAILURE);
462881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
463881Sjohnny 		    "priority = 0x%x\n", priority));
464881Sjohnny 		*(int *)result = priority;
465881Sjohnny 		break;
466881Sjohnny 	case DDI_INTROP_SETPRI:
467881Sjohnny 		/* Validate the interrupt priority passed */
468881Sjohnny 		if (*(int *)result > LOCK_LEVEL)
469881Sjohnny 			return (DDI_FAILURE);
470881Sjohnny 
471881Sjohnny 		/* Ensure that PSM is all initialized */
472881Sjohnny 		if (psm_intr_ops == NULL)
473881Sjohnny 			return (DDI_FAILURE);
474881Sjohnny 
47510190SSophia.Li@Sun.COM 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
47610190SSophia.Li@Sun.COM 		ispec = (struct intrspec *)isp;
47710190SSophia.Li@Sun.COM 		if (ispec == NULL)
47810190SSophia.Li@Sun.COM 			return (DDI_FAILURE);
47910190SSophia.Li@Sun.COM 
48010190SSophia.Li@Sun.COM 		/* For fixed interrupts */
48110190SSophia.Li@Sun.COM 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
48210190SSophia.Li@Sun.COM 			/* if interrupt is shared, return failure */
48310190SSophia.Li@Sun.COM 			((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
48410190SSophia.Li@Sun.COM 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
48510190SSophia.Li@Sun.COM 			    PSM_INTR_OP_GET_SHARED, &psm_status);
48610190SSophia.Li@Sun.COM 			/*
48710190SSophia.Li@Sun.COM 			 * For fixed interrupts, the irq may not have been
48810190SSophia.Li@Sun.COM 			 * allocated when SET_PRI is called, and the above
48910190SSophia.Li@Sun.COM 			 * GET_SHARED op may return PSM_FAILURE. This is not
49010190SSophia.Li@Sun.COM 			 * a real error and is ignored below.
49110190SSophia.Li@Sun.COM 			 */
49210190SSophia.Li@Sun.COM 			if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) {
49310190SSophia.Li@Sun.COM 				DDI_INTR_NEXDBG((CE_CONT,
49410190SSophia.Li@Sun.COM 				    "pci_common_intr_ops: "
49510190SSophia.Li@Sun.COM 				    "dip 0x%p cannot setpri, psm_rval=%d,"
49610190SSophia.Li@Sun.COM 				    "psm_status=%d\n", (void *)rdip, psm_rval,
49710190SSophia.Li@Sun.COM 				    psm_status));
49810190SSophia.Li@Sun.COM 				return (DDI_FAILURE);
49910190SSophia.Li@Sun.COM 			}
50010190SSophia.Li@Sun.COM 		}
50110190SSophia.Li@Sun.COM 
502881Sjohnny 		/* Change the priority */
503881Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
504881Sjohnny 		    PSM_FAILURE)
505881Sjohnny 			return (DDI_FAILURE);
506881Sjohnny 
507881Sjohnny 		/* update ispec */
50810190SSophia.Li@Sun.COM 		ispec->intrspec_pri = *(int *)result;
509881Sjohnny 		break;
510881Sjohnny 	case DDI_INTROP_ADDISR:
511881Sjohnny 		/* update ispec */
512881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
513881Sjohnny 		ispec = (struct intrspec *)isp;
5141087Sschwartz 		if (ispec) {
515881Sjohnny 			ispec->intrspec_func = hdlp->ih_cb_func;
5161087Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
5171087Sschwartz 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
5181087Sschwartz 		}
519881Sjohnny 		break;
520881Sjohnny 	case DDI_INTROP_REMISR:
521881Sjohnny 		/* Get the interrupt structure pointer */
522881Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
523881Sjohnny 		ispec = (struct intrspec *)isp;
5241087Sschwartz 		if (ispec) {
525881Sjohnny 			ispec->intrspec_func = (uint_t (*)()) 0;
5261087Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
5271087Sschwartz 			if (ihdl_plat_datap->ip_ksp != NULL)
5281087Sschwartz 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
5291087Sschwartz 		}
530881Sjohnny 		break;
531881Sjohnny 	case DDI_INTROP_GETCAP:
532881Sjohnny 		/*
533881Sjohnny 		 * First check the config space and/or
534881Sjohnny 		 * MSI capability register(s)
535881Sjohnny 		 */
536881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
537881Sjohnny 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
538881Sjohnny 			    &pci_status);
539881Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
540881Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
541881Sjohnny 
54212683SJimmy.Vetayases@oracle.com 		/* next check with PSM module */
543881Sjohnny 		if (psm_intr_ops != NULL)
544881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
545881Sjohnny 			    PSM_INTR_OP_GET_CAP, &psm_status);
546881Sjohnny 
547881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
548881Sjohnny 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
549881Sjohnny 		    psm_rval, psm_status, pci_rval, pci_status));
550881Sjohnny 
551881Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
552881Sjohnny 			*(int *)result = 0;
553881Sjohnny 			return (DDI_FAILURE);
554881Sjohnny 		}
555881Sjohnny 
556881Sjohnny 		if (psm_rval == PSM_SUCCESS)
557881Sjohnny 			*(int *)result = psm_status;
558881Sjohnny 
559881Sjohnny 		if (pci_rval == DDI_SUCCESS)
560881Sjohnny 			*(int *)result |= pci_status;
561881Sjohnny 
562881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
563881Sjohnny 		    *(int *)result));
564881Sjohnny 		break;
565881Sjohnny 	case DDI_INTROP_SETCAP:
566881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
567881Sjohnny 		    "SETCAP cap=0x%x\n", *(int *)result));
568881Sjohnny 		if (psm_intr_ops == NULL)
569881Sjohnny 			return (DDI_FAILURE);
570881Sjohnny 
571881Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
572881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
573881Sjohnny 			    " returned failure\n"));
574881Sjohnny 			return (DDI_FAILURE);
575881Sjohnny 		}
576881Sjohnny 		break;
577881Sjohnny 	case DDI_INTROP_ENABLE:
578881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
579881Sjohnny 		if (psm_intr_ops == NULL)
580881Sjohnny 			return (DDI_FAILURE);
581881Sjohnny 
582881Sjohnny 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
583881Sjohnny 		    DDI_SUCCESS)
584881Sjohnny 			return (DDI_FAILURE);
585881Sjohnny 
586881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
587881Sjohnny 		    "vector=0x%x\n", hdlp->ih_vector));
588881Sjohnny 		break;
589881Sjohnny 	case DDI_INTROP_DISABLE:
590881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
591881Sjohnny 		if (psm_intr_ops == NULL)
592881Sjohnny 			return (DDI_FAILURE);
593881Sjohnny 
594881Sjohnny 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
595881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
596881Sjohnny 		    "vector = %x\n", hdlp->ih_vector));
597881Sjohnny 		break;
598881Sjohnny 	case DDI_INTROP_BLOCKENABLE:
599881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
600881Sjohnny 		    "BLOCKENABLE\n"));
601881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
602881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
603881Sjohnny 			return (DDI_FAILURE);
604881Sjohnny 		}
605881Sjohnny 
606881Sjohnny 		/* Check if psm_intr_ops is NULL? */
607881Sjohnny 		if (psm_intr_ops == NULL)
608881Sjohnny 			return (DDI_FAILURE);
609881Sjohnny 
6101542Sjohnny 		count = hdlp->ih_scratch1;
6111542Sjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
6121542Sjohnny 		for (i = 0; i < count; i++) {
6131542Sjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
614881Sjohnny 			if (pci_enable_intr(pdip, rdip, hdlp,
6151542Sjohnny 			    hdlp->ih_inum) != DDI_SUCCESS) {
616881Sjohnny 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
617881Sjohnny 				    "pci_enable_intr failed for %d\n", i));
6181542Sjohnny 				for (j = 0; j < i; j++) {
6194397Sschwartz 					hdlp = (ddi_intr_handle_impl_t *)
6204397Sschwartz 					    h_array[j];
6214397Sschwartz 					pci_disable_intr(pdip, rdip, hdlp,
6221542Sjohnny 					    hdlp->ih_inum);
6231542Sjohnny 				}
624881Sjohnny 				return (DDI_FAILURE);
625881Sjohnny 			}
626881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
6271542Sjohnny 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
628881Sjohnny 		}
629881Sjohnny 		break;
630881Sjohnny 	case DDI_INTROP_BLOCKDISABLE:
631881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
632881Sjohnny 		    "BLOCKDISABLE\n"));
633881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
634881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
635881Sjohnny 			return (DDI_FAILURE);
636881Sjohnny 		}
637881Sjohnny 
638881Sjohnny 		/* Check if psm_intr_ops is present */
639881Sjohnny 		if (psm_intr_ops == NULL)
640881Sjohnny 			return (DDI_FAILURE);
641881Sjohnny 
6421542Sjohnny 		count = hdlp->ih_scratch1;
6431542Sjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
6441542Sjohnny 		for (i = 0; i < count; i++) {
6451542Sjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
6461542Sjohnny 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
647881Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
6481542Sjohnny 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
649881Sjohnny 		}
650881Sjohnny 		break;
651881Sjohnny 	case DDI_INTROP_SETMASK:
652881Sjohnny 	case DDI_INTROP_CLRMASK:
653881Sjohnny 		/*
654881Sjohnny 		 * First handle in the config space
655881Sjohnny 		 */
656881Sjohnny 		if (intr_op == DDI_INTROP_SETMASK) {
657881Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
658881Sjohnny 				pci_status = pci_msi_set_mask(rdip,
659881Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
660881Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
661881Sjohnny 				pci_status = pci_intx_set_mask(rdip);
662881Sjohnny 		} else {
663881Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
664881Sjohnny 				pci_status = pci_msi_clr_mask(rdip,
665881Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
666881Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
667881Sjohnny 				pci_status = pci_intx_clr_mask(rdip);
668881Sjohnny 		}
669881Sjohnny 
67012683SJimmy.Vetayases@oracle.com 		/* For MSI/X; no need to check with PSM module */
671881Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
672881Sjohnny 			return (pci_status);
673881Sjohnny 
674881Sjohnny 		/* For fixed interrupts only: handle config space first */
675881Sjohnny 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
676881Sjohnny 		    pci_status == DDI_SUCCESS)
677881Sjohnny 			break;
678881Sjohnny 
67912683SJimmy.Vetayases@oracle.com 		/* For fixed interrupts only: confer with PSM module next */
680881Sjohnny 		if (psm_intr_ops != NULL) {
681881Sjohnny 			/* If interrupt is shared; do nothing */
682881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
683881Sjohnny 			    PSM_INTR_OP_GET_SHARED, &psm_status);
684881Sjohnny 
685881Sjohnny 			if (psm_rval == PSM_FAILURE || psm_status == 1)
686881Sjohnny 				return (pci_status);
687881Sjohnny 
68812683SJimmy.Vetayases@oracle.com 			/* Now, PSM module should try to set/clear the mask */
689881Sjohnny 			if (intr_op == DDI_INTROP_SETMASK)
690881Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
691881Sjohnny 				    PSM_INTR_OP_SET_MASK, NULL);
692881Sjohnny 			else
693881Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
694881Sjohnny 				    PSM_INTR_OP_CLEAR_MASK, NULL);
695881Sjohnny 		}
696881Sjohnny 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
697881Sjohnny 	case DDI_INTROP_GETPENDING:
698881Sjohnny 		/*
699881Sjohnny 		 * First check the config space and/or
700881Sjohnny 		 * MSI capability register(s)
701881Sjohnny 		 */
702881Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
703881Sjohnny 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
704881Sjohnny 			    hdlp->ih_inum, &pci_status);
705881Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
706881Sjohnny 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
707881Sjohnny 
70812683SJimmy.Vetayases@oracle.com 		/* On failure; next try with PSM module */
709881Sjohnny 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
710881Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
711881Sjohnny 			    PSM_INTR_OP_GET_PENDING, &psm_status);
712881Sjohnny 
713881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
714881Sjohnny 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
715881Sjohnny 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
716881Sjohnny 		    pci_status));
717881Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
718881Sjohnny 			*(int *)result = 0;
719881Sjohnny 			return (DDI_FAILURE);
720881Sjohnny 		}
721881Sjohnny 
722881Sjohnny 		if (psm_rval != PSM_FAILURE)
723881Sjohnny 			*(int *)result = psm_status;
724881Sjohnny 		else if (pci_rval != DDI_FAILURE)
725881Sjohnny 			*(int *)result = pci_status;
726881Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
727881Sjohnny 		    *(int *)result));
728881Sjohnny 		break;
72910053SEvan.Yan@Sun.COM 	case DDI_INTROP_GETTARGET:
73010053SEvan.Yan@Sun.COM 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n"));
73110053SEvan.Yan@Sun.COM 
73212683SJimmy.Vetayases@oracle.com 		bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
73312683SJimmy.Vetayases@oracle.com 		tmp_hdl.ih_private = (void *)&intrinfo;
73412683SJimmy.Vetayases@oracle.com 		intrinfo.avgi_req_flags = PSMGI_INTRBY_DEFAULT;
73512683SJimmy.Vetayases@oracle.com 		intrinfo.avgi_req_flags |= PSMGI_REQ_CPUID;
73612683SJimmy.Vetayases@oracle.com 
73712683SJimmy.Vetayases@oracle.com 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_GET_INTR,
73812683SJimmy.Vetayases@oracle.com 		    NULL) == PSM_FAILURE)
73910053SEvan.Yan@Sun.COM 			return (DDI_FAILURE);
74012683SJimmy.Vetayases@oracle.com 
74112683SJimmy.Vetayases@oracle.com 		*(int *)result = intrinfo.avgi_cpu_id;
74210053SEvan.Yan@Sun.COM 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET "
74312683SJimmy.Vetayases@oracle.com 		    "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector,
74412683SJimmy.Vetayases@oracle.com 		    *(int *)result));
74510053SEvan.Yan@Sun.COM 		break;
74610053SEvan.Yan@Sun.COM 	case DDI_INTROP_SETTARGET:
74710053SEvan.Yan@Sun.COM 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n"));
74810053SEvan.Yan@Sun.COM 
74912683SJimmy.Vetayases@oracle.com 		bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
75010053SEvan.Yan@Sun.COM 		tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result;
75112683SJimmy.Vetayases@oracle.com 		tmp_hdl.ih_flags = PSMGI_INTRBY_DEFAULT;
75212683SJimmy.Vetayases@oracle.com 
75312683SJimmy.Vetayases@oracle.com 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU,
75412683SJimmy.Vetayases@oracle.com 		    &psm_status) == PSM_FAILURE)
75512683SJimmy.Vetayases@oracle.com 			return (DDI_FAILURE);
75610053SEvan.Yan@Sun.COM 
75712683SJimmy.Vetayases@oracle.com 		hdlp->ih_vector = tmp_hdl.ih_vector;
75812683SJimmy.Vetayases@oracle.com 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET "
75912683SJimmy.Vetayases@oracle.com 		    "vector = 0x%x\n", hdlp->ih_vector));
76010053SEvan.Yan@Sun.COM 		break;
76112683SJimmy.Vetayases@oracle.com 	case DDI_INTROP_GETPOOL:
76212683SJimmy.Vetayases@oracle.com 		/*
76312683SJimmy.Vetayases@oracle.com 		 * For MSI/X interrupts use global IRM pool if available.
76412683SJimmy.Vetayases@oracle.com 		 */
76512683SJimmy.Vetayases@oracle.com 		if (apix_irm_pool_p && DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
76612683SJimmy.Vetayases@oracle.com 			*(ddi_irm_pool_t **)result = apix_irm_pool_p;
76712683SJimmy.Vetayases@oracle.com 			return (DDI_SUCCESS);
76812683SJimmy.Vetayases@oracle.com 		}
76912683SJimmy.Vetayases@oracle.com 		return (DDI_ENOTSUP);
770881Sjohnny 	default:
771881Sjohnny 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
772881Sjohnny 	}
773881Sjohnny 
774881Sjohnny 	return (DDI_SUCCESS);
775881Sjohnny }
776881Sjohnny 
77712683SJimmy.Vetayases@oracle.com /*
77812683SJimmy.Vetayases@oracle.com  * Allocate a vector for FIXED type interrupt.
77912683SJimmy.Vetayases@oracle.com  */
78012683SJimmy.Vetayases@oracle.com int
pci_alloc_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,void * result)78112683SJimmy.Vetayases@oracle.com pci_alloc_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
78212683SJimmy.Vetayases@oracle.com     ddi_intr_handle_impl_t *hdlp, void *result)
78312683SJimmy.Vetayases@oracle.com {
78412683SJimmy.Vetayases@oracle.com 	struct intrspec		*ispec;
78512683SJimmy.Vetayases@oracle.com 	ddi_intr_handle_impl_t	info_hdl;
78612683SJimmy.Vetayases@oracle.com 	int			ret;
78712683SJimmy.Vetayases@oracle.com 	int			free_phdl = 0;
78812683SJimmy.Vetayases@oracle.com 	int			pci_rval;
78912683SJimmy.Vetayases@oracle.com 	int			pci_status = 0;
79012683SJimmy.Vetayases@oracle.com 	apic_get_type_t		type_info;
79112683SJimmy.Vetayases@oracle.com 
79212683SJimmy.Vetayases@oracle.com 	if (psm_intr_ops == NULL)
79312683SJimmy.Vetayases@oracle.com 		return (DDI_FAILURE);
79412683SJimmy.Vetayases@oracle.com 
79512683SJimmy.Vetayases@oracle.com 	/* Figure out if this device supports MASKING */
79612683SJimmy.Vetayases@oracle.com 	pci_rval = pci_intx_get_cap(rdip, &pci_status);
79712683SJimmy.Vetayases@oracle.com 	if (pci_rval == DDI_SUCCESS && pci_status)
79812683SJimmy.Vetayases@oracle.com 		hdlp->ih_cap |= pci_status;
79912683SJimmy.Vetayases@oracle.com 
80012683SJimmy.Vetayases@oracle.com 	/*
80112683SJimmy.Vetayases@oracle.com 	 * If the PSM module is "APIX" then pass the request for
80212683SJimmy.Vetayases@oracle.com 	 * allocating the vector now.
80312683SJimmy.Vetayases@oracle.com 	 */
80412683SJimmy.Vetayases@oracle.com 	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
80512683SJimmy.Vetayases@oracle.com 	info_hdl.ih_private = &type_info;
80612683SJimmy.Vetayases@oracle.com 	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
80712683SJimmy.Vetayases@oracle.com 	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
80812683SJimmy.Vetayases@oracle.com 		ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
80912683SJimmy.Vetayases@oracle.com 		    (int)hdlp->ih_inum);
81012683SJimmy.Vetayases@oracle.com 		if (ispec == NULL)
81112683SJimmy.Vetayases@oracle.com 			return (DDI_FAILURE);
81212683SJimmy.Vetayases@oracle.com 		if (hdlp->ih_private == NULL) { /* allocate phdl structure */
81312683SJimmy.Vetayases@oracle.com 			free_phdl = 1;
81412683SJimmy.Vetayases@oracle.com 			i_ddi_alloc_intr_phdl(hdlp);
81512683SJimmy.Vetayases@oracle.com 		}
81612683SJimmy.Vetayases@oracle.com 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
81712683SJimmy.Vetayases@oracle.com 		ret = (*psm_intr_ops)(rdip, hdlp,
81812683SJimmy.Vetayases@oracle.com 		    PSM_INTR_OP_ALLOC_VECTORS, result);
81912683SJimmy.Vetayases@oracle.com 		if (free_phdl) { /* free up the phdl structure */
82012683SJimmy.Vetayases@oracle.com 			free_phdl = 0;
82112683SJimmy.Vetayases@oracle.com 			i_ddi_free_intr_phdl(hdlp);
82212683SJimmy.Vetayases@oracle.com 			hdlp->ih_private = NULL;
82312683SJimmy.Vetayases@oracle.com 		}
82412683SJimmy.Vetayases@oracle.com 	} else {
82512683SJimmy.Vetayases@oracle.com 		/*
82612683SJimmy.Vetayases@oracle.com 		 * No APIX module; fall back to the old scheme where the
82712683SJimmy.Vetayases@oracle.com 		 * interrupt vector is allocated during ddi_enable_intr() call.
82812683SJimmy.Vetayases@oracle.com 		 */
82912683SJimmy.Vetayases@oracle.com 		*(int *)result = 1;
83012683SJimmy.Vetayases@oracle.com 		ret = DDI_SUCCESS;
83112683SJimmy.Vetayases@oracle.com 	}
83212683SJimmy.Vetayases@oracle.com 
83312683SJimmy.Vetayases@oracle.com 	return (ret);
83412683SJimmy.Vetayases@oracle.com }
83512683SJimmy.Vetayases@oracle.com 
83612683SJimmy.Vetayases@oracle.com /*
83712683SJimmy.Vetayases@oracle.com  * Free up the vector for FIXED (legacy) type interrupt.
83812683SJimmy.Vetayases@oracle.com  */
83912683SJimmy.Vetayases@oracle.com static int
pci_free_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)84012683SJimmy.Vetayases@oracle.com pci_free_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
84112683SJimmy.Vetayases@oracle.com     ddi_intr_handle_impl_t *hdlp)
84212683SJimmy.Vetayases@oracle.com {
84312683SJimmy.Vetayases@oracle.com 	struct intrspec			*ispec;
84412683SJimmy.Vetayases@oracle.com 	ddi_intr_handle_impl_t		info_hdl;
84512683SJimmy.Vetayases@oracle.com 	int				ret;
84612683SJimmy.Vetayases@oracle.com 	apic_get_type_t			type_info;
84712683SJimmy.Vetayases@oracle.com 
84812683SJimmy.Vetayases@oracle.com 	if (psm_intr_ops == NULL)
84912683SJimmy.Vetayases@oracle.com 		return (DDI_FAILURE);
85012683SJimmy.Vetayases@oracle.com 
85112683SJimmy.Vetayases@oracle.com 	/*
85212683SJimmy.Vetayases@oracle.com 	 * If the PSM module is "APIX" then pass the request to it
85312683SJimmy.Vetayases@oracle.com 	 * to free up the vector now.
85412683SJimmy.Vetayases@oracle.com 	 */
85512683SJimmy.Vetayases@oracle.com 	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
85612683SJimmy.Vetayases@oracle.com 	info_hdl.ih_private = &type_info;
85712683SJimmy.Vetayases@oracle.com 	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
85812683SJimmy.Vetayases@oracle.com 	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
85912683SJimmy.Vetayases@oracle.com 		ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
86012683SJimmy.Vetayases@oracle.com 		    (int)hdlp->ih_inum);
86112683SJimmy.Vetayases@oracle.com 		if (ispec == NULL)
86212683SJimmy.Vetayases@oracle.com 			return (DDI_FAILURE);
86312683SJimmy.Vetayases@oracle.com 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
86412683SJimmy.Vetayases@oracle.com 		ret = (*psm_intr_ops)(rdip, hdlp,
86512683SJimmy.Vetayases@oracle.com 		    PSM_INTR_OP_FREE_VECTORS, NULL);
86612683SJimmy.Vetayases@oracle.com 	} else {
86712683SJimmy.Vetayases@oracle.com 		/*
86812683SJimmy.Vetayases@oracle.com 		 * No APIX module; fall back to the old scheme where
86912683SJimmy.Vetayases@oracle.com 		 * the interrupt vector was already freed during
87012683SJimmy.Vetayases@oracle.com 		 * ddi_disable_intr() call.
87112683SJimmy.Vetayases@oracle.com 		 */
87212683SJimmy.Vetayases@oracle.com 		ret = DDI_SUCCESS;
87312683SJimmy.Vetayases@oracle.com 	}
87412683SJimmy.Vetayases@oracle.com 
87512683SJimmy.Vetayases@oracle.com 	return (ret);
87612683SJimmy.Vetayases@oracle.com }
87712683SJimmy.Vetayases@oracle.com 
878916Sschwartz int
pci_get_intr_from_vecirq(apic_get_intr_t * intrinfo_p,int vecirq,boolean_t is_irq)879916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
880916Sschwartz     int vecirq, boolean_t is_irq)
881916Sschwartz {
882916Sschwartz 	ddi_intr_handle_impl_t	get_info_ii_hdl;
883916Sschwartz 
884916Sschwartz 	if (is_irq)
885916Sschwartz 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
886916Sschwartz 
887916Sschwartz 	/*
888916Sschwartz 	 * For this locally-declared and used handle, ih_private will contain a
889916Sschwartz 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
890916Sschwartz 	 * global interrupt handling.
891916Sschwartz 	 */
892916Sschwartz 	get_info_ii_hdl.ih_private = intrinfo_p;
89312683SJimmy.Vetayases@oracle.com 	get_info_ii_hdl.ih_vector = vecirq;
894916Sschwartz 
895916Sschwartz 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
896916Sschwartz 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
897916Sschwartz 		return (DDI_FAILURE);
898916Sschwartz 
899916Sschwartz 	return (DDI_SUCCESS);
900916Sschwartz }
901916Sschwartz 
902916Sschwartz 
903916Sschwartz int
pci_get_cpu_from_vecirq(int vecirq,boolean_t is_irq)904916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
905916Sschwartz {
906916Sschwartz 	int rval;
90712683SJimmy.Vetayases@oracle.com 	apic_get_intr_t	intrinfo;
908916Sschwartz 
909916Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
910916Sschwartz 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
911916Sschwartz 
912916Sschwartz 	if (rval == DDI_SUCCESS)
913916Sschwartz 		return (intrinfo.avgi_cpu_id);
914916Sschwartz 	else
915916Sschwartz 		return (-1);
916916Sschwartz }
917916Sschwartz 
918881Sjohnny 
919881Sjohnny static int
pci_enable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)920881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
921881Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
922881Sjohnny {
923881Sjohnny 	struct intrspec	*ispec;
924916Sschwartz 	int		irq;
925916Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
926881Sjohnny 
927881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
928881Sjohnny 	    (void *)hdlp, inum));
929881Sjohnny 
930881Sjohnny 	/* Translate the interrupt if needed */
931881Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9322288Sanish 	if (ispec == NULL)
9332288Sanish 		return (DDI_FAILURE);
93410190SSophia.Li@Sun.COM 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
935881Sjohnny 		ispec->intrspec_vec = inum;
93610190SSophia.Li@Sun.COM 		ispec->intrspec_pri = hdlp->ih_pri;
93710190SSophia.Li@Sun.COM 	}
938916Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
939881Sjohnny 
940881Sjohnny 	/* translate the interrupt if needed */
94111465SKerry.Shu@Sun.COM 	if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) ==
94211465SKerry.Shu@Sun.COM 	    PSM_FAILURE)
94311465SKerry.Shu@Sun.COM 		return (DDI_FAILURE);
944916Sschwartz 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
945916Sschwartz 	    hdlp->ih_pri, irq));
946881Sjohnny 
947881Sjohnny 	/* Add the interrupt handler */
948881Sjohnny 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
949916Sschwartz 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
950916Sschwartz 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
951881Sjohnny 		return (DDI_FAILURE);
952881Sjohnny 
95312683SJimmy.Vetayases@oracle.com 	hdlp->ih_vector = irq;
954916Sschwartz 
955881Sjohnny 	return (DDI_SUCCESS);
956881Sjohnny }
957881Sjohnny 
958881Sjohnny 
959881Sjohnny static void
pci_disable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)960881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
961881Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
962881Sjohnny {
963916Sschwartz 	int		irq;
964881Sjohnny 	struct intrspec	*ispec;
965916Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
966881Sjohnny 
967881Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
968881Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9692288Sanish 	if (ispec == NULL)
9702288Sanish 		return;
97110190SSophia.Li@Sun.COM 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
972881Sjohnny 		ispec->intrspec_vec = inum;
97310190SSophia.Li@Sun.COM 		ispec->intrspec_pri = hdlp->ih_pri;
97410190SSophia.Li@Sun.COM 	}
975916Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
976881Sjohnny 
977881Sjohnny 	/* translate the interrupt if needed */
978916Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
979881Sjohnny 
980881Sjohnny 	/* Disable the interrupt handler */
981916Sschwartz 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
982916Sschwartz 	ihdl_plat_datap->ip_ispecp = NULL;
983881Sjohnny }
984881Sjohnny 
985881Sjohnny /*
986881Sjohnny  * Miscellaneous library function
987881Sjohnny  */
988881Sjohnny int
pci_common_get_reg_prop(dev_info_t * dip,pci_regspec_t * pci_rp)989881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
990881Sjohnny {
991881Sjohnny 	int		i;
992881Sjohnny 	int 		number;
993881Sjohnny 	int		assigned_addr_len;
994881Sjohnny 	uint_t		phys_hi = pci_rp->pci_phys_hi;
995881Sjohnny 	pci_regspec_t	*assigned_addr;
996881Sjohnny 
997881Sjohnny 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
998881Sjohnny 	    (phys_hi & PCI_RELOCAT_B))
999881Sjohnny 		return (DDI_SUCCESS);
1000881Sjohnny 
1001881Sjohnny 	/*
1002881Sjohnny 	 * the "reg" property specifies relocatable, get and interpret the
1003881Sjohnny 	 * "assigned-addresses" property.
1004881Sjohnny 	 */
1005881Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1006881Sjohnny 	    "assigned-addresses", (int **)&assigned_addr,
1007881Sjohnny 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
1008881Sjohnny 		return (DDI_FAILURE);
1009881Sjohnny 
1010881Sjohnny 	/*
1011881Sjohnny 	 * Scan the "assigned-addresses" for one that matches the specified
1012881Sjohnny 	 * "reg" property entry.
1013881Sjohnny 	 */
1014881Sjohnny 	phys_hi &= PCI_CONF_ADDR_MASK;
1015881Sjohnny 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
1016881Sjohnny 	for (i = 0; i < number; i++) {
1017881Sjohnny 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
1018881Sjohnny 		    phys_hi) {
1019881Sjohnny 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
1020881Sjohnny 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
1021881Sjohnny 			ddi_prop_free(assigned_addr);
1022881Sjohnny 			return (DDI_SUCCESS);
1023881Sjohnny 		}
1024881Sjohnny 	}
1025881Sjohnny 
1026881Sjohnny 	ddi_prop_free(assigned_addr);
1027881Sjohnny 	return (DDI_FAILURE);
1028881Sjohnny }
1029881Sjohnny 
1030881Sjohnny 
1031881Sjohnny /*
103210923SEvan.Yan@Sun.COM  * To handle PCI tool ioctls
1033881Sjohnny  */
1034881Sjohnny 
103510923SEvan.Yan@Sun.COM /*ARGSUSED*/
1036881Sjohnny int
pci_common_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1037881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
1038881Sjohnny     int mode, cred_t *credp, int *rvalp)
1039881Sjohnny {
104010923SEvan.Yan@Sun.COM 	minor_t	minor = getminor(dev);
104110923SEvan.Yan@Sun.COM 	int	rv = ENOTTY;
1042881Sjohnny 
104310923SEvan.Yan@Sun.COM 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
1044881Sjohnny 	case PCI_TOOL_REG_MINOR_NUM:
1045881Sjohnny 
1046881Sjohnny 		switch (cmd) {
1047881Sjohnny 		case PCITOOL_DEVICE_SET_REG:
1048881Sjohnny 		case PCITOOL_DEVICE_GET_REG:
1049881Sjohnny 
1050881Sjohnny 			/* Require full privileges. */
1051881Sjohnny 			if (secpolicy_kmdb(credp))
1052881Sjohnny 				rv = EPERM;
1053881Sjohnny 			else
1054881Sjohnny 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
1055881Sjohnny 				    cmd, mode);
1056881Sjohnny 			break;
1057881Sjohnny 
1058881Sjohnny 		case PCITOOL_NEXUS_SET_REG:
1059881Sjohnny 		case PCITOOL_NEXUS_GET_REG:
1060881Sjohnny 
1061881Sjohnny 			/* Require full privileges. */
1062881Sjohnny 			if (secpolicy_kmdb(credp))
1063881Sjohnny 				rv = EPERM;
1064881Sjohnny 			else
1065881Sjohnny 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
1066881Sjohnny 				    cmd, mode);
1067881Sjohnny 			break;
1068881Sjohnny 		}
1069881Sjohnny 		break;
1070881Sjohnny 
1071881Sjohnny 	case PCI_TOOL_INTR_MINOR_NUM:
1072881Sjohnny 
1073881Sjohnny 		switch (cmd) {
1074881Sjohnny 		case PCITOOL_DEVICE_SET_INTR:
1075881Sjohnny 
1076881Sjohnny 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
1077881Sjohnny 			if (secpolicy_ponline(credp)) {
1078881Sjohnny 				rv = EPERM;
1079881Sjohnny 				break;
1080881Sjohnny 			}
1081881Sjohnny 
1082881Sjohnny 		/*FALLTHRU*/
1083881Sjohnny 		/* These require no special privileges. */
1084881Sjohnny 		case PCITOOL_DEVICE_GET_INTR:
10854397Sschwartz 		case PCITOOL_SYSTEM_INTR_INFO:
1086881Sjohnny 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
1087881Sjohnny 			break;
1088881Sjohnny 		}
1089881Sjohnny 		break;
1090881Sjohnny 
1091881Sjohnny 	default:
1092881Sjohnny 		break;
1093881Sjohnny 	}
1094881Sjohnny 
1095881Sjohnny 	return (rv);
1096881Sjohnny }
10971083Sanish 
10981083Sanish 
10991865Sdilpreet int
pci_common_ctlops_poke(peekpoke_ctlops_t * in_args)11001865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
11011865Sdilpreet {
11021865Sdilpreet 	size_t size = in_args->size;
11031865Sdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
11041865Sdilpreet 	uintptr_t host_addr = in_args->host_addr;
11051865Sdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
11061865Sdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
11071865Sdilpreet 	size_t repcount = in_args->repcount;
11081865Sdilpreet 	uint_t flags = in_args->flags;
11091865Sdilpreet 	int err = DDI_SUCCESS;
11101865Sdilpreet 
11111865Sdilpreet 	/*
11121865Sdilpreet 	 * if no handle then this is a poke. We have to return failure here
11131865Sdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
11141865Sdilpreet 	 */
11151865Sdilpreet 	if (in_args->handle == NULL)
11161865Sdilpreet 		return (DDI_FAILURE);
11171865Sdilpreet 
11181865Sdilpreet 	/*
11191865Sdilpreet 	 * rest of this function is actually for cautious puts
11201865Sdilpreet 	 */
11211865Sdilpreet 	for (; repcount; repcount--) {
11221865Sdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
11231865Sdilpreet 			switch (size) {
11241865Sdilpreet 			case sizeof (uint8_t):
11251865Sdilpreet 				pci_config_wr8(hp, (uint8_t *)dev_addr,
11261865Sdilpreet 				    *(uint8_t *)host_addr);
11271865Sdilpreet 				break;
11281865Sdilpreet 			case sizeof (uint16_t):
11291865Sdilpreet 				pci_config_wr16(hp, (uint16_t *)dev_addr,
11301865Sdilpreet 				    *(uint16_t *)host_addr);
11311865Sdilpreet 				break;
11321865Sdilpreet 			case sizeof (uint32_t):
11331865Sdilpreet 				pci_config_wr32(hp, (uint32_t *)dev_addr,
11341865Sdilpreet 				    *(uint32_t *)host_addr);
11351865Sdilpreet 				break;
11361865Sdilpreet 			case sizeof (uint64_t):
11371865Sdilpreet 				pci_config_wr64(hp, (uint64_t *)dev_addr,
11381865Sdilpreet 				    *(uint64_t *)host_addr);
11391865Sdilpreet 				break;
11401865Sdilpreet 			default:
11411865Sdilpreet 				err = DDI_FAILURE;
11421865Sdilpreet 				break;
11431865Sdilpreet 			}
11441865Sdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
11451865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
11461865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
11471865Sdilpreet 				switch (size) {
11481865Sdilpreet 				case sizeof (uint8_t):
11491865Sdilpreet 					i_ddi_io_put8(hp,
11501865Sdilpreet 					    (uint8_t *)dev_addr,
11511865Sdilpreet 					    *(uint8_t *)host_addr);
11521865Sdilpreet 					break;
11531865Sdilpreet 				case sizeof (uint16_t):
11541865Sdilpreet 					i_ddi_io_swap_put16(hp,
11551865Sdilpreet 					    (uint16_t *)dev_addr,
11561865Sdilpreet 					    *(uint16_t *)host_addr);
11571865Sdilpreet 					break;
11581865Sdilpreet 				case sizeof (uint32_t):
11591865Sdilpreet 					i_ddi_io_swap_put32(hp,
11601865Sdilpreet 					    (uint32_t *)dev_addr,
11611865Sdilpreet 					    *(uint32_t *)host_addr);
11621865Sdilpreet 					break;
11631865Sdilpreet 				/*
11641865Sdilpreet 				 * note the 64-bit case is a dummy
11651865Sdilpreet 				 * function - so no need to swap
11661865Sdilpreet 				 */
11671865Sdilpreet 				case sizeof (uint64_t):
11681865Sdilpreet 					i_ddi_io_put64(hp,
11691865Sdilpreet 					    (uint64_t *)dev_addr,
11701865Sdilpreet 					    *(uint64_t *)host_addr);
11711865Sdilpreet 					break;
11721865Sdilpreet 				default:
11731865Sdilpreet 					err = DDI_FAILURE;
11741865Sdilpreet 					break;
11751865Sdilpreet 				}
11761865Sdilpreet 			} else {
11771865Sdilpreet 				switch (size) {
11781865Sdilpreet 				case sizeof (uint8_t):
11791865Sdilpreet 					i_ddi_io_put8(hp,
11801865Sdilpreet 					    (uint8_t *)dev_addr,
11811865Sdilpreet 					    *(uint8_t *)host_addr);
11821865Sdilpreet 					break;
11831865Sdilpreet 				case sizeof (uint16_t):
11841865Sdilpreet 					i_ddi_io_put16(hp,
11851865Sdilpreet 					    (uint16_t *)dev_addr,
11861865Sdilpreet 					    *(uint16_t *)host_addr);
11871865Sdilpreet 					break;
11881865Sdilpreet 				case sizeof (uint32_t):
11891865Sdilpreet 					i_ddi_io_put32(hp,
11901865Sdilpreet 					    (uint32_t *)dev_addr,
11911865Sdilpreet 					    *(uint32_t *)host_addr);
11921865Sdilpreet 					break;
11931865Sdilpreet 				case sizeof (uint64_t):
11941865Sdilpreet 					i_ddi_io_put64(hp,
11951865Sdilpreet 					    (uint64_t *)dev_addr,
11961865Sdilpreet 					    *(uint64_t *)host_addr);
11971865Sdilpreet 					break;
11981865Sdilpreet 				default:
11991865Sdilpreet 					err = DDI_FAILURE;
12001865Sdilpreet 					break;
12011865Sdilpreet 				}
12021865Sdilpreet 			}
12031865Sdilpreet 		} else {
12041865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
12051865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
12061865Sdilpreet 				switch (size) {
12071865Sdilpreet 				case sizeof (uint8_t):
12081865Sdilpreet 					*(uint8_t *)dev_addr =
12091865Sdilpreet 					    *(uint8_t *)host_addr;
12101865Sdilpreet 					break;
12111865Sdilpreet 				case sizeof (uint16_t):
12121865Sdilpreet 					*(uint16_t *)dev_addr =
12131865Sdilpreet 					    ddi_swap16(*(uint16_t *)host_addr);
12141865Sdilpreet 					break;
12151865Sdilpreet 				case sizeof (uint32_t):
12161865Sdilpreet 					*(uint32_t *)dev_addr =
12171865Sdilpreet 					    ddi_swap32(*(uint32_t *)host_addr);
12181865Sdilpreet 					break;
12191865Sdilpreet 				case sizeof (uint64_t):
12201865Sdilpreet 					*(uint64_t *)dev_addr =
12211865Sdilpreet 					    ddi_swap64(*(uint64_t *)host_addr);
12221865Sdilpreet 					break;
12231865Sdilpreet 				default:
12241865Sdilpreet 					err = DDI_FAILURE;
12251865Sdilpreet 					break;
12261865Sdilpreet 				}
12271865Sdilpreet 			} else {
12281865Sdilpreet 				switch (size) {
12291865Sdilpreet 				case sizeof (uint8_t):
12301865Sdilpreet 					*(uint8_t *)dev_addr =
12311865Sdilpreet 					    *(uint8_t *)host_addr;
12321865Sdilpreet 					break;
12331865Sdilpreet 				case sizeof (uint16_t):
12341865Sdilpreet 					*(uint16_t *)dev_addr =
12351865Sdilpreet 					    *(uint16_t *)host_addr;
12361865Sdilpreet 					break;
12371865Sdilpreet 				case sizeof (uint32_t):
12381865Sdilpreet 					*(uint32_t *)dev_addr =
12391865Sdilpreet 					    *(uint32_t *)host_addr;
12401865Sdilpreet 					break;
12411865Sdilpreet 				case sizeof (uint64_t):
12421865Sdilpreet 					*(uint64_t *)dev_addr =
12431865Sdilpreet 					    *(uint64_t *)host_addr;
12441865Sdilpreet 					break;
12451865Sdilpreet 				default:
12461865Sdilpreet 					err = DDI_FAILURE;
12471865Sdilpreet 					break;
12481865Sdilpreet 				}
12491865Sdilpreet 			}
12501865Sdilpreet 		}
12511865Sdilpreet 		host_addr += size;
12521865Sdilpreet 		if (flags == DDI_DEV_AUTOINCR)
12531865Sdilpreet 			dev_addr += size;
12541865Sdilpreet 	}
12551865Sdilpreet 	return (err);
12561865Sdilpreet }
12571865Sdilpreet 
12581865Sdilpreet 
12591865Sdilpreet int
pci_fm_acc_setup(ddi_acc_hdl_t * hp,off_t offset,off_t len)12601865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
12611865Sdilpreet {
12621865Sdilpreet 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
12631865Sdilpreet 
12641865Sdilpreet 	/* endian-ness check */
12651865Sdilpreet 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
12661865Sdilpreet 		return (DDI_FAILURE);
12671865Sdilpreet 
12681865Sdilpreet 	/*
12691865Sdilpreet 	 * range check
12701865Sdilpreet 	 */
12711865Sdilpreet 	if ((offset >= PCI_CONF_HDR_SIZE) ||
12721865Sdilpreet 	    (len > PCI_CONF_HDR_SIZE) ||
12731865Sdilpreet 	    (offset + len > PCI_CONF_HDR_SIZE))
12741865Sdilpreet 		return (DDI_FAILURE);
12751865Sdilpreet 
12761865Sdilpreet 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
12771865Sdilpreet 	/*
12781865Sdilpreet 	 * always use cautious mechanism for config space gets
12791865Sdilpreet 	 */
12801865Sdilpreet 	ap->ahi_get8 = i_ddi_caut_get8;
12811865Sdilpreet 	ap->ahi_get16 = i_ddi_caut_get16;
12821865Sdilpreet 	ap->ahi_get32 = i_ddi_caut_get32;
12831865Sdilpreet 	ap->ahi_get64 = i_ddi_caut_get64;
12841865Sdilpreet 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
12851865Sdilpreet 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
12861865Sdilpreet 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
12871865Sdilpreet 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
12881865Sdilpreet 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
12891865Sdilpreet 		ap->ahi_put8 = i_ddi_caut_put8;
12901865Sdilpreet 		ap->ahi_put16 = i_ddi_caut_put16;
12911865Sdilpreet 		ap->ahi_put32 = i_ddi_caut_put32;
12921865Sdilpreet 		ap->ahi_put64 = i_ddi_caut_put64;
12931865Sdilpreet 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
12941865Sdilpreet 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
12951865Sdilpreet 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
12961865Sdilpreet 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
12971865Sdilpreet 	} else {
12981865Sdilpreet 		ap->ahi_put8 = pci_config_wr8;
12991865Sdilpreet 		ap->ahi_put16 = pci_config_wr16;
13001865Sdilpreet 		ap->ahi_put32 = pci_config_wr32;
13011865Sdilpreet 		ap->ahi_put64 = pci_config_wr64;
13021865Sdilpreet 		ap->ahi_rep_put8 = pci_config_rep_wr8;
13031865Sdilpreet 		ap->ahi_rep_put16 = pci_config_rep_wr16;
13041865Sdilpreet 		ap->ahi_rep_put32 = pci_config_rep_wr32;
13051865Sdilpreet 		ap->ahi_rep_put64 = pci_config_rep_wr64;
13061865Sdilpreet 	}
13071865Sdilpreet 
13081865Sdilpreet 	/* Initialize to default check/notify functions */
13091865Sdilpreet 	ap->ahi_fault_check = i_ddi_acc_fault_check;
13101865Sdilpreet 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
13111865Sdilpreet 	ap->ahi_fault = 0;
13121865Sdilpreet 	impl_acc_err_init(hp);
13131865Sdilpreet 	return (DDI_SUCCESS);
13141865Sdilpreet }
13151865Sdilpreet 
13161865Sdilpreet 
13171865Sdilpreet int
pci_common_ctlops_peek(peekpoke_ctlops_t * in_args)13181865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
13191865Sdilpreet {
13201865Sdilpreet 	size_t size = in_args->size;
13211865Sdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
13221865Sdilpreet 	uintptr_t host_addr = in_args->host_addr;
13231865Sdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
13241865Sdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
13251865Sdilpreet 	size_t repcount = in_args->repcount;
13261865Sdilpreet 	uint_t flags = in_args->flags;
13271865Sdilpreet 	int err = DDI_SUCCESS;
13281865Sdilpreet 
13291865Sdilpreet 	/*
13301865Sdilpreet 	 * if no handle then this is a peek. We have to return failure here
13311865Sdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
13321865Sdilpreet 	 */
13331865Sdilpreet 	if (in_args->handle == NULL)
13341865Sdilpreet 		return (DDI_FAILURE);
13351865Sdilpreet 
13361865Sdilpreet 	for (; repcount; repcount--) {
13371865Sdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
13381865Sdilpreet 			switch (size) {
13391865Sdilpreet 			case sizeof (uint8_t):
13401865Sdilpreet 				*(uint8_t *)host_addr = pci_config_rd8(hp,
13411865Sdilpreet 				    (uint8_t *)dev_addr);
13421865Sdilpreet 				break;
13431865Sdilpreet 			case sizeof (uint16_t):
13441865Sdilpreet 				*(uint16_t *)host_addr = pci_config_rd16(hp,
13451865Sdilpreet 				    (uint16_t *)dev_addr);
13461865Sdilpreet 				break;
13471865Sdilpreet 			case sizeof (uint32_t):
13481865Sdilpreet 				*(uint32_t *)host_addr = pci_config_rd32(hp,
13491865Sdilpreet 				    (uint32_t *)dev_addr);
13501865Sdilpreet 				break;
13511865Sdilpreet 			case sizeof (uint64_t):
13521865Sdilpreet 				*(uint64_t *)host_addr = pci_config_rd64(hp,
13531865Sdilpreet 				    (uint64_t *)dev_addr);
13541865Sdilpreet 				break;
13551865Sdilpreet 			default:
13561865Sdilpreet 				err = DDI_FAILURE;
13571865Sdilpreet 				break;
13581865Sdilpreet 			}
13591865Sdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
13601865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
13611865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
13621865Sdilpreet 				switch (size) {
13631865Sdilpreet 				case sizeof (uint8_t):
13641865Sdilpreet 					*(uint8_t *)host_addr =
13651865Sdilpreet 					    i_ddi_io_get8(hp,
13661865Sdilpreet 					    (uint8_t *)dev_addr);
13671865Sdilpreet 					break;
13681865Sdilpreet 				case sizeof (uint16_t):
13691865Sdilpreet 					*(uint16_t *)host_addr =
13701865Sdilpreet 					    i_ddi_io_swap_get16(hp,
13711865Sdilpreet 					    (uint16_t *)dev_addr);
13721865Sdilpreet 					break;
13731865Sdilpreet 				case sizeof (uint32_t):
13741865Sdilpreet 					*(uint32_t *)host_addr =
13751865Sdilpreet 					    i_ddi_io_swap_get32(hp,
13761865Sdilpreet 					    (uint32_t *)dev_addr);
13771865Sdilpreet 					break;
13781865Sdilpreet 				/*
13791865Sdilpreet 				 * note the 64-bit case is a dummy
13801865Sdilpreet 				 * function - so no need to swap
13811865Sdilpreet 				 */
13821865Sdilpreet 				case sizeof (uint64_t):
13831865Sdilpreet 					*(uint64_t *)host_addr =
13841865Sdilpreet 					    i_ddi_io_get64(hp,
13851865Sdilpreet 					    (uint64_t *)dev_addr);
13861865Sdilpreet 					break;
13871865Sdilpreet 				default:
13881865Sdilpreet 					err = DDI_FAILURE;
13891865Sdilpreet 					break;
13901865Sdilpreet 				}
13911865Sdilpreet 			} else {
13921865Sdilpreet 				switch (size) {
13931865Sdilpreet 				case sizeof (uint8_t):
13941865Sdilpreet 					*(uint8_t *)host_addr =
13951865Sdilpreet 					    i_ddi_io_get8(hp,
13961865Sdilpreet 					    (uint8_t *)dev_addr);
13971865Sdilpreet 					break;
13981865Sdilpreet 				case sizeof (uint16_t):
13991865Sdilpreet 					*(uint16_t *)host_addr =
14001865Sdilpreet 					    i_ddi_io_get16(hp,
14011865Sdilpreet 					    (uint16_t *)dev_addr);
14021865Sdilpreet 					break;
14031865Sdilpreet 				case sizeof (uint32_t):
14041865Sdilpreet 					*(uint32_t *)host_addr =
14051865Sdilpreet 					    i_ddi_io_get32(hp,
14061865Sdilpreet 					    (uint32_t *)dev_addr);
14071865Sdilpreet 					break;
14081865Sdilpreet 				case sizeof (uint64_t):
14091865Sdilpreet 					*(uint64_t *)host_addr =
14101865Sdilpreet 					    i_ddi_io_get64(hp,
14111865Sdilpreet 					    (uint64_t *)dev_addr);
14121865Sdilpreet 					break;
14131865Sdilpreet 				default:
14141865Sdilpreet 					err = DDI_FAILURE;
14151865Sdilpreet 					break;
14161865Sdilpreet 				}
14171865Sdilpreet 			}
14181865Sdilpreet 		} else {
14191865Sdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
14201865Sdilpreet 			    DDI_STRUCTURE_BE_ACC) {
14211865Sdilpreet 				switch (in_args->size) {
14221865Sdilpreet 				case sizeof (uint8_t):
14231865Sdilpreet 					*(uint8_t *)host_addr =
14241865Sdilpreet 					    *(uint8_t *)dev_addr;
14251865Sdilpreet 					break;
14261865Sdilpreet 				case sizeof (uint16_t):
14271865Sdilpreet 					*(uint16_t *)host_addr =
14281865Sdilpreet 					    ddi_swap16(*(uint16_t *)dev_addr);
14291865Sdilpreet 					break;
14301865Sdilpreet 				case sizeof (uint32_t):
14311865Sdilpreet 					*(uint32_t *)host_addr =
14321865Sdilpreet 					    ddi_swap32(*(uint32_t *)dev_addr);
14331865Sdilpreet 					break;
14341865Sdilpreet 				case sizeof (uint64_t):
14351865Sdilpreet 					*(uint64_t *)host_addr =
14361865Sdilpreet 					    ddi_swap64(*(uint64_t *)dev_addr);
14371865Sdilpreet 					break;
14381865Sdilpreet 				default:
14391865Sdilpreet 					err = DDI_FAILURE;
14401865Sdilpreet 					break;
14411865Sdilpreet 				}
14421865Sdilpreet 			} else {
14431865Sdilpreet 				switch (in_args->size) {
14441865Sdilpreet 				case sizeof (uint8_t):
14451865Sdilpreet 					*(uint8_t *)host_addr =
14461865Sdilpreet 					    *(uint8_t *)dev_addr;
14471865Sdilpreet 					break;
14481865Sdilpreet 				case sizeof (uint16_t):
14491865Sdilpreet 					*(uint16_t *)host_addr =
14501865Sdilpreet 					    *(uint16_t *)dev_addr;
14511865Sdilpreet 					break;
14521865Sdilpreet 				case sizeof (uint32_t):
14531865Sdilpreet 					*(uint32_t *)host_addr =
14541865Sdilpreet 					    *(uint32_t *)dev_addr;
14551865Sdilpreet 					break;
14561865Sdilpreet 				case sizeof (uint64_t):
14571865Sdilpreet 					*(uint64_t *)host_addr =
14581865Sdilpreet 					    *(uint64_t *)dev_addr;
14591865Sdilpreet 					break;
14601865Sdilpreet 				default:
14611865Sdilpreet 					err = DDI_FAILURE;
14621865Sdilpreet 					break;
14631865Sdilpreet 				}
14641865Sdilpreet 			}
14651865Sdilpreet 		}
14661865Sdilpreet 		host_addr += size;
14671865Sdilpreet 		if (flags == DDI_DEV_AUTOINCR)
14681865Sdilpreet 			dev_addr += size;
14691865Sdilpreet 	}
14701865Sdilpreet 	return (err);
14711865Sdilpreet }
14721865Sdilpreet 
14731865Sdilpreet /*ARGSUSED*/
14741865Sdilpreet int
pci_common_peekpoke(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)14751865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
14761865Sdilpreet 	ddi_ctl_enum_t ctlop, void *arg, void *result)
14771865Sdilpreet {
14781865Sdilpreet 	if (ctlop == DDI_CTLOPS_PEEK)
14791865Sdilpreet 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
14801865Sdilpreet 	else
14811865Sdilpreet 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
14821865Sdilpreet }
14831865Sdilpreet 
14841083Sanish /*
14851083Sanish  * These are the get and put functions to be shared with drivers. The
14861083Sanish  * mutex locking is done inside the functions referenced, rather than
14871083Sanish  * here, and is thus shared across PCI child drivers and any other
14881083Sanish  * consumers of PCI config space (such as the ACPI subsystem).
14891083Sanish  *
14901083Sanish  * The configuration space addresses come in as pointers.  This is fine on
14911083Sanish  * a 32-bit system, where the VM space and configuration space are the same
14921083Sanish  * size.  It's not such a good idea on a 64-bit system, where memory
14931083Sanish  * addresses are twice as large as configuration space addresses.  At some
14941083Sanish  * point in the call tree we need to take a stand and say "you are 32-bit
14951083Sanish  * from this time forth", and this seems like a nice self-contained place.
14961083Sanish  */
14971083Sanish 
14981083Sanish uint8_t
pci_config_rd8(ddi_acc_impl_t * hdlp,uint8_t * addr)14991083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
15001083Sanish {
15011083Sanish 	pci_acc_cfblk_t *cfp;
15021083Sanish 	uint8_t	rval;
15031083Sanish 	int reg;
15041083Sanish 
15051083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
15061083Sanish 
15071083Sanish 	reg = (int)(uintptr_t)addr;
15081083Sanish 
15091083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15101083Sanish 
15111083Sanish 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
15121083Sanish 	    reg);
15131083Sanish 
15141083Sanish 	return (rval);
15151083Sanish }
15161083Sanish 
15171083Sanish void
pci_config_rep_rd8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)15181083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
15191083Sanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
15201083Sanish {
15211083Sanish 	uint8_t *h, *d;
15221083Sanish 
15231083Sanish 	h = host_addr;
15241083Sanish 	d = dev_addr;
15251083Sanish 
15261083Sanish 	if (flags == DDI_DEV_AUTOINCR)
15271083Sanish 		for (; repcount; repcount--)
15281083Sanish 			*h++ = pci_config_rd8(hdlp, d++);
15291083Sanish 	else
15301083Sanish 		for (; repcount; repcount--)
15311083Sanish 			*h++ = pci_config_rd8(hdlp, d);
15321083Sanish }
15331083Sanish 
15341083Sanish uint16_t
pci_config_rd16(ddi_acc_impl_t * hdlp,uint16_t * addr)15351083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
15361083Sanish {
15371083Sanish 	pci_acc_cfblk_t *cfp;
15381083Sanish 	uint16_t rval;
15391083Sanish 	int reg;
15401083Sanish 
15411083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
15421083Sanish 
15431083Sanish 	reg = (int)(uintptr_t)addr;
15441083Sanish 
15451083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15461083Sanish 
15471083Sanish 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
15481083Sanish 	    reg);
15491083Sanish 
15501083Sanish 	return (rval);
15511083Sanish }
15521083Sanish 
15531083Sanish void
pci_config_rep_rd16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)15541083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
15551083Sanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
15561083Sanish {
15571083Sanish 	uint16_t *h, *d;
15581083Sanish 
15591083Sanish 	h = host_addr;
15601083Sanish 	d = dev_addr;
15611083Sanish 
15621083Sanish 	if (flags == DDI_DEV_AUTOINCR)
15631083Sanish 		for (; repcount; repcount--)
15641083Sanish 			*h++ = pci_config_rd16(hdlp, d++);
15651083Sanish 	else
15661083Sanish 		for (; repcount; repcount--)
15671083Sanish 			*h++ = pci_config_rd16(hdlp, d);
15681083Sanish }
15691083Sanish 
15701083Sanish uint32_t
pci_config_rd32(ddi_acc_impl_t * hdlp,uint32_t * addr)15711083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
15721083Sanish {
15731083Sanish 	pci_acc_cfblk_t *cfp;
15741083Sanish 	uint32_t rval;
15751083Sanish 	int reg;
15761083Sanish 
15771083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
15781083Sanish 
15791083Sanish 	reg = (int)(uintptr_t)addr;
15801083Sanish 
15811083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
15821083Sanish 
15831083Sanish 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
15841083Sanish 	    cfp->c_funcnum, reg);
15851083Sanish 
15861083Sanish 	return (rval);
15871083Sanish }
15881083Sanish 
15891083Sanish void
pci_config_rep_rd32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)15901083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
15911083Sanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
15921083Sanish {
15931083Sanish 	uint32_t *h, *d;
15941083Sanish 
15951083Sanish 	h = host_addr;
15961083Sanish 	d = dev_addr;
15971083Sanish 
15981083Sanish 	if (flags == DDI_DEV_AUTOINCR)
15991083Sanish 		for (; repcount; repcount--)
16001083Sanish 			*h++ = pci_config_rd32(hdlp, d++);
16011083Sanish 	else
16021083Sanish 		for (; repcount; repcount--)
16031083Sanish 			*h++ = pci_config_rd32(hdlp, d);
16041083Sanish }
16051083Sanish 
16061083Sanish 
16071083Sanish void
pci_config_wr8(ddi_acc_impl_t * hdlp,uint8_t * addr,uint8_t value)16081083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
16091083Sanish {
16101083Sanish 	pci_acc_cfblk_t *cfp;
16111083Sanish 	int reg;
16121083Sanish 
16131083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
16141083Sanish 
16151083Sanish 	reg = (int)(uintptr_t)addr;
16161083Sanish 
16171083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
16181083Sanish 
16191083Sanish 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
16201083Sanish 	    cfp->c_funcnum, reg, value);
16211083Sanish }
16221083Sanish 
16231083Sanish void
pci_config_rep_wr8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)16241083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
16251083Sanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
16261083Sanish {
16271083Sanish 	uint8_t *h, *d;
16281083Sanish 
16291083Sanish 	h = host_addr;
16301083Sanish 	d = dev_addr;
16311083Sanish 
16321083Sanish 	if (flags == DDI_DEV_AUTOINCR)
16331083Sanish 		for (; repcount; repcount--)
16341083Sanish 			pci_config_wr8(hdlp, d++, *h++);
16351083Sanish 	else
16361083Sanish 		for (; repcount; repcount--)
16371083Sanish 			pci_config_wr8(hdlp, d, *h++);
16381083Sanish }
16391083Sanish 
16401083Sanish void
pci_config_wr16(ddi_acc_impl_t * hdlp,uint16_t * addr,uint16_t value)16411083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
16421083Sanish {
16431083Sanish 	pci_acc_cfblk_t *cfp;
16441083Sanish 	int reg;
16451083Sanish 
16461083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
16471083Sanish 
16481083Sanish 	reg = (int)(uintptr_t)addr;
16491083Sanish 
16501083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
16511083Sanish 
16521083Sanish 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
16531083Sanish 	    cfp->c_funcnum, reg, value);
16541083Sanish }
16551083Sanish 
16561083Sanish void
pci_config_rep_wr16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)16571083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
16581083Sanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
16591083Sanish {
16601083Sanish 	uint16_t *h, *d;
16611083Sanish 
16621083Sanish 	h = host_addr;
16631083Sanish 	d = dev_addr;
16641083Sanish 
16651083Sanish 	if (flags == DDI_DEV_AUTOINCR)
16661083Sanish 		for (; repcount; repcount--)
16671083Sanish 			pci_config_wr16(hdlp, d++, *h++);
16681083Sanish 	else
16691083Sanish 		for (; repcount; repcount--)
16701083Sanish 			pci_config_wr16(hdlp, d, *h++);
16711083Sanish }
16721083Sanish 
16731083Sanish void
pci_config_wr32(ddi_acc_impl_t * hdlp,uint32_t * addr,uint32_t value)16741083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
16751083Sanish {
16761083Sanish 	pci_acc_cfblk_t *cfp;
16771083Sanish 	int reg;
16781083Sanish 
16791083Sanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
16801083Sanish 
16811083Sanish 	reg = (int)(uintptr_t)addr;
16821083Sanish 
16831083Sanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
16841083Sanish 
16851083Sanish 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
16861083Sanish 	    cfp->c_funcnum, reg, value);
16871083Sanish }
16881083Sanish 
16891083Sanish void
pci_config_rep_wr32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)16901083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
16911083Sanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
16921083Sanish {
16931083Sanish 	uint32_t *h, *d;
16941083Sanish 
16951083Sanish 	h = host_addr;
16961083Sanish 	d = dev_addr;
16971083Sanish 
16981083Sanish 	if (flags == DDI_DEV_AUTOINCR)
16991083Sanish 		for (; repcount; repcount--)
17001083Sanish 			pci_config_wr32(hdlp, d++, *h++);
17011083Sanish 	else
17021083Sanish 		for (; repcount; repcount--)
17031083Sanish 			pci_config_wr32(hdlp, d, *h++);
17041083Sanish }
17051083Sanish 
17061083Sanish uint64_t
pci_config_rd64(ddi_acc_impl_t * hdlp,uint64_t * addr)17071083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
17081083Sanish {
17091083Sanish 	uint32_t lw_val;
17101083Sanish 	uint32_t hi_val;
17111083Sanish 	uint32_t *dp;
17121083Sanish 	uint64_t val;
17131083Sanish 
17141083Sanish 	dp = (uint32_t *)addr;
17151083Sanish 	lw_val = pci_config_rd32(hdlp, dp);
17161083Sanish 	dp++;
17171083Sanish 	hi_val = pci_config_rd32(hdlp, dp);
17181083Sanish 	val = ((uint64_t)hi_val << 32) | lw_val;
17191083Sanish 	return (val);
17201083Sanish }
17211083Sanish 
17221083Sanish void
pci_config_wr64(ddi_acc_impl_t * hdlp,uint64_t * addr,uint64_t value)17231083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
17241083Sanish {
17251083Sanish 	uint32_t lw_val;
17261083Sanish 	uint32_t hi_val;
17271083Sanish 	uint32_t *dp;
17281083Sanish 
17291083Sanish 	dp = (uint32_t *)addr;
17301083Sanish 	lw_val = (uint32_t)(value & 0xffffffff);
17311083Sanish 	hi_val = (uint32_t)(value >> 32);
17321083Sanish 	pci_config_wr32(hdlp, dp, lw_val);
17331083Sanish 	dp++;
17341083Sanish 	pci_config_wr32(hdlp, dp, hi_val);
17351083Sanish }
17361083Sanish 
17371083Sanish void
pci_config_rep_rd64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)17381083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
17391083Sanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
17401083Sanish {
17411083Sanish 	if (flags == DDI_DEV_AUTOINCR) {
17421083Sanish 		for (; repcount; repcount--)
17431083Sanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
17441083Sanish 	} else {
17451083Sanish 		for (; repcount; repcount--)
17461083Sanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
17471083Sanish 	}
17481083Sanish }
17491083Sanish 
17501083Sanish void
pci_config_rep_wr64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)17511083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
17521083Sanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
17531083Sanish {
17541083Sanish 	if (flags == DDI_DEV_AUTOINCR) {
17551083Sanish 		for (; repcount; repcount--)
17561083Sanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
17571083Sanish 	} else {
17581083Sanish 		for (; repcount; repcount--)
17591083Sanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
17601083Sanish 	}
17611083Sanish }
1762