xref: /titanic_44/usr/src/uts/i86pc/io/pci/pci_common.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
170025d76Sjohnny /*
270025d76Sjohnny  * CDDL HEADER START
370025d76Sjohnny  *
470025d76Sjohnny  * The contents of this file are subject to the terms of the
5102cb92eSjohnny  * Common Development and Distribution License (the "License").
6102cb92eSjohnny  * You may not use this file except in compliance with the License.
770025d76Sjohnny  *
870025d76Sjohnny  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
970025d76Sjohnny  * or http://www.opensolaris.org/os/licensing.
1070025d76Sjohnny  * See the License for the specific language governing permissions
1170025d76Sjohnny  * and limitations under the License.
1270025d76Sjohnny  *
1370025d76Sjohnny  * When distributing Covered Code, include this CDDL HEADER in each
1470025d76Sjohnny  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1570025d76Sjohnny  * If applicable, add the following below this CDDL HEADER, with the
1670025d76Sjohnny  * fields enclosed by brackets "[]" replaced with your own identifying
1770025d76Sjohnny  * information: Portions Copyright [yyyy] [name of copyright owner]
1870025d76Sjohnny  *
1970025d76Sjohnny  * CDDL HEADER END
2070025d76Sjohnny  */
2170025d76Sjohnny 
2270025d76Sjohnny /*
235cd376e8SJimmy Vetayases  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2470025d76Sjohnny  */
2570025d76Sjohnny 
2670025d76Sjohnny /*
2770025d76Sjohnny  *	File that has code which is common between pci(7d) and npe(7d)
2870025d76Sjohnny  *	It shares the following:
2970025d76Sjohnny  *	- interrupt code
3070025d76Sjohnny  *	- pci_tools ioctl code
3170025d76Sjohnny  *	- name_child code
3270025d76Sjohnny  *	- set_parent_private_data code
3370025d76Sjohnny  */
3470025d76Sjohnny 
3570025d76Sjohnny #include <sys/conf.h>
3670025d76Sjohnny #include <sys/pci.h>
3770025d76Sjohnny #include <sys/sunndi.h>
387a364d25Sschwartz #include <sys/mach_intr.h>
3970025d76Sjohnny #include <sys/pci_intr_lib.h>
4070025d76Sjohnny #include <sys/psm.h>
4170025d76Sjohnny #include <sys/policy.h>
4270025d76Sjohnny #include <sys/sysmacros.h>
437a364d25Sschwartz #include <sys/clock.h>
44ae115bc7Smrj #include <sys/apic.h>
4570025d76Sjohnny #include <sys/pci_tools.h>
4670025d76Sjohnny #include <io/pci/pci_var.h>
4770025d76Sjohnny #include <io/pci/pci_tools_ext.h>
4870025d76Sjohnny #include <io/pci/pci_common.h>
49649d4cceSanish #include <sys/pci_cfgspace.h>
50649d4cceSanish #include <sys/pci_impl.h>
51600d7745Sjveta #include <sys/pci_cap.h>
5270025d76Sjohnny 
5370025d76Sjohnny /*
5470025d76Sjohnny  * Function prototypes
5570025d76Sjohnny  */
5670025d76Sjohnny static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
5770025d76Sjohnny static int	pci_enable_intr(dev_info_t *, dev_info_t *,
5870025d76Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
5970025d76Sjohnny static void	pci_disable_intr(dev_info_t *, dev_info_t *,
6070025d76Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
61*7ff178cdSJimmy Vetayases static int	pci_alloc_intr_fixed(dev_info_t *, dev_info_t *,
62*7ff178cdSJimmy Vetayases 		    ddi_intr_handle_impl_t *, void *);
63*7ff178cdSJimmy Vetayases static int	pci_free_intr_fixed(dev_info_t *, dev_info_t *,
64*7ff178cdSJimmy Vetayases 		    ddi_intr_handle_impl_t *);
6570025d76Sjohnny 
66*7ff178cdSJimmy Vetayases /* Extern declarations for PSM module */
6770025d76Sjohnny extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
6870025d76Sjohnny 		    psm_intr_op_t, int *);
69*7ff178cdSJimmy Vetayases extern ddi_irm_pool_t *apix_irm_pool_p;
7070025d76Sjohnny 
7170025d76Sjohnny /*
7270025d76Sjohnny  * pci_name_child:
7370025d76Sjohnny  *
7470025d76Sjohnny  *	Assign the address portion of the node name
7570025d76Sjohnny  */
7670025d76Sjohnny int
pci_common_name_child(dev_info_t * child,char * name,int namelen)7770025d76Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
7870025d76Sjohnny {
7970025d76Sjohnny 	int		dev, func, length;
8070025d76Sjohnny 	char		**unit_addr;
8170025d76Sjohnny 	uint_t		n;
8270025d76Sjohnny 	pci_regspec_t	*pci_rp;
8370025d76Sjohnny 
8470025d76Sjohnny 	if (ndi_dev_is_persistent_node(child) == 0) {
8570025d76Sjohnny 		/*
8670025d76Sjohnny 		 * For .conf node, use "unit-address" property
8770025d76Sjohnny 		 */
8870025d76Sjohnny 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
8970025d76Sjohnny 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
9070025d76Sjohnny 		    DDI_PROP_SUCCESS) {
9170025d76Sjohnny 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
9270025d76Sjohnny 			    ddi_get_name(child));
9370025d76Sjohnny 			return (DDI_FAILURE);
9470025d76Sjohnny 		}
9570025d76Sjohnny 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
9670025d76Sjohnny 			cmn_err(CE_WARN, "unit-address property in %s.conf"
9770025d76Sjohnny 			    " not well-formed", ddi_get_name(child));
9870025d76Sjohnny 			ddi_prop_free(unit_addr);
9970025d76Sjohnny 			return (DDI_FAILURE);
10070025d76Sjohnny 		}
10170025d76Sjohnny 		(void) snprintf(name, namelen, "%s", *unit_addr);
10270025d76Sjohnny 		ddi_prop_free(unit_addr);
10370025d76Sjohnny 		return (DDI_SUCCESS);
10470025d76Sjohnny 	}
10570025d76Sjohnny 
10670025d76Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
10770025d76Sjohnny 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
10870025d76Sjohnny 		cmn_err(CE_WARN, "cannot find reg property in %s",
10970025d76Sjohnny 		    ddi_get_name(child));
11070025d76Sjohnny 		return (DDI_FAILURE);
11170025d76Sjohnny 	}
11270025d76Sjohnny 
11370025d76Sjohnny 	/* copy the device identifications */
11470025d76Sjohnny 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
11570025d76Sjohnny 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
11670025d76Sjohnny 
11770025d76Sjohnny 	/*
11870025d76Sjohnny 	 * free the memory allocated by ddi_prop_lookup_int_array
11970025d76Sjohnny 	 */
12070025d76Sjohnny 	ddi_prop_free(pci_rp);
12170025d76Sjohnny 
12270025d76Sjohnny 	if (func != 0) {
12370025d76Sjohnny 		(void) snprintf(name, namelen, "%x,%x", dev, func);
12470025d76Sjohnny 	} else {
12570025d76Sjohnny 		(void) snprintf(name, namelen, "%x", dev);
12670025d76Sjohnny 	}
12770025d76Sjohnny 
12870025d76Sjohnny 	return (DDI_SUCCESS);
12970025d76Sjohnny }
13070025d76Sjohnny 
13170025d76Sjohnny /*
13270025d76Sjohnny  * Interrupt related code:
13370025d76Sjohnny  *
13470025d76Sjohnny  * The following busop is common to npe and pci drivers
13570025d76Sjohnny  *	bus_introp
13670025d76Sjohnny  */
13770025d76Sjohnny 
13870025d76Sjohnny /*
13970025d76Sjohnny  * Create the ddi_parent_private_data for a pseudo child.
14070025d76Sjohnny  */
14170025d76Sjohnny void
pci_common_set_parent_private_data(dev_info_t * dip)14270025d76Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
14370025d76Sjohnny {
14470025d76Sjohnny 	struct ddi_parent_private_data *pdptr;
14570025d76Sjohnny 
14670025d76Sjohnny 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
14770025d76Sjohnny 	    (sizeof (struct ddi_parent_private_data) +
14870025d76Sjohnny 	    sizeof (struct intrspec)), KM_SLEEP);
14970025d76Sjohnny 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
15070025d76Sjohnny 	pdptr->par_nintr = 1;
15170025d76Sjohnny 	ddi_set_parent_data(dip, pdptr);
15270025d76Sjohnny }
15370025d76Sjohnny 
15470025d76Sjohnny /*
15570025d76Sjohnny  * pci_get_priority:
15670025d76Sjohnny  *	Figure out the priority of the device
15770025d76Sjohnny  */
15870025d76Sjohnny static int
pci_get_priority(dev_info_t * dip,ddi_intr_handle_impl_t * hdlp,int * pri)15970025d76Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
16070025d76Sjohnny {
16170025d76Sjohnny 	struct intrspec *ispec;
16270025d76Sjohnny 
16370025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
16470025d76Sjohnny 	    (void *)dip, (void *)hdlp));
16570025d76Sjohnny 
16670025d76Sjohnny 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
16770025d76Sjohnny 	    hdlp->ih_inum)) == NULL) {
16870025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
169614edcaeSEvan Yan 			*pri = pci_class_to_pil(dip);
17070025d76Sjohnny 			pci_common_set_parent_private_data(hdlp->ih_dip);
17170025d76Sjohnny 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
17270025d76Sjohnny 			    hdlp->ih_inum);
17370025d76Sjohnny 			return (DDI_SUCCESS);
17470025d76Sjohnny 		}
17570025d76Sjohnny 		return (DDI_FAILURE);
17670025d76Sjohnny 	}
17770025d76Sjohnny 
17870025d76Sjohnny 	*pri = ispec->intrspec_pri;
17970025d76Sjohnny 	return (DDI_SUCCESS);
18070025d76Sjohnny }
18170025d76Sjohnny 
18270025d76Sjohnny 
18370025d76Sjohnny 
184d4bc0535SKrishna Elango static int pcieb_intr_pri_counter = 0;
18570025d76Sjohnny 
18670025d76Sjohnny /*
18770025d76Sjohnny  * pci_common_intr_ops: bus_intr_op() function for interrupt support
18870025d76Sjohnny  */
18970025d76Sjohnny 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)19070025d76Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
19170025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
19270025d76Sjohnny {
19370025d76Sjohnny 	int			priority = 0;
19470025d76Sjohnny 	int			psm_status = 0;
19570025d76Sjohnny 	int			pci_status = 0;
19670025d76Sjohnny 	int			pci_rval, psm_rval = PSM_FAILURE;
19770025d76Sjohnny 	int			types = 0;
19870025d76Sjohnny 	int			pciepci = 0;
199102cb92eSjohnny 	int			i, j, count;
200600d7745Sjveta 	int			rv;
20170025d76Sjohnny 	int			behavior;
202d12abe7cSanish 	int			cap_ptr;
203600d7745Sjveta 	uint16_t		msi_cap_base, msix_cap_base, cap_ctrl;
204600d7745Sjveta 	char			*prop;
20570025d76Sjohnny 	ddi_intrspec_t		isp;
20670025d76Sjohnny 	struct intrspec		*ispec;
20770025d76Sjohnny 	ddi_intr_handle_impl_t	tmp_hdl;
20870025d76Sjohnny 	ddi_intr_msix_t		*msix_p;
209e1d9f4e6Sschwartz 	ihdl_plat_t		*ihdl_plat_datap;
210102cb92eSjohnny 	ddi_intr_handle_t	*h_array;
211d12abe7cSanish 	ddi_acc_handle_t	handle;
212*7ff178cdSJimmy Vetayases 	apic_get_intr_t		intrinfo;
21370025d76Sjohnny 
21470025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT,
21570025d76Sjohnny 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
21670025d76Sjohnny 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
21770025d76Sjohnny 
21870025d76Sjohnny 	/* Process the request */
21970025d76Sjohnny 	switch (intr_op) {
22070025d76Sjohnny 	case DDI_INTROP_SUPPORTED_TYPES:
22120036fe5Segillett 		/*
222600d7745Sjveta 		 * First we determine the interrupt types supported by the
223600d7745Sjveta 		 * device itself, then we filter them through what the OS
224600d7745Sjveta 		 * and system supports.  We determine system-level
225600d7745Sjveta 		 * interrupt type support for anything other than fixed intrs
226600d7745Sjveta 		 * through the psm_intr_ops vector
22720036fe5Segillett 		 */
228600d7745Sjveta 		rv = DDI_FAILURE;
22970025d76Sjohnny 
230600d7745Sjveta 		/* Fixed supported by default */
231600d7745Sjveta 		types = DDI_INTR_TYPE_FIXED;
232600d7745Sjveta 
233600d7745Sjveta 		if (psm_intr_ops == NULL) {
234600d7745Sjveta 			*(int *)result = types;
235600d7745Sjveta 			return (DDI_SUCCESS);
236600d7745Sjveta 		}
237600d7745Sjveta 		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
238600d7745Sjveta 			return (DDI_FAILURE);
239600d7745Sjveta 
240600d7745Sjveta 		/* Sanity test cap control values if found */
241600d7745Sjveta 
242600d7745Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
243600d7745Sjveta 		    DDI_SUCCESS) {
244600d7745Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
245600d7745Sjveta 			    PCI_MSI_CTRL);
246600d7745Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
247600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
248600d7745Sjveta 
249600d7745Sjveta 			types |= DDI_INTR_TYPE_MSI;
250600d7745Sjveta 		}
251600d7745Sjveta 
252600d7745Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
253600d7745Sjveta 		    DDI_SUCCESS) {
254600d7745Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
255600d7745Sjveta 			    PCI_MSIX_CTRL);
256600d7745Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
257600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
258600d7745Sjveta 
259600d7745Sjveta 			types |= DDI_INTR_TYPE_MSIX;
260600d7745Sjveta 		}
261600d7745Sjveta 
262600d7745Sjveta 		/*
263600d7745Sjveta 		 * Filter device-level types through system-level support
264600d7745Sjveta 		 */
265600d7745Sjveta 		tmp_hdl.ih_type = types;
266600d7745Sjveta 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
267600d7745Sjveta 		    &types) != PSM_SUCCESS)
268600d7745Sjveta 			goto SUPPORTED_TYPES_OUT;
269600d7745Sjveta 
27070025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
27170025d76Sjohnny 		    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
272*7ff178cdSJimmy Vetayases 		    types));
273600d7745Sjveta 
274600d7745Sjveta 		/*
275600d7745Sjveta 		 * Export any MSI/MSI-X cap locations via properties
276600d7745Sjveta 		 */
277600d7745Sjveta 		if (types & DDI_INTR_TYPE_MSI) {
278600d7745Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
279600d7745Sjveta 			    "pci-msi-capid-pointer", (int)msi_cap_base) !=
280600d7745Sjveta 			    DDI_PROP_SUCCESS)
281600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
28270025d76Sjohnny 		}
283600d7745Sjveta 		if (types & DDI_INTR_TYPE_MSIX) {
284600d7745Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
285600d7745Sjveta 			    "pci-msix-capid-pointer", (int)msix_cap_base) !=
286600d7745Sjveta 			    DDI_PROP_SUCCESS)
287600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
288600d7745Sjveta 		}
289600d7745Sjveta 
290600d7745Sjveta 		rv = DDI_SUCCESS;
291600d7745Sjveta 
292600d7745Sjveta SUPPORTED_TYPES_OUT:
293600d7745Sjveta 		*(int *)result = types;
294600d7745Sjveta 		pci_config_teardown(&handle);
295600d7745Sjveta 		return (rv);
296600d7745Sjveta 
297a54f81fbSanish 	case DDI_INTROP_NAVAIL:
29870025d76Sjohnny 	case DDI_INTROP_NINTRS:
299a54f81fbSanish 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
300a54f81fbSanish 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
301a54f81fbSanish 			    result) != DDI_SUCCESS)
30270025d76Sjohnny 				return (DDI_FAILURE);
303a54f81fbSanish 		} else {
304a54f81fbSanish 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
305a54f81fbSanish 			if (*(int *)result == 0)
306a54f81fbSanish 				return (DDI_FAILURE);
307a54f81fbSanish 		}
30870025d76Sjohnny 		break;
30970025d76Sjohnny 	case DDI_INTROP_ALLOC:
310*7ff178cdSJimmy Vetayases 
311*7ff178cdSJimmy Vetayases 		/*
312*7ff178cdSJimmy Vetayases 		 * FIXED type
313*7ff178cdSJimmy Vetayases 		 */
314*7ff178cdSJimmy Vetayases 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
315*7ff178cdSJimmy Vetayases 			return (pci_alloc_intr_fixed(pdip, rdip, hdlp, result));
31670025d76Sjohnny 		/*
31770025d76Sjohnny 		 * MSI or MSIX (figure out number of vectors available)
31870025d76Sjohnny 		 */
31970025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
32070025d76Sjohnny 		    (psm_intr_ops != NULL) &&
32170025d76Sjohnny 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
32270025d76Sjohnny 			/*
323d4bc0535SKrishna Elango 			 * Following check is a special case for 'pcieb'.
32470025d76Sjohnny 			 * This makes sure vectors with the right priority
325d4bc0535SKrishna Elango 			 * are allocated for pcieb during ALLOC time.
32670025d76Sjohnny 			 */
327d4bc0535SKrishna Elango 			if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) {
32870025d76Sjohnny 				hdlp->ih_pri =
329d4bc0535SKrishna Elango 				    (pcieb_intr_pri_counter % 2) ? 4 : 7;
33070025d76Sjohnny 				pciepci = 1;
33170025d76Sjohnny 			} else
33270025d76Sjohnny 				hdlp->ih_pri = priority;
33380ab886dSwesolows 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
334d12abe7cSanish 
335d12abe7cSanish 			/*
336d12abe7cSanish 			 * Cache in the config handle and cap_ptr
337d12abe7cSanish 			 */
338d12abe7cSanish 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
339d12abe7cSanish 				if (pci_config_setup(rdip, &handle) !=
340d12abe7cSanish 				    DDI_SUCCESS)
341d12abe7cSanish 					return (DDI_FAILURE);
342d12abe7cSanish 				i_ddi_set_pci_config_handle(rdip, handle);
343d12abe7cSanish 			}
344d12abe7cSanish 
345600d7745Sjveta 			prop = NULL;
346600d7745Sjveta 			cap_ptr = 0;
347600d7745Sjveta 			if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
348600d7745Sjveta 				prop = "pci-msi-capid-pointer";
349600d7745Sjveta 			else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
350600d7745Sjveta 				prop = "pci-msix-capid-pointer";
351d12abe7cSanish 
352600d7745Sjveta 			/*
353600d7745Sjveta 			 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
354600d7745Sjveta 			 * for MSI(X) before allocation
355600d7745Sjveta 			 */
356600d7745Sjveta 			if (prop != NULL) {
357d12abe7cSanish 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
358600d7745Sjveta 				    DDI_PROP_DONTPASS, prop, 0);
359600d7745Sjveta 				if (cap_ptr == 0) {
360600d7745Sjveta 					DDI_INTR_NEXDBG((CE_CONT,
361600d7745Sjveta 					    "pci_common_intr_ops: rdip: 0x%p "
362600d7745Sjveta 					    "attempted MSI(X) alloc without "
363600d7745Sjveta 					    "cap property\n", (void *)rdip));
364600d7745Sjveta 					return (DDI_FAILURE);
365d12abe7cSanish 				}
366600d7745Sjveta 			}
367600d7745Sjveta 			i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
368d12abe7cSanish 
369600d7745Sjveta 			/*
370600d7745Sjveta 			 * Allocate interrupt vectors
371600d7745Sjveta 			 */
37270025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
37370025d76Sjohnny 			    PSM_INTR_OP_ALLOC_VECTORS, result);
37470025d76Sjohnny 
3751ac1709fSanish 			if (*(int *)result == 0)
3761ac1709fSanish 				return (DDI_INTR_NOTFOUND);
3771ac1709fSanish 
37870025d76Sjohnny 			/* verify behavior flag and take appropriate action */
37970025d76Sjohnny 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
38070025d76Sjohnny 			    (*(int *)result < hdlp->ih_scratch1)) {
38170025d76Sjohnny 				DDI_INTR_NEXDBG((CE_CONT,
38270025d76Sjohnny 				    "pci_common_intr_ops: behavior %x, "
38370025d76Sjohnny 				    "couldn't get enough intrs\n", behavior));
38470025d76Sjohnny 				hdlp->ih_scratch1 = *(int *)result;
38570025d76Sjohnny 				(void) (*psm_intr_ops)(rdip, hdlp,
38670025d76Sjohnny 				    PSM_INTR_OP_FREE_VECTORS, NULL);
38770025d76Sjohnny 				return (DDI_EAGAIN);
38870025d76Sjohnny 			}
38970025d76Sjohnny 
39070025d76Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
39170025d76Sjohnny 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
39270025d76Sjohnny 					msix_p = pci_msix_init(hdlp->ih_dip);
393fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 					if (msix_p) {
39470025d76Sjohnny 						i_ddi_set_msix(hdlp->ih_dip,
39570025d76Sjohnny 						    msix_p);
396fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 					} else {
397fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						DDI_INTR_NEXDBG((CE_CONT,
398fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    "pci_common_intr_ops: MSI-X"
399fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    "table initilization failed"
400fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    ", rdip 0x%p inum 0x%x\n",
401fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    (void *)rdip,
402fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    hdlp->ih_inum));
403fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 
404fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						(void) (*psm_intr_ops)(rdip,
405fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    hdlp,
406fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    PSM_INTR_OP_FREE_VECTORS,
407fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    NULL);
408fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 
409fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						return (DDI_FAILURE);
410fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 					}
41170025d76Sjohnny 				}
41270025d76Sjohnny 			}
41370025d76Sjohnny 
41470025d76Sjohnny 			if (pciepci) {
41570025d76Sjohnny 				/* update priority in ispec */
41670025d76Sjohnny 				isp = pci_intx_get_ispec(pdip, rdip,
41770025d76Sjohnny 				    (int)hdlp->ih_inum);
41870025d76Sjohnny 				ispec = (struct intrspec *)isp;
41970025d76Sjohnny 				if (ispec)
42070025d76Sjohnny 					ispec->intrspec_pri = hdlp->ih_pri;
421d4bc0535SKrishna Elango 				++pcieb_intr_pri_counter;
42270025d76Sjohnny 			}
42370025d76Sjohnny 
42470025d76Sjohnny 		} else
42570025d76Sjohnny 			return (DDI_FAILURE);
42670025d76Sjohnny 		break;
42770025d76Sjohnny 	case DDI_INTROP_FREE:
42870025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
42970025d76Sjohnny 		    (psm_intr_ops != NULL)) {
43068565200Sanish 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
43168565200Sanish 			    0) {
432d12abe7cSanish 				if (handle = i_ddi_get_pci_config_handle(
433d12abe7cSanish 				    rdip)) {
434d12abe7cSanish 					(void) pci_config_teardown(&handle);
435d12abe7cSanish 					i_ddi_set_pci_config_handle(rdip, NULL);
436d12abe7cSanish 				}
437d12abe7cSanish 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
438d12abe7cSanish 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
439d12abe7cSanish 			}
440d12abe7cSanish 
44170025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
44270025d76Sjohnny 			    PSM_INTR_OP_FREE_VECTORS, NULL);
44370025d76Sjohnny 
44470025d76Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
44570025d76Sjohnny 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
44670025d76Sjohnny 				if (msix_p &&
44768565200Sanish 				    (i_ddi_intr_get_current_nintrs(
44868565200Sanish 				    hdlp->ih_dip) - 1) == 0) {
44970025d76Sjohnny 					pci_msix_fini(msix_p);
45070025d76Sjohnny 					i_ddi_set_msix(hdlp->ih_dip, NULL);
45170025d76Sjohnny 				}
45270025d76Sjohnny 			}
453*7ff178cdSJimmy Vetayases 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
454*7ff178cdSJimmy Vetayases 			return (pci_free_intr_fixed(pdip, rdip, hdlp));
455*7ff178cdSJimmy Vetayases 		} else
456*7ff178cdSJimmy Vetayases 			return (DDI_FAILURE);
45770025d76Sjohnny 		break;
45870025d76Sjohnny 	case DDI_INTROP_GETPRI:
45970025d76Sjohnny 		/* Get the priority */
46070025d76Sjohnny 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
46170025d76Sjohnny 			return (DDI_FAILURE);
46270025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
46370025d76Sjohnny 		    "priority = 0x%x\n", priority));
46470025d76Sjohnny 		*(int *)result = priority;
46570025d76Sjohnny 		break;
46670025d76Sjohnny 	case DDI_INTROP_SETPRI:
46770025d76Sjohnny 		/* Validate the interrupt priority passed */
46870025d76Sjohnny 		if (*(int *)result > LOCK_LEVEL)
46970025d76Sjohnny 			return (DDI_FAILURE);
47070025d76Sjohnny 
47170025d76Sjohnny 		/* Ensure that PSM is all initialized */
47270025d76Sjohnny 		if (psm_intr_ops == NULL)
47370025d76Sjohnny 			return (DDI_FAILURE);
47470025d76Sjohnny 
47596f82fefSSophia Li 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
47696f82fefSSophia Li 		ispec = (struct intrspec *)isp;
47796f82fefSSophia Li 		if (ispec == NULL)
47896f82fefSSophia Li 			return (DDI_FAILURE);
47996f82fefSSophia Li 
48096f82fefSSophia Li 		/* For fixed interrupts */
48196f82fefSSophia Li 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
48296f82fefSSophia Li 			/* if interrupt is shared, return failure */
48396f82fefSSophia Li 			((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
48496f82fefSSophia Li 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
48596f82fefSSophia Li 			    PSM_INTR_OP_GET_SHARED, &psm_status);
48696f82fefSSophia Li 			/*
48796f82fefSSophia Li 			 * For fixed interrupts, the irq may not have been
48896f82fefSSophia Li 			 * allocated when SET_PRI is called, and the above
48996f82fefSSophia Li 			 * GET_SHARED op may return PSM_FAILURE. This is not
49096f82fefSSophia Li 			 * a real error and is ignored below.
49196f82fefSSophia Li 			 */
49296f82fefSSophia Li 			if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) {
49396f82fefSSophia Li 				DDI_INTR_NEXDBG((CE_CONT,
49496f82fefSSophia Li 				    "pci_common_intr_ops: "
49596f82fefSSophia Li 				    "dip 0x%p cannot setpri, psm_rval=%d,"
49696f82fefSSophia Li 				    "psm_status=%d\n", (void *)rdip, psm_rval,
49796f82fefSSophia Li 				    psm_status));
49896f82fefSSophia Li 				return (DDI_FAILURE);
49996f82fefSSophia Li 			}
50096f82fefSSophia Li 		}
50196f82fefSSophia Li 
50270025d76Sjohnny 		/* Change the priority */
50370025d76Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
50470025d76Sjohnny 		    PSM_FAILURE)
50570025d76Sjohnny 			return (DDI_FAILURE);
50670025d76Sjohnny 
50770025d76Sjohnny 		/* update ispec */
50870025d76Sjohnny 		ispec->intrspec_pri = *(int *)result;
50970025d76Sjohnny 		break;
51070025d76Sjohnny 	case DDI_INTROP_ADDISR:
51170025d76Sjohnny 		/* update ispec */
51270025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
51370025d76Sjohnny 		ispec = (struct intrspec *)isp;
514e1d9f4e6Sschwartz 		if (ispec) {
51570025d76Sjohnny 			ispec->intrspec_func = hdlp->ih_cb_func;
516e1d9f4e6Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
517e1d9f4e6Sschwartz 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
518e1d9f4e6Sschwartz 		}
51970025d76Sjohnny 		break;
52070025d76Sjohnny 	case DDI_INTROP_REMISR:
52170025d76Sjohnny 		/* Get the interrupt structure pointer */
52270025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
52370025d76Sjohnny 		ispec = (struct intrspec *)isp;
524e1d9f4e6Sschwartz 		if (ispec) {
52570025d76Sjohnny 			ispec->intrspec_func = (uint_t (*)()) 0;
526e1d9f4e6Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
527e1d9f4e6Sschwartz 			if (ihdl_plat_datap->ip_ksp != NULL)
528e1d9f4e6Sschwartz 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
529e1d9f4e6Sschwartz 		}
53070025d76Sjohnny 		break;
53170025d76Sjohnny 	case DDI_INTROP_GETCAP:
53270025d76Sjohnny 		/*
53370025d76Sjohnny 		 * First check the config space and/or
53470025d76Sjohnny 		 * MSI capability register(s)
53570025d76Sjohnny 		 */
53670025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
53770025d76Sjohnny 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
53870025d76Sjohnny 			    &pci_status);
53970025d76Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
54070025d76Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
54170025d76Sjohnny 
542*7ff178cdSJimmy Vetayases 		/* next check with PSM module */
54370025d76Sjohnny 		if (psm_intr_ops != NULL)
54470025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
54570025d76Sjohnny 			    PSM_INTR_OP_GET_CAP, &psm_status);
54670025d76Sjohnny 
54770025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
54870025d76Sjohnny 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
54970025d76Sjohnny 		    psm_rval, psm_status, pci_rval, pci_status));
55070025d76Sjohnny 
55170025d76Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
55270025d76Sjohnny 			*(int *)result = 0;
55370025d76Sjohnny 			return (DDI_FAILURE);
55470025d76Sjohnny 		}
55570025d76Sjohnny 
55670025d76Sjohnny 		if (psm_rval == PSM_SUCCESS)
55770025d76Sjohnny 			*(int *)result = psm_status;
55870025d76Sjohnny 
55970025d76Sjohnny 		if (pci_rval == DDI_SUCCESS)
56070025d76Sjohnny 			*(int *)result |= pci_status;
56170025d76Sjohnny 
56270025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
56370025d76Sjohnny 		    *(int *)result));
56470025d76Sjohnny 		break;
56570025d76Sjohnny 	case DDI_INTROP_SETCAP:
56670025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
56770025d76Sjohnny 		    "SETCAP cap=0x%x\n", *(int *)result));
56870025d76Sjohnny 		if (psm_intr_ops == NULL)
56970025d76Sjohnny 			return (DDI_FAILURE);
57070025d76Sjohnny 
57170025d76Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
57270025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
57370025d76Sjohnny 			    " returned failure\n"));
57470025d76Sjohnny 			return (DDI_FAILURE);
57570025d76Sjohnny 		}
57670025d76Sjohnny 		break;
57770025d76Sjohnny 	case DDI_INTROP_ENABLE:
57870025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
57970025d76Sjohnny 		if (psm_intr_ops == NULL)
58070025d76Sjohnny 			return (DDI_FAILURE);
58170025d76Sjohnny 
58270025d76Sjohnny 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
58370025d76Sjohnny 		    DDI_SUCCESS)
58470025d76Sjohnny 			return (DDI_FAILURE);
58570025d76Sjohnny 
58670025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
58770025d76Sjohnny 		    "vector=0x%x\n", hdlp->ih_vector));
58870025d76Sjohnny 		break;
58970025d76Sjohnny 	case DDI_INTROP_DISABLE:
59070025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
59170025d76Sjohnny 		if (psm_intr_ops == NULL)
59270025d76Sjohnny 			return (DDI_FAILURE);
59370025d76Sjohnny 
59470025d76Sjohnny 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
59570025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
59670025d76Sjohnny 		    "vector = %x\n", hdlp->ih_vector));
59770025d76Sjohnny 		break;
59870025d76Sjohnny 	case DDI_INTROP_BLOCKENABLE:
59970025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
60070025d76Sjohnny 		    "BLOCKENABLE\n"));
60170025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
60270025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
60370025d76Sjohnny 			return (DDI_FAILURE);
60470025d76Sjohnny 		}
60570025d76Sjohnny 
60670025d76Sjohnny 		/* Check if psm_intr_ops is NULL? */
60770025d76Sjohnny 		if (psm_intr_ops == NULL)
60870025d76Sjohnny 			return (DDI_FAILURE);
60970025d76Sjohnny 
610102cb92eSjohnny 		count = hdlp->ih_scratch1;
611102cb92eSjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
612102cb92eSjohnny 		for (i = 0; i < count; i++) {
613102cb92eSjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
61470025d76Sjohnny 			if (pci_enable_intr(pdip, rdip, hdlp,
615102cb92eSjohnny 			    hdlp->ih_inum) != DDI_SUCCESS) {
61670025d76Sjohnny 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
61770025d76Sjohnny 				    "pci_enable_intr failed for %d\n", i));
618102cb92eSjohnny 				for (j = 0; j < i; j++) {
6192917a9c9Sschwartz 					hdlp = (ddi_intr_handle_impl_t *)
6202917a9c9Sschwartz 					    h_array[j];
62170025d76Sjohnny 					pci_disable_intr(pdip, rdip, hdlp,
622102cb92eSjohnny 					    hdlp->ih_inum);
623102cb92eSjohnny 				}
62470025d76Sjohnny 				return (DDI_FAILURE);
62570025d76Sjohnny 			}
62670025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
627102cb92eSjohnny 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
62870025d76Sjohnny 		}
62970025d76Sjohnny 		break;
63070025d76Sjohnny 	case DDI_INTROP_BLOCKDISABLE:
63170025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
63270025d76Sjohnny 		    "BLOCKDISABLE\n"));
63370025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
63470025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
63570025d76Sjohnny 			return (DDI_FAILURE);
63670025d76Sjohnny 		}
63770025d76Sjohnny 
63870025d76Sjohnny 		/* Check if psm_intr_ops is present */
63970025d76Sjohnny 		if (psm_intr_ops == NULL)
64070025d76Sjohnny 			return (DDI_FAILURE);
64170025d76Sjohnny 
642102cb92eSjohnny 		count = hdlp->ih_scratch1;
643102cb92eSjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
644102cb92eSjohnny 		for (i = 0; i < count; i++) {
645102cb92eSjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
646102cb92eSjohnny 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
64770025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
648102cb92eSjohnny 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
64970025d76Sjohnny 		}
65070025d76Sjohnny 		break;
65170025d76Sjohnny 	case DDI_INTROP_SETMASK:
65270025d76Sjohnny 	case DDI_INTROP_CLRMASK:
65370025d76Sjohnny 		/*
65470025d76Sjohnny 		 * First handle in the config space
65570025d76Sjohnny 		 */
65670025d76Sjohnny 		if (intr_op == DDI_INTROP_SETMASK) {
65770025d76Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
65870025d76Sjohnny 				pci_status = pci_msi_set_mask(rdip,
65970025d76Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
66070025d76Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
66170025d76Sjohnny 				pci_status = pci_intx_set_mask(rdip);
66270025d76Sjohnny 		} else {
66370025d76Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
66470025d76Sjohnny 				pci_status = pci_msi_clr_mask(rdip,
66570025d76Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
66670025d76Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
66770025d76Sjohnny 				pci_status = pci_intx_clr_mask(rdip);
66870025d76Sjohnny 		}
66970025d76Sjohnny 
670*7ff178cdSJimmy Vetayases 		/* For MSI/X; no need to check with PSM module */
67170025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
67270025d76Sjohnny 			return (pci_status);
67370025d76Sjohnny 
67470025d76Sjohnny 		/* For fixed interrupts only: handle config space first */
67570025d76Sjohnny 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
67670025d76Sjohnny 		    pci_status == DDI_SUCCESS)
67770025d76Sjohnny 			break;
67870025d76Sjohnny 
679*7ff178cdSJimmy Vetayases 		/* For fixed interrupts only: confer with PSM module next */
68070025d76Sjohnny 		if (psm_intr_ops != NULL) {
68170025d76Sjohnny 			/* If interrupt is shared; do nothing */
68270025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
68370025d76Sjohnny 			    PSM_INTR_OP_GET_SHARED, &psm_status);
68470025d76Sjohnny 
68570025d76Sjohnny 			if (psm_rval == PSM_FAILURE || psm_status == 1)
68670025d76Sjohnny 				return (pci_status);
68770025d76Sjohnny 
688*7ff178cdSJimmy Vetayases 			/* Now, PSM module should try to set/clear the mask */
68970025d76Sjohnny 			if (intr_op == DDI_INTROP_SETMASK)
69070025d76Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
69170025d76Sjohnny 				    PSM_INTR_OP_SET_MASK, NULL);
69270025d76Sjohnny 			else
69370025d76Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
69470025d76Sjohnny 				    PSM_INTR_OP_CLEAR_MASK, NULL);
69570025d76Sjohnny 		}
69670025d76Sjohnny 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
69770025d76Sjohnny 	case DDI_INTROP_GETPENDING:
69870025d76Sjohnny 		/*
69970025d76Sjohnny 		 * First check the config space and/or
70070025d76Sjohnny 		 * MSI capability register(s)
70170025d76Sjohnny 		 */
70270025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
70370025d76Sjohnny 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
70470025d76Sjohnny 			    hdlp->ih_inum, &pci_status);
70570025d76Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
70670025d76Sjohnny 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
70770025d76Sjohnny 
708*7ff178cdSJimmy Vetayases 		/* On failure; next try with PSM module */
70970025d76Sjohnny 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
71070025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
71170025d76Sjohnny 			    PSM_INTR_OP_GET_PENDING, &psm_status);
71270025d76Sjohnny 
71370025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
71470025d76Sjohnny 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
71570025d76Sjohnny 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
71670025d76Sjohnny 		    pci_status));
71770025d76Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
71870025d76Sjohnny 			*(int *)result = 0;
71970025d76Sjohnny 			return (DDI_FAILURE);
72070025d76Sjohnny 		}
72170025d76Sjohnny 
72270025d76Sjohnny 		if (psm_rval != PSM_FAILURE)
72370025d76Sjohnny 			*(int *)result = psm_status;
72470025d76Sjohnny 		else if (pci_rval != DDI_FAILURE)
72570025d76Sjohnny 			*(int *)result = pci_status;
72670025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
72770025d76Sjohnny 		    *(int *)result));
72870025d76Sjohnny 		break;
72909b1eac2SEvan Yan 	case DDI_INTROP_GETTARGET:
73009b1eac2SEvan Yan 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n"));
73109b1eac2SEvan Yan 
732*7ff178cdSJimmy Vetayases 		bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
733*7ff178cdSJimmy Vetayases 		tmp_hdl.ih_private = (void *)&intrinfo;
734*7ff178cdSJimmy Vetayases 		intrinfo.avgi_req_flags = PSMGI_INTRBY_DEFAULT;
735*7ff178cdSJimmy Vetayases 		intrinfo.avgi_req_flags |= PSMGI_REQ_CPUID;
736*7ff178cdSJimmy Vetayases 
737*7ff178cdSJimmy Vetayases 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_GET_INTR,
738*7ff178cdSJimmy Vetayases 		    NULL) == PSM_FAILURE)
73909b1eac2SEvan Yan 			return (DDI_FAILURE);
740*7ff178cdSJimmy Vetayases 
741*7ff178cdSJimmy Vetayases 		*(int *)result = intrinfo.avgi_cpu_id;
74209b1eac2SEvan Yan 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET "
743*7ff178cdSJimmy Vetayases 		    "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector,
744*7ff178cdSJimmy Vetayases 		    *(int *)result));
74509b1eac2SEvan Yan 		break;
74609b1eac2SEvan Yan 	case DDI_INTROP_SETTARGET:
74709b1eac2SEvan Yan 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n"));
74809b1eac2SEvan Yan 
749*7ff178cdSJimmy Vetayases 		bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
75009b1eac2SEvan Yan 		tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result;
751*7ff178cdSJimmy Vetayases 		tmp_hdl.ih_flags = PSMGI_INTRBY_DEFAULT;
75209b1eac2SEvan Yan 
753*7ff178cdSJimmy Vetayases 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU,
754*7ff178cdSJimmy Vetayases 		    &psm_status) == PSM_FAILURE)
75509b1eac2SEvan Yan 			return (DDI_FAILURE);
756*7ff178cdSJimmy Vetayases 
757*7ff178cdSJimmy Vetayases 		hdlp->ih_vector = tmp_hdl.ih_vector;
758*7ff178cdSJimmy Vetayases 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET "
759*7ff178cdSJimmy Vetayases 		    "vector = 0x%x\n", hdlp->ih_vector));
76009b1eac2SEvan Yan 		break;
761*7ff178cdSJimmy Vetayases 	case DDI_INTROP_GETPOOL:
762*7ff178cdSJimmy Vetayases 		/*
763*7ff178cdSJimmy Vetayases 		 * For MSI/X interrupts use global IRM pool if available.
764*7ff178cdSJimmy Vetayases 		 */
765*7ff178cdSJimmy Vetayases 		if (apix_irm_pool_p && DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
766*7ff178cdSJimmy Vetayases 			*(ddi_irm_pool_t **)result = apix_irm_pool_p;
767*7ff178cdSJimmy Vetayases 			return (DDI_SUCCESS);
768*7ff178cdSJimmy Vetayases 		}
769*7ff178cdSJimmy Vetayases 		return (DDI_ENOTSUP);
77070025d76Sjohnny 	default:
77170025d76Sjohnny 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
77270025d76Sjohnny 	}
77370025d76Sjohnny 
77470025d76Sjohnny 	return (DDI_SUCCESS);
77570025d76Sjohnny }
77670025d76Sjohnny 
777*7ff178cdSJimmy Vetayases /*
778*7ff178cdSJimmy Vetayases  * Allocate a vector for FIXED type interrupt.
779*7ff178cdSJimmy Vetayases  */
780*7ff178cdSJimmy Vetayases int
pci_alloc_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,void * result)781*7ff178cdSJimmy Vetayases pci_alloc_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
782*7ff178cdSJimmy Vetayases     ddi_intr_handle_impl_t *hdlp, void *result)
783*7ff178cdSJimmy Vetayases {
784*7ff178cdSJimmy Vetayases 	struct intrspec		*ispec;
785*7ff178cdSJimmy Vetayases 	ddi_intr_handle_impl_t	info_hdl;
786*7ff178cdSJimmy Vetayases 	int			ret;
787*7ff178cdSJimmy Vetayases 	int			free_phdl = 0;
788*7ff178cdSJimmy Vetayases 	int			pci_rval;
789*7ff178cdSJimmy Vetayases 	int			pci_status = 0;
790*7ff178cdSJimmy Vetayases 	apic_get_type_t		type_info;
791*7ff178cdSJimmy Vetayases 
792*7ff178cdSJimmy Vetayases 	if (psm_intr_ops == NULL)
793*7ff178cdSJimmy Vetayases 		return (DDI_FAILURE);
794*7ff178cdSJimmy Vetayases 
795*7ff178cdSJimmy Vetayases 	/* Figure out if this device supports MASKING */
796*7ff178cdSJimmy Vetayases 	pci_rval = pci_intx_get_cap(rdip, &pci_status);
797*7ff178cdSJimmy Vetayases 	if (pci_rval == DDI_SUCCESS && pci_status)
798*7ff178cdSJimmy Vetayases 		hdlp->ih_cap |= pci_status;
799*7ff178cdSJimmy Vetayases 
800*7ff178cdSJimmy Vetayases 	/*
801*7ff178cdSJimmy Vetayases 	 * If the PSM module is "APIX" then pass the request for
802*7ff178cdSJimmy Vetayases 	 * allocating the vector now.
803*7ff178cdSJimmy Vetayases 	 */
804*7ff178cdSJimmy Vetayases 	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
805*7ff178cdSJimmy Vetayases 	info_hdl.ih_private = &type_info;
806*7ff178cdSJimmy Vetayases 	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
807*7ff178cdSJimmy Vetayases 	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
808*7ff178cdSJimmy Vetayases 		ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
809*7ff178cdSJimmy Vetayases 		    (int)hdlp->ih_inum);
810*7ff178cdSJimmy Vetayases 		if (ispec == NULL)
811*7ff178cdSJimmy Vetayases 			return (DDI_FAILURE);
812*7ff178cdSJimmy Vetayases 		if (hdlp->ih_private == NULL) { /* allocate phdl structure */
813*7ff178cdSJimmy Vetayases 			free_phdl = 1;
814*7ff178cdSJimmy Vetayases 			i_ddi_alloc_intr_phdl(hdlp);
815*7ff178cdSJimmy Vetayases 		}
816*7ff178cdSJimmy Vetayases 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
817*7ff178cdSJimmy Vetayases 		ret = (*psm_intr_ops)(rdip, hdlp,
818*7ff178cdSJimmy Vetayases 		    PSM_INTR_OP_ALLOC_VECTORS, result);
819*7ff178cdSJimmy Vetayases 		if (free_phdl) { /* free up the phdl structure */
820*7ff178cdSJimmy Vetayases 			free_phdl = 0;
821*7ff178cdSJimmy Vetayases 			i_ddi_free_intr_phdl(hdlp);
822*7ff178cdSJimmy Vetayases 			hdlp->ih_private = NULL;
823*7ff178cdSJimmy Vetayases 		}
824*7ff178cdSJimmy Vetayases 	} else {
825*7ff178cdSJimmy Vetayases 		/*
826*7ff178cdSJimmy Vetayases 		 * No APIX module; fall back to the old scheme where the
827*7ff178cdSJimmy Vetayases 		 * interrupt vector is allocated during ddi_enable_intr() call.
828*7ff178cdSJimmy Vetayases 		 */
829*7ff178cdSJimmy Vetayases 		*(int *)result = 1;
830*7ff178cdSJimmy Vetayases 		ret = DDI_SUCCESS;
831*7ff178cdSJimmy Vetayases 	}
832*7ff178cdSJimmy Vetayases 
833*7ff178cdSJimmy Vetayases 	return (ret);
834*7ff178cdSJimmy Vetayases }
835*7ff178cdSJimmy Vetayases 
836*7ff178cdSJimmy Vetayases /*
837*7ff178cdSJimmy Vetayases  * Free up the vector for FIXED (legacy) type interrupt.
838*7ff178cdSJimmy Vetayases  */
839*7ff178cdSJimmy Vetayases static int
pci_free_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)840*7ff178cdSJimmy Vetayases pci_free_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
841*7ff178cdSJimmy Vetayases     ddi_intr_handle_impl_t *hdlp)
842*7ff178cdSJimmy Vetayases {
843*7ff178cdSJimmy Vetayases 	struct intrspec			*ispec;
844*7ff178cdSJimmy Vetayases 	ddi_intr_handle_impl_t		info_hdl;
845*7ff178cdSJimmy Vetayases 	int				ret;
846*7ff178cdSJimmy Vetayases 	apic_get_type_t			type_info;
847*7ff178cdSJimmy Vetayases 
848*7ff178cdSJimmy Vetayases 	if (psm_intr_ops == NULL)
849*7ff178cdSJimmy Vetayases 		return (DDI_FAILURE);
850*7ff178cdSJimmy Vetayases 
851*7ff178cdSJimmy Vetayases 	/*
852*7ff178cdSJimmy Vetayases 	 * If the PSM module is "APIX" then pass the request to it
853*7ff178cdSJimmy Vetayases 	 * to free up the vector now.
854*7ff178cdSJimmy Vetayases 	 */
855*7ff178cdSJimmy Vetayases 	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
856*7ff178cdSJimmy Vetayases 	info_hdl.ih_private = &type_info;
857*7ff178cdSJimmy Vetayases 	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
858*7ff178cdSJimmy Vetayases 	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
859*7ff178cdSJimmy Vetayases 		ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
860*7ff178cdSJimmy Vetayases 		    (int)hdlp->ih_inum);
861*7ff178cdSJimmy Vetayases 		if (ispec == NULL)
862*7ff178cdSJimmy Vetayases 			return (DDI_FAILURE);
863*7ff178cdSJimmy Vetayases 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
864*7ff178cdSJimmy Vetayases 		ret = (*psm_intr_ops)(rdip, hdlp,
865*7ff178cdSJimmy Vetayases 		    PSM_INTR_OP_FREE_VECTORS, NULL);
866*7ff178cdSJimmy Vetayases 	} else {
867*7ff178cdSJimmy Vetayases 		/*
868*7ff178cdSJimmy Vetayases 		 * No APIX module; fall back to the old scheme where
869*7ff178cdSJimmy Vetayases 		 * the interrupt vector was already freed during
870*7ff178cdSJimmy Vetayases 		 * ddi_disable_intr() call.
871*7ff178cdSJimmy Vetayases 		 */
872*7ff178cdSJimmy Vetayases 		ret = DDI_SUCCESS;
873*7ff178cdSJimmy Vetayases 	}
874*7ff178cdSJimmy Vetayases 
875*7ff178cdSJimmy Vetayases 	return (ret);
876*7ff178cdSJimmy Vetayases }
877*7ff178cdSJimmy Vetayases 
8787a364d25Sschwartz int
pci_get_intr_from_vecirq(apic_get_intr_t * intrinfo_p,int vecirq,boolean_t is_irq)8797a364d25Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
8807a364d25Sschwartz     int vecirq, boolean_t is_irq)
8817a364d25Sschwartz {
8827a364d25Sschwartz 	ddi_intr_handle_impl_t	get_info_ii_hdl;
8837a364d25Sschwartz 
8847a364d25Sschwartz 	if (is_irq)
8857a364d25Sschwartz 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
8867a364d25Sschwartz 
8877a364d25Sschwartz 	/*
8887a364d25Sschwartz 	 * For this locally-declared and used handle, ih_private will contain a
8897a364d25Sschwartz 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
8907a364d25Sschwartz 	 * global interrupt handling.
8917a364d25Sschwartz 	 */
8927a364d25Sschwartz 	get_info_ii_hdl.ih_private = intrinfo_p;
893*7ff178cdSJimmy Vetayases 	get_info_ii_hdl.ih_vector = vecirq;
8947a364d25Sschwartz 
8957a364d25Sschwartz 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
8967a364d25Sschwartz 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
8977a364d25Sschwartz 		return (DDI_FAILURE);
8987a364d25Sschwartz 
8997a364d25Sschwartz 	return (DDI_SUCCESS);
9007a364d25Sschwartz }
9017a364d25Sschwartz 
9027a364d25Sschwartz 
9037a364d25Sschwartz int
pci_get_cpu_from_vecirq(int vecirq,boolean_t is_irq)9047a364d25Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
9057a364d25Sschwartz {
9067a364d25Sschwartz 	int rval;
9077a364d25Sschwartz 	apic_get_intr_t	intrinfo;
908*7ff178cdSJimmy Vetayases 
9097a364d25Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
9107a364d25Sschwartz 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
9117a364d25Sschwartz 
9127a364d25Sschwartz 	if (rval == DDI_SUCCESS)
9137a364d25Sschwartz 		return (intrinfo.avgi_cpu_id);
9147a364d25Sschwartz 	else
9157a364d25Sschwartz 		return (-1);
9167a364d25Sschwartz }
9177a364d25Sschwartz 
91870025d76Sjohnny 
91970025d76Sjohnny static int
pci_enable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)92070025d76Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
92170025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
92270025d76Sjohnny {
92370025d76Sjohnny 	struct intrspec	*ispec;
9247a364d25Sschwartz 	int		irq;
9257a364d25Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
92670025d76Sjohnny 
92770025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
92870025d76Sjohnny 	    (void *)hdlp, inum));
92970025d76Sjohnny 
93070025d76Sjohnny 	/* Translate the interrupt if needed */
93170025d76Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9328d9a0e26Sanish 	if (ispec == NULL)
9338d9a0e26Sanish 		return (DDI_FAILURE);
93496f82fefSSophia Li 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
93570025d76Sjohnny 		ispec->intrspec_vec = inum;
93696f82fefSSophia Li 		ispec->intrspec_pri = hdlp->ih_pri;
93796f82fefSSophia Li 	}
9387a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
93970025d76Sjohnny 
94070025d76Sjohnny 	/* translate the interrupt if needed */
94186a9c507SGuoli Shu 	if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) ==
94286a9c507SGuoli Shu 	    PSM_FAILURE)
94386a9c507SGuoli Shu 		return (DDI_FAILURE);
9447a364d25Sschwartz 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
9457a364d25Sschwartz 	    hdlp->ih_pri, irq));
94670025d76Sjohnny 
94770025d76Sjohnny 	/* Add the interrupt handler */
94870025d76Sjohnny 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
9497a364d25Sschwartz 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
9507a364d25Sschwartz 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
95170025d76Sjohnny 		return (DDI_FAILURE);
95270025d76Sjohnny 
953*7ff178cdSJimmy Vetayases 	hdlp->ih_vector = irq;
9547a364d25Sschwartz 
95570025d76Sjohnny 	return (DDI_SUCCESS);
95670025d76Sjohnny }
95770025d76Sjohnny 
95870025d76Sjohnny 
95970025d76Sjohnny static void
pci_disable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)96070025d76Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
96170025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
96270025d76Sjohnny {
9637a364d25Sschwartz 	int		irq;
96470025d76Sjohnny 	struct intrspec	*ispec;
9657a364d25Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
96670025d76Sjohnny 
96770025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
96870025d76Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9698d9a0e26Sanish 	if (ispec == NULL)
9708d9a0e26Sanish 		return;
97196f82fefSSophia Li 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
97270025d76Sjohnny 		ispec->intrspec_vec = inum;
97396f82fefSSophia Li 		ispec->intrspec_pri = hdlp->ih_pri;
97496f82fefSSophia Li 	}
9757a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
97670025d76Sjohnny 
97770025d76Sjohnny 	/* translate the interrupt if needed */
9787a364d25Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
97970025d76Sjohnny 
98070025d76Sjohnny 	/* Disable the interrupt handler */
9817a364d25Sschwartz 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
9827a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = NULL;
98370025d76Sjohnny }
98470025d76Sjohnny 
98570025d76Sjohnny /*
98670025d76Sjohnny  * Miscellaneous library function
98770025d76Sjohnny  */
98870025d76Sjohnny int
pci_common_get_reg_prop(dev_info_t * dip,pci_regspec_t * pci_rp)98970025d76Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
99070025d76Sjohnny {
99170025d76Sjohnny 	int		i;
99270025d76Sjohnny 	int 		number;
99370025d76Sjohnny 	int		assigned_addr_len;
99470025d76Sjohnny 	uint_t		phys_hi = pci_rp->pci_phys_hi;
99570025d76Sjohnny 	pci_regspec_t	*assigned_addr;
99670025d76Sjohnny 
99770025d76Sjohnny 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
99870025d76Sjohnny 	    (phys_hi & PCI_RELOCAT_B))
99970025d76Sjohnny 		return (DDI_SUCCESS);
100070025d76Sjohnny 
100170025d76Sjohnny 	/*
100270025d76Sjohnny 	 * the "reg" property specifies relocatable, get and interpret the
100370025d76Sjohnny 	 * "assigned-addresses" property.
100470025d76Sjohnny 	 */
100570025d76Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
100670025d76Sjohnny 	    "assigned-addresses", (int **)&assigned_addr,
100770025d76Sjohnny 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
100870025d76Sjohnny 		return (DDI_FAILURE);
100970025d76Sjohnny 
101070025d76Sjohnny 	/*
101170025d76Sjohnny 	 * Scan the "assigned-addresses" for one that matches the specified
101270025d76Sjohnny 	 * "reg" property entry.
101370025d76Sjohnny 	 */
101470025d76Sjohnny 	phys_hi &= PCI_CONF_ADDR_MASK;
101570025d76Sjohnny 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
101670025d76Sjohnny 	for (i = 0; i < number; i++) {
101770025d76Sjohnny 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
101870025d76Sjohnny 		    phys_hi) {
101970025d76Sjohnny 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
102070025d76Sjohnny 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
102170025d76Sjohnny 			ddi_prop_free(assigned_addr);
102270025d76Sjohnny 			return (DDI_SUCCESS);
102370025d76Sjohnny 		}
102470025d76Sjohnny 	}
102570025d76Sjohnny 
102670025d76Sjohnny 	ddi_prop_free(assigned_addr);
102770025d76Sjohnny 	return (DDI_FAILURE);
102870025d76Sjohnny }
102970025d76Sjohnny 
103070025d76Sjohnny 
103170025d76Sjohnny /*
103226947304SEvan Yan  * To handle PCI tool ioctls
103370025d76Sjohnny  */
103470025d76Sjohnny 
103526947304SEvan Yan /*ARGSUSED*/
103670025d76Sjohnny int
pci_common_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)103770025d76Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
103870025d76Sjohnny     int mode, cred_t *credp, int *rvalp)
103970025d76Sjohnny {
104026947304SEvan Yan 	minor_t	minor = getminor(dev);
104170025d76Sjohnny 	int	rv = ENOTTY;
104270025d76Sjohnny 
104326947304SEvan Yan 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
104470025d76Sjohnny 	case PCI_TOOL_REG_MINOR_NUM:
104570025d76Sjohnny 
104670025d76Sjohnny 		switch (cmd) {
104770025d76Sjohnny 		case PCITOOL_DEVICE_SET_REG:
104870025d76Sjohnny 		case PCITOOL_DEVICE_GET_REG:
104970025d76Sjohnny 
105070025d76Sjohnny 			/* Require full privileges. */
105170025d76Sjohnny 			if (secpolicy_kmdb(credp))
105270025d76Sjohnny 				rv = EPERM;
105370025d76Sjohnny 			else
105470025d76Sjohnny 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
105570025d76Sjohnny 				    cmd, mode);
105670025d76Sjohnny 			break;
105770025d76Sjohnny 
105870025d76Sjohnny 		case PCITOOL_NEXUS_SET_REG:
105970025d76Sjohnny 		case PCITOOL_NEXUS_GET_REG:
106070025d76Sjohnny 
106170025d76Sjohnny 			/* Require full privileges. */
106270025d76Sjohnny 			if (secpolicy_kmdb(credp))
106370025d76Sjohnny 				rv = EPERM;
106470025d76Sjohnny 			else
106570025d76Sjohnny 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
106670025d76Sjohnny 				    cmd, mode);
106770025d76Sjohnny 			break;
106870025d76Sjohnny 		}
106970025d76Sjohnny 		break;
107070025d76Sjohnny 
107170025d76Sjohnny 	case PCI_TOOL_INTR_MINOR_NUM:
107270025d76Sjohnny 
107370025d76Sjohnny 		switch (cmd) {
107470025d76Sjohnny 		case PCITOOL_DEVICE_SET_INTR:
107570025d76Sjohnny 
107670025d76Sjohnny 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
107770025d76Sjohnny 			if (secpolicy_ponline(credp)) {
107870025d76Sjohnny 				rv = EPERM;
107970025d76Sjohnny 				break;
108070025d76Sjohnny 			}
108170025d76Sjohnny 
108270025d76Sjohnny 		/*FALLTHRU*/
108370025d76Sjohnny 		/* These require no special privileges. */
108470025d76Sjohnny 		case PCITOOL_DEVICE_GET_INTR:
10852917a9c9Sschwartz 		case PCITOOL_SYSTEM_INTR_INFO:
108670025d76Sjohnny 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
108770025d76Sjohnny 			break;
108870025d76Sjohnny 		}
108970025d76Sjohnny 		break;
109070025d76Sjohnny 
109170025d76Sjohnny 	default:
109270025d76Sjohnny 		break;
109370025d76Sjohnny 	}
109470025d76Sjohnny 
109570025d76Sjohnny 	return (rv);
109670025d76Sjohnny }
1097649d4cceSanish 
1098649d4cceSanish 
109900d0963fSdilpreet int
pci_common_ctlops_poke(peekpoke_ctlops_t * in_args)110000d0963fSdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
110100d0963fSdilpreet {
110200d0963fSdilpreet 	size_t size = in_args->size;
110300d0963fSdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
110400d0963fSdilpreet 	uintptr_t host_addr = in_args->host_addr;
110500d0963fSdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
110600d0963fSdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
110700d0963fSdilpreet 	size_t repcount = in_args->repcount;
110800d0963fSdilpreet 	uint_t flags = in_args->flags;
110900d0963fSdilpreet 	int err = DDI_SUCCESS;
111000d0963fSdilpreet 
111100d0963fSdilpreet 	/*
111200d0963fSdilpreet 	 * if no handle then this is a poke. We have to return failure here
111300d0963fSdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
111400d0963fSdilpreet 	 */
111500d0963fSdilpreet 	if (in_args->handle == NULL)
111600d0963fSdilpreet 		return (DDI_FAILURE);
111700d0963fSdilpreet 
111800d0963fSdilpreet 	/*
111900d0963fSdilpreet 	 * rest of this function is actually for cautious puts
112000d0963fSdilpreet 	 */
112100d0963fSdilpreet 	for (; repcount; repcount--) {
112200d0963fSdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
112300d0963fSdilpreet 			switch (size) {
112400d0963fSdilpreet 			case sizeof (uint8_t):
112500d0963fSdilpreet 				pci_config_wr8(hp, (uint8_t *)dev_addr,
112600d0963fSdilpreet 				    *(uint8_t *)host_addr);
112700d0963fSdilpreet 				break;
112800d0963fSdilpreet 			case sizeof (uint16_t):
112900d0963fSdilpreet 				pci_config_wr16(hp, (uint16_t *)dev_addr,
113000d0963fSdilpreet 				    *(uint16_t *)host_addr);
113100d0963fSdilpreet 				break;
113200d0963fSdilpreet 			case sizeof (uint32_t):
113300d0963fSdilpreet 				pci_config_wr32(hp, (uint32_t *)dev_addr,
113400d0963fSdilpreet 				    *(uint32_t *)host_addr);
113500d0963fSdilpreet 				break;
113600d0963fSdilpreet 			case sizeof (uint64_t):
113700d0963fSdilpreet 				pci_config_wr64(hp, (uint64_t *)dev_addr,
113800d0963fSdilpreet 				    *(uint64_t *)host_addr);
113900d0963fSdilpreet 				break;
114000d0963fSdilpreet 			default:
114100d0963fSdilpreet 				err = DDI_FAILURE;
114200d0963fSdilpreet 				break;
114300d0963fSdilpreet 			}
114400d0963fSdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
114500d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
114600d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
114700d0963fSdilpreet 				switch (size) {
114800d0963fSdilpreet 				case sizeof (uint8_t):
114900d0963fSdilpreet 					i_ddi_io_put8(hp,
115000d0963fSdilpreet 					    (uint8_t *)dev_addr,
115100d0963fSdilpreet 					    *(uint8_t *)host_addr);
115200d0963fSdilpreet 					break;
115300d0963fSdilpreet 				case sizeof (uint16_t):
115400d0963fSdilpreet 					i_ddi_io_swap_put16(hp,
115500d0963fSdilpreet 					    (uint16_t *)dev_addr,
115600d0963fSdilpreet 					    *(uint16_t *)host_addr);
115700d0963fSdilpreet 					break;
115800d0963fSdilpreet 				case sizeof (uint32_t):
115900d0963fSdilpreet 					i_ddi_io_swap_put32(hp,
116000d0963fSdilpreet 					    (uint32_t *)dev_addr,
116100d0963fSdilpreet 					    *(uint32_t *)host_addr);
116200d0963fSdilpreet 					break;
116300d0963fSdilpreet 				/*
116400d0963fSdilpreet 				 * note the 64-bit case is a dummy
116500d0963fSdilpreet 				 * function - so no need to swap
116600d0963fSdilpreet 				 */
116700d0963fSdilpreet 				case sizeof (uint64_t):
116800d0963fSdilpreet 					i_ddi_io_put64(hp,
116900d0963fSdilpreet 					    (uint64_t *)dev_addr,
117000d0963fSdilpreet 					    *(uint64_t *)host_addr);
117100d0963fSdilpreet 					break;
117200d0963fSdilpreet 				default:
117300d0963fSdilpreet 					err = DDI_FAILURE;
117400d0963fSdilpreet 					break;
117500d0963fSdilpreet 				}
117600d0963fSdilpreet 			} else {
117700d0963fSdilpreet 				switch (size) {
117800d0963fSdilpreet 				case sizeof (uint8_t):
117900d0963fSdilpreet 					i_ddi_io_put8(hp,
118000d0963fSdilpreet 					    (uint8_t *)dev_addr,
118100d0963fSdilpreet 					    *(uint8_t *)host_addr);
118200d0963fSdilpreet 					break;
118300d0963fSdilpreet 				case sizeof (uint16_t):
118400d0963fSdilpreet 					i_ddi_io_put16(hp,
118500d0963fSdilpreet 					    (uint16_t *)dev_addr,
118600d0963fSdilpreet 					    *(uint16_t *)host_addr);
118700d0963fSdilpreet 					break;
118800d0963fSdilpreet 				case sizeof (uint32_t):
118900d0963fSdilpreet 					i_ddi_io_put32(hp,
119000d0963fSdilpreet 					    (uint32_t *)dev_addr,
119100d0963fSdilpreet 					    *(uint32_t *)host_addr);
119200d0963fSdilpreet 					break;
119300d0963fSdilpreet 				case sizeof (uint64_t):
119400d0963fSdilpreet 					i_ddi_io_put64(hp,
119500d0963fSdilpreet 					    (uint64_t *)dev_addr,
119600d0963fSdilpreet 					    *(uint64_t *)host_addr);
119700d0963fSdilpreet 					break;
119800d0963fSdilpreet 				default:
119900d0963fSdilpreet 					err = DDI_FAILURE;
120000d0963fSdilpreet 					break;
120100d0963fSdilpreet 				}
120200d0963fSdilpreet 			}
120300d0963fSdilpreet 		} else {
120400d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
120500d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
120600d0963fSdilpreet 				switch (size) {
120700d0963fSdilpreet 				case sizeof (uint8_t):
120800d0963fSdilpreet 					*(uint8_t *)dev_addr =
120900d0963fSdilpreet 					    *(uint8_t *)host_addr;
121000d0963fSdilpreet 					break;
121100d0963fSdilpreet 				case sizeof (uint16_t):
121200d0963fSdilpreet 					*(uint16_t *)dev_addr =
121300d0963fSdilpreet 					    ddi_swap16(*(uint16_t *)host_addr);
121400d0963fSdilpreet 					break;
121500d0963fSdilpreet 				case sizeof (uint32_t):
121600d0963fSdilpreet 					*(uint32_t *)dev_addr =
121700d0963fSdilpreet 					    ddi_swap32(*(uint32_t *)host_addr);
121800d0963fSdilpreet 					break;
121900d0963fSdilpreet 				case sizeof (uint64_t):
122000d0963fSdilpreet 					*(uint64_t *)dev_addr =
122100d0963fSdilpreet 					    ddi_swap64(*(uint64_t *)host_addr);
122200d0963fSdilpreet 					break;
122300d0963fSdilpreet 				default:
122400d0963fSdilpreet 					err = DDI_FAILURE;
122500d0963fSdilpreet 					break;
122600d0963fSdilpreet 				}
122700d0963fSdilpreet 			} else {
122800d0963fSdilpreet 				switch (size) {
122900d0963fSdilpreet 				case sizeof (uint8_t):
123000d0963fSdilpreet 					*(uint8_t *)dev_addr =
123100d0963fSdilpreet 					    *(uint8_t *)host_addr;
123200d0963fSdilpreet 					break;
123300d0963fSdilpreet 				case sizeof (uint16_t):
123400d0963fSdilpreet 					*(uint16_t *)dev_addr =
123500d0963fSdilpreet 					    *(uint16_t *)host_addr;
123600d0963fSdilpreet 					break;
123700d0963fSdilpreet 				case sizeof (uint32_t):
123800d0963fSdilpreet 					*(uint32_t *)dev_addr =
123900d0963fSdilpreet 					    *(uint32_t *)host_addr;
124000d0963fSdilpreet 					break;
124100d0963fSdilpreet 				case sizeof (uint64_t):
124200d0963fSdilpreet 					*(uint64_t *)dev_addr =
124300d0963fSdilpreet 					    *(uint64_t *)host_addr;
124400d0963fSdilpreet 					break;
124500d0963fSdilpreet 				default:
124600d0963fSdilpreet 					err = DDI_FAILURE;
124700d0963fSdilpreet 					break;
124800d0963fSdilpreet 				}
124900d0963fSdilpreet 			}
125000d0963fSdilpreet 		}
125100d0963fSdilpreet 		host_addr += size;
125200d0963fSdilpreet 		if (flags == DDI_DEV_AUTOINCR)
125300d0963fSdilpreet 			dev_addr += size;
125400d0963fSdilpreet 	}
125500d0963fSdilpreet 	return (err);
125600d0963fSdilpreet }
125700d0963fSdilpreet 
125800d0963fSdilpreet 
125900d0963fSdilpreet int
pci_fm_acc_setup(ddi_acc_hdl_t * hp,off_t offset,off_t len)126000d0963fSdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
126100d0963fSdilpreet {
126200d0963fSdilpreet 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
126300d0963fSdilpreet 
126400d0963fSdilpreet 	/* endian-ness check */
126500d0963fSdilpreet 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
126600d0963fSdilpreet 		return (DDI_FAILURE);
126700d0963fSdilpreet 
126800d0963fSdilpreet 	/*
126900d0963fSdilpreet 	 * range check
127000d0963fSdilpreet 	 */
127100d0963fSdilpreet 	if ((offset >= PCI_CONF_HDR_SIZE) ||
127200d0963fSdilpreet 	    (len > PCI_CONF_HDR_SIZE) ||
127300d0963fSdilpreet 	    (offset + len > PCI_CONF_HDR_SIZE))
127400d0963fSdilpreet 		return (DDI_FAILURE);
127500d0963fSdilpreet 
127600d0963fSdilpreet 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
127700d0963fSdilpreet 	/*
127800d0963fSdilpreet 	 * always use cautious mechanism for config space gets
127900d0963fSdilpreet 	 */
128000d0963fSdilpreet 	ap->ahi_get8 = i_ddi_caut_get8;
128100d0963fSdilpreet 	ap->ahi_get16 = i_ddi_caut_get16;
128200d0963fSdilpreet 	ap->ahi_get32 = i_ddi_caut_get32;
128300d0963fSdilpreet 	ap->ahi_get64 = i_ddi_caut_get64;
128400d0963fSdilpreet 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
128500d0963fSdilpreet 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
128600d0963fSdilpreet 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
128700d0963fSdilpreet 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
128800d0963fSdilpreet 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
128900d0963fSdilpreet 		ap->ahi_put8 = i_ddi_caut_put8;
129000d0963fSdilpreet 		ap->ahi_put16 = i_ddi_caut_put16;
129100d0963fSdilpreet 		ap->ahi_put32 = i_ddi_caut_put32;
129200d0963fSdilpreet 		ap->ahi_put64 = i_ddi_caut_put64;
129300d0963fSdilpreet 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
129400d0963fSdilpreet 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
129500d0963fSdilpreet 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
129600d0963fSdilpreet 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
129700d0963fSdilpreet 	} else {
129800d0963fSdilpreet 		ap->ahi_put8 = pci_config_wr8;
129900d0963fSdilpreet 		ap->ahi_put16 = pci_config_wr16;
130000d0963fSdilpreet 		ap->ahi_put32 = pci_config_wr32;
130100d0963fSdilpreet 		ap->ahi_put64 = pci_config_wr64;
130200d0963fSdilpreet 		ap->ahi_rep_put8 = pci_config_rep_wr8;
130300d0963fSdilpreet 		ap->ahi_rep_put16 = pci_config_rep_wr16;
130400d0963fSdilpreet 		ap->ahi_rep_put32 = pci_config_rep_wr32;
130500d0963fSdilpreet 		ap->ahi_rep_put64 = pci_config_rep_wr64;
130600d0963fSdilpreet 	}
130700d0963fSdilpreet 
130800d0963fSdilpreet 	/* Initialize to default check/notify functions */
130900d0963fSdilpreet 	ap->ahi_fault_check = i_ddi_acc_fault_check;
131000d0963fSdilpreet 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
131100d0963fSdilpreet 	ap->ahi_fault = 0;
131200d0963fSdilpreet 	impl_acc_err_init(hp);
131300d0963fSdilpreet 	return (DDI_SUCCESS);
131400d0963fSdilpreet }
131500d0963fSdilpreet 
131600d0963fSdilpreet 
131700d0963fSdilpreet int
pci_common_ctlops_peek(peekpoke_ctlops_t * in_args)131800d0963fSdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
131900d0963fSdilpreet {
132000d0963fSdilpreet 	size_t size = in_args->size;
132100d0963fSdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
132200d0963fSdilpreet 	uintptr_t host_addr = in_args->host_addr;
132300d0963fSdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
132400d0963fSdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
132500d0963fSdilpreet 	size_t repcount = in_args->repcount;
132600d0963fSdilpreet 	uint_t flags = in_args->flags;
132700d0963fSdilpreet 	int err = DDI_SUCCESS;
132800d0963fSdilpreet 
132900d0963fSdilpreet 	/*
133000d0963fSdilpreet 	 * if no handle then this is a peek. We have to return failure here
133100d0963fSdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
133200d0963fSdilpreet 	 */
133300d0963fSdilpreet 	if (in_args->handle == NULL)
133400d0963fSdilpreet 		return (DDI_FAILURE);
133500d0963fSdilpreet 
133600d0963fSdilpreet 	for (; repcount; repcount--) {
133700d0963fSdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
133800d0963fSdilpreet 			switch (size) {
133900d0963fSdilpreet 			case sizeof (uint8_t):
134000d0963fSdilpreet 				*(uint8_t *)host_addr = pci_config_rd8(hp,
134100d0963fSdilpreet 				    (uint8_t *)dev_addr);
134200d0963fSdilpreet 				break;
134300d0963fSdilpreet 			case sizeof (uint16_t):
134400d0963fSdilpreet 				*(uint16_t *)host_addr = pci_config_rd16(hp,
134500d0963fSdilpreet 				    (uint16_t *)dev_addr);
134600d0963fSdilpreet 				break;
134700d0963fSdilpreet 			case sizeof (uint32_t):
134800d0963fSdilpreet 				*(uint32_t *)host_addr = pci_config_rd32(hp,
134900d0963fSdilpreet 				    (uint32_t *)dev_addr);
135000d0963fSdilpreet 				break;
135100d0963fSdilpreet 			case sizeof (uint64_t):
135200d0963fSdilpreet 				*(uint64_t *)host_addr = pci_config_rd64(hp,
135300d0963fSdilpreet 				    (uint64_t *)dev_addr);
135400d0963fSdilpreet 				break;
135500d0963fSdilpreet 			default:
135600d0963fSdilpreet 				err = DDI_FAILURE;
135700d0963fSdilpreet 				break;
135800d0963fSdilpreet 			}
135900d0963fSdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
136000d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
136100d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
136200d0963fSdilpreet 				switch (size) {
136300d0963fSdilpreet 				case sizeof (uint8_t):
136400d0963fSdilpreet 					*(uint8_t *)host_addr =
136500d0963fSdilpreet 					    i_ddi_io_get8(hp,
136600d0963fSdilpreet 					    (uint8_t *)dev_addr);
136700d0963fSdilpreet 					break;
136800d0963fSdilpreet 				case sizeof (uint16_t):
136900d0963fSdilpreet 					*(uint16_t *)host_addr =
137000d0963fSdilpreet 					    i_ddi_io_swap_get16(hp,
137100d0963fSdilpreet 					    (uint16_t *)dev_addr);
137200d0963fSdilpreet 					break;
137300d0963fSdilpreet 				case sizeof (uint32_t):
137400d0963fSdilpreet 					*(uint32_t *)host_addr =
137500d0963fSdilpreet 					    i_ddi_io_swap_get32(hp,
137600d0963fSdilpreet 					    (uint32_t *)dev_addr);
137700d0963fSdilpreet 					break;
137800d0963fSdilpreet 				/*
137900d0963fSdilpreet 				 * note the 64-bit case is a dummy
138000d0963fSdilpreet 				 * function - so no need to swap
138100d0963fSdilpreet 				 */
138200d0963fSdilpreet 				case sizeof (uint64_t):
138300d0963fSdilpreet 					*(uint64_t *)host_addr =
138400d0963fSdilpreet 					    i_ddi_io_get64(hp,
138500d0963fSdilpreet 					    (uint64_t *)dev_addr);
138600d0963fSdilpreet 					break;
138700d0963fSdilpreet 				default:
138800d0963fSdilpreet 					err = DDI_FAILURE;
138900d0963fSdilpreet 					break;
139000d0963fSdilpreet 				}
139100d0963fSdilpreet 			} else {
139200d0963fSdilpreet 				switch (size) {
139300d0963fSdilpreet 				case sizeof (uint8_t):
139400d0963fSdilpreet 					*(uint8_t *)host_addr =
139500d0963fSdilpreet 					    i_ddi_io_get8(hp,
139600d0963fSdilpreet 					    (uint8_t *)dev_addr);
139700d0963fSdilpreet 					break;
139800d0963fSdilpreet 				case sizeof (uint16_t):
139900d0963fSdilpreet 					*(uint16_t *)host_addr =
140000d0963fSdilpreet 					    i_ddi_io_get16(hp,
140100d0963fSdilpreet 					    (uint16_t *)dev_addr);
140200d0963fSdilpreet 					break;
140300d0963fSdilpreet 				case sizeof (uint32_t):
140400d0963fSdilpreet 					*(uint32_t *)host_addr =
140500d0963fSdilpreet 					    i_ddi_io_get32(hp,
140600d0963fSdilpreet 					    (uint32_t *)dev_addr);
140700d0963fSdilpreet 					break;
140800d0963fSdilpreet 				case sizeof (uint64_t):
140900d0963fSdilpreet 					*(uint64_t *)host_addr =
141000d0963fSdilpreet 					    i_ddi_io_get64(hp,
141100d0963fSdilpreet 					    (uint64_t *)dev_addr);
141200d0963fSdilpreet 					break;
141300d0963fSdilpreet 				default:
141400d0963fSdilpreet 					err = DDI_FAILURE;
141500d0963fSdilpreet 					break;
141600d0963fSdilpreet 				}
141700d0963fSdilpreet 			}
141800d0963fSdilpreet 		} else {
141900d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
142000d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
142100d0963fSdilpreet 				switch (in_args->size) {
142200d0963fSdilpreet 				case sizeof (uint8_t):
142300d0963fSdilpreet 					*(uint8_t *)host_addr =
142400d0963fSdilpreet 					    *(uint8_t *)dev_addr;
142500d0963fSdilpreet 					break;
142600d0963fSdilpreet 				case sizeof (uint16_t):
142700d0963fSdilpreet 					*(uint16_t *)host_addr =
142800d0963fSdilpreet 					    ddi_swap16(*(uint16_t *)dev_addr);
142900d0963fSdilpreet 					break;
143000d0963fSdilpreet 				case sizeof (uint32_t):
143100d0963fSdilpreet 					*(uint32_t *)host_addr =
143200d0963fSdilpreet 					    ddi_swap32(*(uint32_t *)dev_addr);
143300d0963fSdilpreet 					break;
143400d0963fSdilpreet 				case sizeof (uint64_t):
143500d0963fSdilpreet 					*(uint64_t *)host_addr =
143600d0963fSdilpreet 					    ddi_swap64(*(uint64_t *)dev_addr);
143700d0963fSdilpreet 					break;
143800d0963fSdilpreet 				default:
143900d0963fSdilpreet 					err = DDI_FAILURE;
144000d0963fSdilpreet 					break;
144100d0963fSdilpreet 				}
144200d0963fSdilpreet 			} else {
144300d0963fSdilpreet 				switch (in_args->size) {
144400d0963fSdilpreet 				case sizeof (uint8_t):
144500d0963fSdilpreet 					*(uint8_t *)host_addr =
144600d0963fSdilpreet 					    *(uint8_t *)dev_addr;
144700d0963fSdilpreet 					break;
144800d0963fSdilpreet 				case sizeof (uint16_t):
144900d0963fSdilpreet 					*(uint16_t *)host_addr =
145000d0963fSdilpreet 					    *(uint16_t *)dev_addr;
145100d0963fSdilpreet 					break;
145200d0963fSdilpreet 				case sizeof (uint32_t):
145300d0963fSdilpreet 					*(uint32_t *)host_addr =
145400d0963fSdilpreet 					    *(uint32_t *)dev_addr;
145500d0963fSdilpreet 					break;
145600d0963fSdilpreet 				case sizeof (uint64_t):
145700d0963fSdilpreet 					*(uint64_t *)host_addr =
145800d0963fSdilpreet 					    *(uint64_t *)dev_addr;
145900d0963fSdilpreet 					break;
146000d0963fSdilpreet 				default:
146100d0963fSdilpreet 					err = DDI_FAILURE;
146200d0963fSdilpreet 					break;
146300d0963fSdilpreet 				}
146400d0963fSdilpreet 			}
146500d0963fSdilpreet 		}
146600d0963fSdilpreet 		host_addr += size;
146700d0963fSdilpreet 		if (flags == DDI_DEV_AUTOINCR)
146800d0963fSdilpreet 			dev_addr += size;
146900d0963fSdilpreet 	}
147000d0963fSdilpreet 	return (err);
147100d0963fSdilpreet }
147200d0963fSdilpreet 
147300d0963fSdilpreet /*ARGSUSED*/
147400d0963fSdilpreet int
pci_common_peekpoke(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)147500d0963fSdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
147600d0963fSdilpreet 	ddi_ctl_enum_t ctlop, void *arg, void *result)
147700d0963fSdilpreet {
147800d0963fSdilpreet 	if (ctlop == DDI_CTLOPS_PEEK)
147900d0963fSdilpreet 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
148000d0963fSdilpreet 	else
148100d0963fSdilpreet 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
148200d0963fSdilpreet }
148300d0963fSdilpreet 
1484649d4cceSanish /*
1485649d4cceSanish  * These are the get and put functions to be shared with drivers. The
1486649d4cceSanish  * mutex locking is done inside the functions referenced, rather than
1487649d4cceSanish  * here, and is thus shared across PCI child drivers and any other
1488649d4cceSanish  * consumers of PCI config space (such as the ACPI subsystem).
1489649d4cceSanish  *
1490649d4cceSanish  * The configuration space addresses come in as pointers.  This is fine on
1491649d4cceSanish  * a 32-bit system, where the VM space and configuration space are the same
1492649d4cceSanish  * size.  It's not such a good idea on a 64-bit system, where memory
1493649d4cceSanish  * addresses are twice as large as configuration space addresses.  At some
1494649d4cceSanish  * point in the call tree we need to take a stand and say "you are 32-bit
1495649d4cceSanish  * from this time forth", and this seems like a nice self-contained place.
1496649d4cceSanish  */
1497649d4cceSanish 
1498649d4cceSanish uint8_t
pci_config_rd8(ddi_acc_impl_t * hdlp,uint8_t * addr)1499649d4cceSanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1500649d4cceSanish {
1501649d4cceSanish 	pci_acc_cfblk_t *cfp;
1502649d4cceSanish 	uint8_t	rval;
1503649d4cceSanish 	int reg;
1504649d4cceSanish 
1505649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1506649d4cceSanish 
1507649d4cceSanish 	reg = (int)(uintptr_t)addr;
1508649d4cceSanish 
1509649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1510649d4cceSanish 
1511649d4cceSanish 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1512649d4cceSanish 	    reg);
1513649d4cceSanish 
1514649d4cceSanish 	return (rval);
1515649d4cceSanish }
1516649d4cceSanish 
1517649d4cceSanish void
pci_config_rep_rd8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)1518649d4cceSanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1519649d4cceSanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1520649d4cceSanish {
1521649d4cceSanish 	uint8_t *h, *d;
1522649d4cceSanish 
1523649d4cceSanish 	h = host_addr;
1524649d4cceSanish 	d = dev_addr;
1525649d4cceSanish 
1526649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1527649d4cceSanish 		for (; repcount; repcount--)
1528649d4cceSanish 			*h++ = pci_config_rd8(hdlp, d++);
1529649d4cceSanish 	else
1530649d4cceSanish 		for (; repcount; repcount--)
1531649d4cceSanish 			*h++ = pci_config_rd8(hdlp, d);
1532649d4cceSanish }
1533649d4cceSanish 
1534649d4cceSanish uint16_t
pci_config_rd16(ddi_acc_impl_t * hdlp,uint16_t * addr)1535649d4cceSanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1536649d4cceSanish {
1537649d4cceSanish 	pci_acc_cfblk_t *cfp;
1538649d4cceSanish 	uint16_t rval;
1539649d4cceSanish 	int reg;
1540649d4cceSanish 
1541649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1542649d4cceSanish 
1543649d4cceSanish 	reg = (int)(uintptr_t)addr;
1544649d4cceSanish 
1545649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1546649d4cceSanish 
1547649d4cceSanish 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1548649d4cceSanish 	    reg);
1549649d4cceSanish 
1550649d4cceSanish 	return (rval);
1551649d4cceSanish }
1552649d4cceSanish 
1553649d4cceSanish void
pci_config_rep_rd16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)1554649d4cceSanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1555649d4cceSanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1556649d4cceSanish {
1557649d4cceSanish 	uint16_t *h, *d;
1558649d4cceSanish 
1559649d4cceSanish 	h = host_addr;
1560649d4cceSanish 	d = dev_addr;
1561649d4cceSanish 
1562649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1563649d4cceSanish 		for (; repcount; repcount--)
1564649d4cceSanish 			*h++ = pci_config_rd16(hdlp, d++);
1565649d4cceSanish 	else
1566649d4cceSanish 		for (; repcount; repcount--)
1567649d4cceSanish 			*h++ = pci_config_rd16(hdlp, d);
1568649d4cceSanish }
1569649d4cceSanish 
1570649d4cceSanish uint32_t
pci_config_rd32(ddi_acc_impl_t * hdlp,uint32_t * addr)1571649d4cceSanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1572649d4cceSanish {
1573649d4cceSanish 	pci_acc_cfblk_t *cfp;
1574649d4cceSanish 	uint32_t rval;
1575649d4cceSanish 	int reg;
1576649d4cceSanish 
1577649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1578649d4cceSanish 
1579649d4cceSanish 	reg = (int)(uintptr_t)addr;
1580649d4cceSanish 
1581649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1582649d4cceSanish 
1583649d4cceSanish 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1584649d4cceSanish 	    cfp->c_funcnum, reg);
1585649d4cceSanish 
1586649d4cceSanish 	return (rval);
1587649d4cceSanish }
1588649d4cceSanish 
1589649d4cceSanish void
pci_config_rep_rd32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)1590649d4cceSanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1591649d4cceSanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1592649d4cceSanish {
1593649d4cceSanish 	uint32_t *h, *d;
1594649d4cceSanish 
1595649d4cceSanish 	h = host_addr;
1596649d4cceSanish 	d = dev_addr;
1597649d4cceSanish 
1598649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1599649d4cceSanish 		for (; repcount; repcount--)
1600649d4cceSanish 			*h++ = pci_config_rd32(hdlp, d++);
1601649d4cceSanish 	else
1602649d4cceSanish 		for (; repcount; repcount--)
1603649d4cceSanish 			*h++ = pci_config_rd32(hdlp, d);
1604649d4cceSanish }
1605649d4cceSanish 
1606649d4cceSanish 
1607649d4cceSanish void
pci_config_wr8(ddi_acc_impl_t * hdlp,uint8_t * addr,uint8_t value)1608649d4cceSanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1609649d4cceSanish {
1610649d4cceSanish 	pci_acc_cfblk_t *cfp;
1611649d4cceSanish 	int reg;
1612649d4cceSanish 
1613649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1614649d4cceSanish 
1615649d4cceSanish 	reg = (int)(uintptr_t)addr;
1616649d4cceSanish 
1617649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1618649d4cceSanish 
1619649d4cceSanish 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1620649d4cceSanish 	    cfp->c_funcnum, reg, value);
1621649d4cceSanish }
1622649d4cceSanish 
1623649d4cceSanish void
pci_config_rep_wr8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)1624649d4cceSanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1625649d4cceSanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1626649d4cceSanish {
1627649d4cceSanish 	uint8_t *h, *d;
1628649d4cceSanish 
1629649d4cceSanish 	h = host_addr;
1630649d4cceSanish 	d = dev_addr;
1631649d4cceSanish 
1632649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1633649d4cceSanish 		for (; repcount; repcount--)
1634649d4cceSanish 			pci_config_wr8(hdlp, d++, *h++);
1635649d4cceSanish 	else
1636649d4cceSanish 		for (; repcount; repcount--)
1637649d4cceSanish 			pci_config_wr8(hdlp, d, *h++);
1638649d4cceSanish }
1639649d4cceSanish 
1640649d4cceSanish void
pci_config_wr16(ddi_acc_impl_t * hdlp,uint16_t * addr,uint16_t value)1641649d4cceSanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1642649d4cceSanish {
1643649d4cceSanish 	pci_acc_cfblk_t *cfp;
1644649d4cceSanish 	int reg;
1645649d4cceSanish 
1646649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1647649d4cceSanish 
1648649d4cceSanish 	reg = (int)(uintptr_t)addr;
1649649d4cceSanish 
1650649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1651649d4cceSanish 
1652649d4cceSanish 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1653649d4cceSanish 	    cfp->c_funcnum, reg, value);
1654649d4cceSanish }
1655649d4cceSanish 
1656649d4cceSanish void
pci_config_rep_wr16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)1657649d4cceSanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1658649d4cceSanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1659649d4cceSanish {
1660649d4cceSanish 	uint16_t *h, *d;
1661649d4cceSanish 
1662649d4cceSanish 	h = host_addr;
1663649d4cceSanish 	d = dev_addr;
1664649d4cceSanish 
1665649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1666649d4cceSanish 		for (; repcount; repcount--)
1667649d4cceSanish 			pci_config_wr16(hdlp, d++, *h++);
1668649d4cceSanish 	else
1669649d4cceSanish 		for (; repcount; repcount--)
1670649d4cceSanish 			pci_config_wr16(hdlp, d, *h++);
1671649d4cceSanish }
1672649d4cceSanish 
1673649d4cceSanish void
pci_config_wr32(ddi_acc_impl_t * hdlp,uint32_t * addr,uint32_t value)1674649d4cceSanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1675649d4cceSanish {
1676649d4cceSanish 	pci_acc_cfblk_t *cfp;
1677649d4cceSanish 	int reg;
1678649d4cceSanish 
1679649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1680649d4cceSanish 
1681649d4cceSanish 	reg = (int)(uintptr_t)addr;
1682649d4cceSanish 
1683649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1684649d4cceSanish 
1685649d4cceSanish 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1686649d4cceSanish 	    cfp->c_funcnum, reg, value);
1687649d4cceSanish }
1688649d4cceSanish 
1689649d4cceSanish void
pci_config_rep_wr32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)1690649d4cceSanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1691649d4cceSanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1692649d4cceSanish {
1693649d4cceSanish 	uint32_t *h, *d;
1694649d4cceSanish 
1695649d4cceSanish 	h = host_addr;
1696649d4cceSanish 	d = dev_addr;
1697649d4cceSanish 
1698649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1699649d4cceSanish 		for (; repcount; repcount--)
1700649d4cceSanish 			pci_config_wr32(hdlp, d++, *h++);
1701649d4cceSanish 	else
1702649d4cceSanish 		for (; repcount; repcount--)
1703649d4cceSanish 			pci_config_wr32(hdlp, d, *h++);
1704649d4cceSanish }
1705649d4cceSanish 
1706649d4cceSanish uint64_t
pci_config_rd64(ddi_acc_impl_t * hdlp,uint64_t * addr)1707649d4cceSanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1708649d4cceSanish {
1709649d4cceSanish 	uint32_t lw_val;
1710649d4cceSanish 	uint32_t hi_val;
1711649d4cceSanish 	uint32_t *dp;
1712649d4cceSanish 	uint64_t val;
1713649d4cceSanish 
1714649d4cceSanish 	dp = (uint32_t *)addr;
1715649d4cceSanish 	lw_val = pci_config_rd32(hdlp, dp);
1716649d4cceSanish 	dp++;
1717649d4cceSanish 	hi_val = pci_config_rd32(hdlp, dp);
1718649d4cceSanish 	val = ((uint64_t)hi_val << 32) | lw_val;
1719649d4cceSanish 	return (val);
1720649d4cceSanish }
1721649d4cceSanish 
1722649d4cceSanish void
pci_config_wr64(ddi_acc_impl_t * hdlp,uint64_t * addr,uint64_t value)1723649d4cceSanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1724649d4cceSanish {
1725649d4cceSanish 	uint32_t lw_val;
1726649d4cceSanish 	uint32_t hi_val;
1727649d4cceSanish 	uint32_t *dp;
1728649d4cceSanish 
1729649d4cceSanish 	dp = (uint32_t *)addr;
1730649d4cceSanish 	lw_val = (uint32_t)(value & 0xffffffff);
1731649d4cceSanish 	hi_val = (uint32_t)(value >> 32);
1732649d4cceSanish 	pci_config_wr32(hdlp, dp, lw_val);
1733649d4cceSanish 	dp++;
1734649d4cceSanish 	pci_config_wr32(hdlp, dp, hi_val);
1735649d4cceSanish }
1736649d4cceSanish 
1737649d4cceSanish void
pci_config_rep_rd64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)1738649d4cceSanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1739649d4cceSanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1740649d4cceSanish {
1741649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR) {
1742649d4cceSanish 		for (; repcount; repcount--)
1743649d4cceSanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1744649d4cceSanish 	} else {
1745649d4cceSanish 		for (; repcount; repcount--)
1746649d4cceSanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
1747649d4cceSanish 	}
1748649d4cceSanish }
1749649d4cceSanish 
1750649d4cceSanish void
pci_config_rep_wr64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)1751649d4cceSanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1752649d4cceSanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1753649d4cceSanish {
1754649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR) {
1755649d4cceSanish 		for (; repcount; repcount--)
1756649d4cceSanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1757649d4cceSanish 	} else {
1758649d4cceSanish 		for (; repcount; repcount--)
1759649d4cceSanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
1760649d4cceSanish 	}
1761649d4cceSanish }
1762