xref: /illumos-gate/usr/src/uts/i86pc/io/pci/pci_common.c (revision 614edcae)
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 /*
23*614edcaeSEvan Yan  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2470025d76Sjohnny  * Use is subject to license terms.
2570025d76Sjohnny  */
2670025d76Sjohnny 
2770025d76Sjohnny /*
2870025d76Sjohnny  *	File that has code which is common between pci(7d) and npe(7d)
2970025d76Sjohnny  *	It shares the following:
3070025d76Sjohnny  *	- interrupt code
3170025d76Sjohnny  *	- pci_tools ioctl code
3270025d76Sjohnny  *	- name_child code
3370025d76Sjohnny  *	- set_parent_private_data code
3470025d76Sjohnny  */
3570025d76Sjohnny 
3670025d76Sjohnny #include <sys/conf.h>
3770025d76Sjohnny #include <sys/pci.h>
3870025d76Sjohnny #include <sys/sunndi.h>
397a364d25Sschwartz #include <sys/mach_intr.h>
4070025d76Sjohnny #include <sys/hotplug/pci/pcihp.h>
4170025d76Sjohnny #include <sys/pci_intr_lib.h>
4270025d76Sjohnny #include <sys/psm.h>
4370025d76Sjohnny #include <sys/policy.h>
4470025d76Sjohnny #include <sys/sysmacros.h>
457a364d25Sschwartz #include <sys/clock.h>
46ae115bc7Smrj #include <sys/apic.h>
4770025d76Sjohnny #include <sys/pci_tools.h>
4870025d76Sjohnny #include <io/pci/pci_var.h>
4970025d76Sjohnny #include <io/pci/pci_tools_ext.h>
5070025d76Sjohnny #include <io/pci/pci_common.h>
51649d4cceSanish #include <sys/pci_cfgspace.h>
52649d4cceSanish #include <sys/pci_impl.h>
53600d7745Sjveta #include <sys/pci_cap.h>
5470025d76Sjohnny 
5570025d76Sjohnny /*
5670025d76Sjohnny  * Function prototypes
5770025d76Sjohnny  */
5870025d76Sjohnny static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
5970025d76Sjohnny static int	pci_enable_intr(dev_info_t *, dev_info_t *,
6070025d76Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
6170025d76Sjohnny static void	pci_disable_intr(dev_info_t *, dev_info_t *,
6270025d76Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
6370025d76Sjohnny 
6470025d76Sjohnny /* Extern decalration for pcplusmp module */
6570025d76Sjohnny extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
6670025d76Sjohnny 		    psm_intr_op_t, int *);
6770025d76Sjohnny 
6870025d76Sjohnny /*
6970025d76Sjohnny  * pci_name_child:
7070025d76Sjohnny  *
7170025d76Sjohnny  *	Assign the address portion of the node name
7270025d76Sjohnny  */
7370025d76Sjohnny int
7470025d76Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
7570025d76Sjohnny {
7670025d76Sjohnny 	int		dev, func, length;
7770025d76Sjohnny 	char		**unit_addr;
7870025d76Sjohnny 	uint_t		n;
7970025d76Sjohnny 	pci_regspec_t	*pci_rp;
8070025d76Sjohnny 
8170025d76Sjohnny 	if (ndi_dev_is_persistent_node(child) == 0) {
8270025d76Sjohnny 		/*
8370025d76Sjohnny 		 * For .conf node, use "unit-address" property
8470025d76Sjohnny 		 */
8570025d76Sjohnny 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
8670025d76Sjohnny 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
8770025d76Sjohnny 		    DDI_PROP_SUCCESS) {
8870025d76Sjohnny 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
8970025d76Sjohnny 			    ddi_get_name(child));
9070025d76Sjohnny 			return (DDI_FAILURE);
9170025d76Sjohnny 		}
9270025d76Sjohnny 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
9370025d76Sjohnny 			cmn_err(CE_WARN, "unit-address property in %s.conf"
9470025d76Sjohnny 			    " not well-formed", ddi_get_name(child));
9570025d76Sjohnny 			ddi_prop_free(unit_addr);
9670025d76Sjohnny 			return (DDI_FAILURE);
9770025d76Sjohnny 		}
9870025d76Sjohnny 		(void) snprintf(name, namelen, "%s", *unit_addr);
9970025d76Sjohnny 		ddi_prop_free(unit_addr);
10070025d76Sjohnny 		return (DDI_SUCCESS);
10170025d76Sjohnny 	}
10270025d76Sjohnny 
10370025d76Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
10470025d76Sjohnny 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
10570025d76Sjohnny 		cmn_err(CE_WARN, "cannot find reg property in %s",
10670025d76Sjohnny 		    ddi_get_name(child));
10770025d76Sjohnny 		return (DDI_FAILURE);
10870025d76Sjohnny 	}
10970025d76Sjohnny 
11070025d76Sjohnny 	/* copy the device identifications */
11170025d76Sjohnny 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
11270025d76Sjohnny 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
11370025d76Sjohnny 
11470025d76Sjohnny 	/*
11570025d76Sjohnny 	 * free the memory allocated by ddi_prop_lookup_int_array
11670025d76Sjohnny 	 */
11770025d76Sjohnny 	ddi_prop_free(pci_rp);
11870025d76Sjohnny 
11970025d76Sjohnny 	if (func != 0) {
12070025d76Sjohnny 		(void) snprintf(name, namelen, "%x,%x", dev, func);
12170025d76Sjohnny 	} else {
12270025d76Sjohnny 		(void) snprintf(name, namelen, "%x", dev);
12370025d76Sjohnny 	}
12470025d76Sjohnny 
12570025d76Sjohnny 	return (DDI_SUCCESS);
12670025d76Sjohnny }
12770025d76Sjohnny 
12870025d76Sjohnny /*
12970025d76Sjohnny  * Interrupt related code:
13070025d76Sjohnny  *
13170025d76Sjohnny  * The following busop is common to npe and pci drivers
13270025d76Sjohnny  *	bus_introp
13370025d76Sjohnny  */
13470025d76Sjohnny 
13570025d76Sjohnny /*
13670025d76Sjohnny  * Create the ddi_parent_private_data for a pseudo child.
13770025d76Sjohnny  */
13870025d76Sjohnny void
13970025d76Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
14070025d76Sjohnny {
14170025d76Sjohnny 	struct ddi_parent_private_data *pdptr;
14270025d76Sjohnny 
14370025d76Sjohnny 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
14470025d76Sjohnny 	    (sizeof (struct ddi_parent_private_data) +
14570025d76Sjohnny 	    sizeof (struct intrspec)), KM_SLEEP);
14670025d76Sjohnny 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
14770025d76Sjohnny 	pdptr->par_nintr = 1;
14870025d76Sjohnny 	ddi_set_parent_data(dip, pdptr);
14970025d76Sjohnny }
15070025d76Sjohnny 
15170025d76Sjohnny /*
15270025d76Sjohnny  * pci_get_priority:
15370025d76Sjohnny  *	Figure out the priority of the device
15470025d76Sjohnny  */
15570025d76Sjohnny static int
15670025d76Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
15770025d76Sjohnny {
15870025d76Sjohnny 	struct intrspec *ispec;
15970025d76Sjohnny 
16070025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
16170025d76Sjohnny 	    (void *)dip, (void *)hdlp));
16270025d76Sjohnny 
16370025d76Sjohnny 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
16470025d76Sjohnny 	    hdlp->ih_inum)) == NULL) {
16570025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
166*614edcaeSEvan Yan 			*pri = pci_class_to_pil(dip);
16770025d76Sjohnny 			pci_common_set_parent_private_data(hdlp->ih_dip);
16870025d76Sjohnny 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
16970025d76Sjohnny 			    hdlp->ih_inum);
17070025d76Sjohnny 			return (DDI_SUCCESS);
17170025d76Sjohnny 		}
17270025d76Sjohnny 		return (DDI_FAILURE);
17370025d76Sjohnny 	}
17470025d76Sjohnny 
17570025d76Sjohnny 	*pri = ispec->intrspec_pri;
17670025d76Sjohnny 	return (DDI_SUCCESS);
17770025d76Sjohnny }
17870025d76Sjohnny 
17970025d76Sjohnny 
18070025d76Sjohnny 
18170025d76Sjohnny static int pcie_pci_intr_pri_counter = 0;
18270025d76Sjohnny 
18370025d76Sjohnny /*
18470025d76Sjohnny  * pci_common_intr_ops: bus_intr_op() function for interrupt support
18570025d76Sjohnny  */
18670025d76Sjohnny int
18770025d76Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
18870025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
18970025d76Sjohnny {
19070025d76Sjohnny 	int			priority = 0;
19170025d76Sjohnny 	int			psm_status = 0;
19270025d76Sjohnny 	int			pci_status = 0;
19370025d76Sjohnny 	int			pci_rval, psm_rval = PSM_FAILURE;
19470025d76Sjohnny 	int			types = 0;
19570025d76Sjohnny 	int			pciepci = 0;
196102cb92eSjohnny 	int			i, j, count;
197600d7745Sjveta 	int			rv;
19870025d76Sjohnny 	int			behavior;
199d12abe7cSanish 	int			cap_ptr;
200600d7745Sjveta 	uint16_t		msi_cap_base, msix_cap_base, cap_ctrl;
201600d7745Sjveta 	char			*prop;
20270025d76Sjohnny 	ddi_intrspec_t		isp;
20370025d76Sjohnny 	struct intrspec		*ispec;
20470025d76Sjohnny 	ddi_intr_handle_impl_t	tmp_hdl;
20570025d76Sjohnny 	ddi_intr_msix_t		*msix_p;
206e1d9f4e6Sschwartz 	ihdl_plat_t		*ihdl_plat_datap;
207102cb92eSjohnny 	ddi_intr_handle_t	*h_array;
208d12abe7cSanish 	ddi_acc_handle_t	handle;
20970025d76Sjohnny 
21070025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT,
21170025d76Sjohnny 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
21270025d76Sjohnny 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
21370025d76Sjohnny 
21470025d76Sjohnny 	/* Process the request */
21570025d76Sjohnny 	switch (intr_op) {
21670025d76Sjohnny 	case DDI_INTROP_SUPPORTED_TYPES:
21720036fe5Segillett 		/*
218600d7745Sjveta 		 * First we determine the interrupt types supported by the
219600d7745Sjveta 		 * device itself, then we filter them through what the OS
220600d7745Sjveta 		 * and system supports.  We determine system-level
221600d7745Sjveta 		 * interrupt type support for anything other than fixed intrs
222600d7745Sjveta 		 * through the psm_intr_ops vector
22320036fe5Segillett 		 */
224600d7745Sjveta 		rv = DDI_FAILURE;
22570025d76Sjohnny 
226600d7745Sjveta 		/* Fixed supported by default */
227600d7745Sjveta 		types = DDI_INTR_TYPE_FIXED;
228600d7745Sjveta 
229600d7745Sjveta 		if (psm_intr_ops == NULL) {
230600d7745Sjveta 			*(int *)result = types;
231600d7745Sjveta 			return (DDI_SUCCESS);
232600d7745Sjveta 		}
233600d7745Sjveta 		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
234600d7745Sjveta 			return (DDI_FAILURE);
235600d7745Sjveta 
236600d7745Sjveta 		/* Sanity test cap control values if found */
237600d7745Sjveta 
238600d7745Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
239600d7745Sjveta 		    DDI_SUCCESS) {
240600d7745Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
241600d7745Sjveta 			    PCI_MSI_CTRL);
242600d7745Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
243600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
244600d7745Sjveta 
245600d7745Sjveta 			types |= DDI_INTR_TYPE_MSI;
246600d7745Sjveta 		}
247600d7745Sjveta 
248600d7745Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
249600d7745Sjveta 		    DDI_SUCCESS) {
250600d7745Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
251600d7745Sjveta 			    PCI_MSIX_CTRL);
252600d7745Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
253600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
254600d7745Sjveta 
255600d7745Sjveta 			types |= DDI_INTR_TYPE_MSIX;
256600d7745Sjveta 		}
257600d7745Sjveta 
258600d7745Sjveta 		/*
259600d7745Sjveta 		 * Filter device-level types through system-level support
260600d7745Sjveta 		 */
261600d7745Sjveta 		tmp_hdl.ih_type = types;
262600d7745Sjveta 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
263600d7745Sjveta 		    &types) != PSM_SUCCESS)
264600d7745Sjveta 			goto SUPPORTED_TYPES_OUT;
265600d7745Sjveta 
26670025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
26770025d76Sjohnny 		    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
26870025d76Sjohnny 		    *(int *)result));
269600d7745Sjveta 
270600d7745Sjveta 		/*
271600d7745Sjveta 		 * Export any MSI/MSI-X cap locations via properties
272600d7745Sjveta 		 */
273600d7745Sjveta 		if (types & DDI_INTR_TYPE_MSI) {
274600d7745Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
275600d7745Sjveta 			    "pci-msi-capid-pointer", (int)msi_cap_base) !=
276600d7745Sjveta 			    DDI_PROP_SUCCESS)
277600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
27870025d76Sjohnny 		}
279600d7745Sjveta 		if (types & DDI_INTR_TYPE_MSIX) {
280600d7745Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
281600d7745Sjveta 			    "pci-msix-capid-pointer", (int)msix_cap_base) !=
282600d7745Sjveta 			    DDI_PROP_SUCCESS)
283600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
284600d7745Sjveta 		}
285600d7745Sjveta 
286600d7745Sjveta 		rv = DDI_SUCCESS;
287600d7745Sjveta 
288600d7745Sjveta SUPPORTED_TYPES_OUT:
289600d7745Sjveta 		*(int *)result = types;
290600d7745Sjveta 		pci_config_teardown(&handle);
291600d7745Sjveta 		return (rv);
292600d7745Sjveta 
293a54f81fbSanish 	case DDI_INTROP_NAVAIL:
29470025d76Sjohnny 	case DDI_INTROP_NINTRS:
295a54f81fbSanish 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
296a54f81fbSanish 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
297a54f81fbSanish 			    result) != DDI_SUCCESS)
29870025d76Sjohnny 				return (DDI_FAILURE);
299a54f81fbSanish 		} else {
300a54f81fbSanish 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
301a54f81fbSanish 			if (*(int *)result == 0)
302a54f81fbSanish 				return (DDI_FAILURE);
303a54f81fbSanish 		}
30470025d76Sjohnny 		break;
30570025d76Sjohnny 	case DDI_INTROP_ALLOC:
30670025d76Sjohnny 		/*
30770025d76Sjohnny 		 * MSI or MSIX (figure out number of vectors available)
30870025d76Sjohnny 		 * FIXED interrupts: just return available interrupts
30970025d76Sjohnny 		 */
31070025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
31170025d76Sjohnny 		    (psm_intr_ops != NULL) &&
31270025d76Sjohnny 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
31370025d76Sjohnny 			/*
31470025d76Sjohnny 			 * Following check is a special case for 'pcie_pci'.
31570025d76Sjohnny 			 * This makes sure vectors with the right priority
31670025d76Sjohnny 			 * are allocated for pcie_pci during ALLOC time.
31770025d76Sjohnny 			 */
31870025d76Sjohnny 			if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) {
31970025d76Sjohnny 				hdlp->ih_pri =
32070025d76Sjohnny 				    (pcie_pci_intr_pri_counter % 2) ? 4 : 7;
32170025d76Sjohnny 				pciepci = 1;
32270025d76Sjohnny 			} else
32370025d76Sjohnny 				hdlp->ih_pri = priority;
32480ab886dSwesolows 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
325d12abe7cSanish 
326d12abe7cSanish 			/*
327d12abe7cSanish 			 * Cache in the config handle and cap_ptr
328d12abe7cSanish 			 */
329d12abe7cSanish 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
330d12abe7cSanish 				if (pci_config_setup(rdip, &handle) !=
331d12abe7cSanish 				    DDI_SUCCESS)
332d12abe7cSanish 					return (DDI_FAILURE);
333d12abe7cSanish 				i_ddi_set_pci_config_handle(rdip, handle);
334d12abe7cSanish 			}
335d12abe7cSanish 
336600d7745Sjveta 			prop = NULL;
337600d7745Sjveta 			cap_ptr = 0;
338600d7745Sjveta 			if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
339600d7745Sjveta 				prop = "pci-msi-capid-pointer";
340600d7745Sjveta 			else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
341600d7745Sjveta 				prop = "pci-msix-capid-pointer";
342d12abe7cSanish 
343600d7745Sjveta 			/*
344600d7745Sjveta 			 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
345600d7745Sjveta 			 * for MSI(X) before allocation
346600d7745Sjveta 			 */
347600d7745Sjveta 			if (prop != NULL) {
348d12abe7cSanish 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
349600d7745Sjveta 				    DDI_PROP_DONTPASS, prop, 0);
350600d7745Sjveta 				if (cap_ptr == 0) {
351600d7745Sjveta 					DDI_INTR_NEXDBG((CE_CONT,
352600d7745Sjveta 					    "pci_common_intr_ops: rdip: 0x%p "
353600d7745Sjveta 					    "attempted MSI(X) alloc without "
354600d7745Sjveta 					    "cap property\n", (void *)rdip));
355600d7745Sjveta 					return (DDI_FAILURE);
356d12abe7cSanish 				}
357600d7745Sjveta 			}
358600d7745Sjveta 			i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
359d12abe7cSanish 
360600d7745Sjveta 			/*
361600d7745Sjveta 			 * Allocate interrupt vectors
362600d7745Sjveta 			 */
36370025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
36470025d76Sjohnny 			    PSM_INTR_OP_ALLOC_VECTORS, result);
36570025d76Sjohnny 
3661ac1709fSanish 			if (*(int *)result == 0)
3671ac1709fSanish 				return (DDI_INTR_NOTFOUND);
3681ac1709fSanish 
36970025d76Sjohnny 			/* verify behavior flag and take appropriate action */
37070025d76Sjohnny 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
37170025d76Sjohnny 			    (*(int *)result < hdlp->ih_scratch1)) {
37270025d76Sjohnny 				DDI_INTR_NEXDBG((CE_CONT,
37370025d76Sjohnny 				    "pci_common_intr_ops: behavior %x, "
37470025d76Sjohnny 				    "couldn't get enough intrs\n", behavior));
37570025d76Sjohnny 				hdlp->ih_scratch1 = *(int *)result;
37670025d76Sjohnny 				(void) (*psm_intr_ops)(rdip, hdlp,
37770025d76Sjohnny 				    PSM_INTR_OP_FREE_VECTORS, NULL);
37870025d76Sjohnny 				return (DDI_EAGAIN);
37970025d76Sjohnny 			}
38070025d76Sjohnny 
38170025d76Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
38270025d76Sjohnny 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
38370025d76Sjohnny 					msix_p = pci_msix_init(hdlp->ih_dip);
38470025d76Sjohnny 					if (msix_p)
38570025d76Sjohnny 						i_ddi_set_msix(hdlp->ih_dip,
38670025d76Sjohnny 						    msix_p);
38770025d76Sjohnny 				}
38870025d76Sjohnny 			}
38970025d76Sjohnny 
39070025d76Sjohnny 			if (pciepci) {
39170025d76Sjohnny 				/* update priority in ispec */
39270025d76Sjohnny 				isp = pci_intx_get_ispec(pdip, rdip,
39370025d76Sjohnny 				    (int)hdlp->ih_inum);
39470025d76Sjohnny 				ispec = (struct intrspec *)isp;
39570025d76Sjohnny 				if (ispec)
39670025d76Sjohnny 					ispec->intrspec_pri = hdlp->ih_pri;
39770025d76Sjohnny 				++pcie_pci_intr_pri_counter;
39870025d76Sjohnny 			}
39970025d76Sjohnny 
40070025d76Sjohnny 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
40170025d76Sjohnny 			/* Figure out if this device supports MASKING */
40270025d76Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
40370025d76Sjohnny 			if (pci_rval == DDI_SUCCESS && pci_status)
40470025d76Sjohnny 				hdlp->ih_cap |= pci_status;
40570025d76Sjohnny 			*(int *)result = 1;	/* DDI_INTR_TYPE_FIXED */
40670025d76Sjohnny 		} else
40770025d76Sjohnny 			return (DDI_FAILURE);
40870025d76Sjohnny 		break;
40970025d76Sjohnny 	case DDI_INTROP_FREE:
41070025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
41170025d76Sjohnny 		    (psm_intr_ops != NULL)) {
41268565200Sanish 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
41368565200Sanish 			    0) {
414d12abe7cSanish 				if (handle = i_ddi_get_pci_config_handle(
415d12abe7cSanish 				    rdip)) {
416d12abe7cSanish 					(void) pci_config_teardown(&handle);
417d12abe7cSanish 					i_ddi_set_pci_config_handle(rdip, NULL);
418d12abe7cSanish 				}
419d12abe7cSanish 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
420d12abe7cSanish 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
421d12abe7cSanish 			}
422d12abe7cSanish 
42370025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
42470025d76Sjohnny 			    PSM_INTR_OP_FREE_VECTORS, NULL);
42570025d76Sjohnny 
42670025d76Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
42770025d76Sjohnny 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
42870025d76Sjohnny 				if (msix_p &&
42968565200Sanish 				    (i_ddi_intr_get_current_nintrs(
43068565200Sanish 				    hdlp->ih_dip) - 1) == 0) {
43170025d76Sjohnny 					pci_msix_fini(msix_p);
43270025d76Sjohnny 					i_ddi_set_msix(hdlp->ih_dip, NULL);
43370025d76Sjohnny 				}
43470025d76Sjohnny 			}
43570025d76Sjohnny 		}
43670025d76Sjohnny 		break;
43770025d76Sjohnny 	case DDI_INTROP_GETPRI:
43870025d76Sjohnny 		/* Get the priority */
43970025d76Sjohnny 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
44070025d76Sjohnny 			return (DDI_FAILURE);
44170025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
44270025d76Sjohnny 		    "priority = 0x%x\n", priority));
44370025d76Sjohnny 		*(int *)result = priority;
44470025d76Sjohnny 		break;
44570025d76Sjohnny 	case DDI_INTROP_SETPRI:
44670025d76Sjohnny 		/* Validate the interrupt priority passed */
44770025d76Sjohnny 		if (*(int *)result > LOCK_LEVEL)
44870025d76Sjohnny 			return (DDI_FAILURE);
44970025d76Sjohnny 
45070025d76Sjohnny 		/* Ensure that PSM is all initialized */
45170025d76Sjohnny 		if (psm_intr_ops == NULL)
45270025d76Sjohnny 			return (DDI_FAILURE);
45370025d76Sjohnny 
45470025d76Sjohnny 		/* Change the priority */
45570025d76Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
45670025d76Sjohnny 		    PSM_FAILURE)
45770025d76Sjohnny 			return (DDI_FAILURE);
45870025d76Sjohnny 
45970025d76Sjohnny 		/* update ispec */
46070025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
46170025d76Sjohnny 		ispec = (struct intrspec *)isp;
46270025d76Sjohnny 		if (ispec)
46370025d76Sjohnny 			ispec->intrspec_pri = *(int *)result;
46470025d76Sjohnny 		break;
46570025d76Sjohnny 	case DDI_INTROP_ADDISR:
46670025d76Sjohnny 		/* update ispec */
46770025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
46870025d76Sjohnny 		ispec = (struct intrspec *)isp;
469e1d9f4e6Sschwartz 		if (ispec) {
47070025d76Sjohnny 			ispec->intrspec_func = hdlp->ih_cb_func;
471e1d9f4e6Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
472e1d9f4e6Sschwartz 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
473e1d9f4e6Sschwartz 		}
47470025d76Sjohnny 		break;
47570025d76Sjohnny 	case DDI_INTROP_REMISR:
47670025d76Sjohnny 		/* Get the interrupt structure pointer */
47770025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
47870025d76Sjohnny 		ispec = (struct intrspec *)isp;
479e1d9f4e6Sschwartz 		if (ispec) {
48070025d76Sjohnny 			ispec->intrspec_func = (uint_t (*)()) 0;
481e1d9f4e6Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
482e1d9f4e6Sschwartz 			if (ihdl_plat_datap->ip_ksp != NULL)
483e1d9f4e6Sschwartz 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
484e1d9f4e6Sschwartz 		}
48570025d76Sjohnny 		break;
48670025d76Sjohnny 	case DDI_INTROP_GETCAP:
48770025d76Sjohnny 		/*
48870025d76Sjohnny 		 * First check the config space and/or
48970025d76Sjohnny 		 * MSI capability register(s)
49070025d76Sjohnny 		 */
49170025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
49270025d76Sjohnny 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
49370025d76Sjohnny 			    &pci_status);
49470025d76Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
49570025d76Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
49670025d76Sjohnny 
49770025d76Sjohnny 		/* next check with pcplusmp */
49870025d76Sjohnny 		if (psm_intr_ops != NULL)
49970025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
50070025d76Sjohnny 			    PSM_INTR_OP_GET_CAP, &psm_status);
50170025d76Sjohnny 
50270025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
50370025d76Sjohnny 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
50470025d76Sjohnny 		    psm_rval, psm_status, pci_rval, pci_status));
50570025d76Sjohnny 
50670025d76Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
50770025d76Sjohnny 			*(int *)result = 0;
50870025d76Sjohnny 			return (DDI_FAILURE);
50970025d76Sjohnny 		}
51070025d76Sjohnny 
51170025d76Sjohnny 		if (psm_rval == PSM_SUCCESS)
51270025d76Sjohnny 			*(int *)result = psm_status;
51370025d76Sjohnny 
51470025d76Sjohnny 		if (pci_rval == DDI_SUCCESS)
51570025d76Sjohnny 			*(int *)result |= pci_status;
51670025d76Sjohnny 
51770025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
51870025d76Sjohnny 		    *(int *)result));
51970025d76Sjohnny 		break;
52070025d76Sjohnny 	case DDI_INTROP_SETCAP:
52170025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
52270025d76Sjohnny 		    "SETCAP cap=0x%x\n", *(int *)result));
52370025d76Sjohnny 		if (psm_intr_ops == NULL)
52470025d76Sjohnny 			return (DDI_FAILURE);
52570025d76Sjohnny 
52670025d76Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
52770025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
52870025d76Sjohnny 			    " returned failure\n"));
52970025d76Sjohnny 			return (DDI_FAILURE);
53070025d76Sjohnny 		}
53170025d76Sjohnny 		break;
53270025d76Sjohnny 	case DDI_INTROP_ENABLE:
53370025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
53470025d76Sjohnny 		if (psm_intr_ops == NULL)
53570025d76Sjohnny 			return (DDI_FAILURE);
53670025d76Sjohnny 
53770025d76Sjohnny 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
53870025d76Sjohnny 		    DDI_SUCCESS)
53970025d76Sjohnny 			return (DDI_FAILURE);
54070025d76Sjohnny 
54170025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
54270025d76Sjohnny 		    "vector=0x%x\n", hdlp->ih_vector));
54370025d76Sjohnny 		break;
54470025d76Sjohnny 	case DDI_INTROP_DISABLE:
54570025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
54670025d76Sjohnny 		if (psm_intr_ops == NULL)
54770025d76Sjohnny 			return (DDI_FAILURE);
54870025d76Sjohnny 
54970025d76Sjohnny 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
55070025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
55170025d76Sjohnny 		    "vector = %x\n", hdlp->ih_vector));
55270025d76Sjohnny 		break;
55370025d76Sjohnny 	case DDI_INTROP_BLOCKENABLE:
55470025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
55570025d76Sjohnny 		    "BLOCKENABLE\n"));
55670025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
55770025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
55870025d76Sjohnny 			return (DDI_FAILURE);
55970025d76Sjohnny 		}
56070025d76Sjohnny 
56170025d76Sjohnny 		/* Check if psm_intr_ops is NULL? */
56270025d76Sjohnny 		if (psm_intr_ops == NULL)
56370025d76Sjohnny 			return (DDI_FAILURE);
56470025d76Sjohnny 
565102cb92eSjohnny 		count = hdlp->ih_scratch1;
566102cb92eSjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
567102cb92eSjohnny 		for (i = 0; i < count; i++) {
568102cb92eSjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
56970025d76Sjohnny 			if (pci_enable_intr(pdip, rdip, hdlp,
570102cb92eSjohnny 			    hdlp->ih_inum) != DDI_SUCCESS) {
57170025d76Sjohnny 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
57270025d76Sjohnny 				    "pci_enable_intr failed for %d\n", i));
573102cb92eSjohnny 				for (j = 0; j < i; j++) {
5742917a9c9Sschwartz 					hdlp = (ddi_intr_handle_impl_t *)
5752917a9c9Sschwartz 					    h_array[j];
57670025d76Sjohnny 					pci_disable_intr(pdip, rdip, hdlp,
577102cb92eSjohnny 					    hdlp->ih_inum);
578102cb92eSjohnny 				}
57970025d76Sjohnny 				return (DDI_FAILURE);
58070025d76Sjohnny 			}
58170025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
582102cb92eSjohnny 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
58370025d76Sjohnny 		}
58470025d76Sjohnny 		break;
58570025d76Sjohnny 	case DDI_INTROP_BLOCKDISABLE:
58670025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
58770025d76Sjohnny 		    "BLOCKDISABLE\n"));
58870025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
58970025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
59070025d76Sjohnny 			return (DDI_FAILURE);
59170025d76Sjohnny 		}
59270025d76Sjohnny 
59370025d76Sjohnny 		/* Check if psm_intr_ops is present */
59470025d76Sjohnny 		if (psm_intr_ops == NULL)
59570025d76Sjohnny 			return (DDI_FAILURE);
59670025d76Sjohnny 
597102cb92eSjohnny 		count = hdlp->ih_scratch1;
598102cb92eSjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
599102cb92eSjohnny 		for (i = 0; i < count; i++) {
600102cb92eSjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
601102cb92eSjohnny 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
60270025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
603102cb92eSjohnny 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
60470025d76Sjohnny 		}
60570025d76Sjohnny 		break;
60670025d76Sjohnny 	case DDI_INTROP_SETMASK:
60770025d76Sjohnny 	case DDI_INTROP_CLRMASK:
60870025d76Sjohnny 		/*
60970025d76Sjohnny 		 * First handle in the config space
61070025d76Sjohnny 		 */
61170025d76Sjohnny 		if (intr_op == DDI_INTROP_SETMASK) {
61270025d76Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
61370025d76Sjohnny 				pci_status = pci_msi_set_mask(rdip,
61470025d76Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
61570025d76Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
61670025d76Sjohnny 				pci_status = pci_intx_set_mask(rdip);
61770025d76Sjohnny 		} else {
61870025d76Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
61970025d76Sjohnny 				pci_status = pci_msi_clr_mask(rdip,
62070025d76Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
62170025d76Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
62270025d76Sjohnny 				pci_status = pci_intx_clr_mask(rdip);
62370025d76Sjohnny 		}
62470025d76Sjohnny 
62570025d76Sjohnny 		/* For MSI/X; no need to check with pcplusmp */
62670025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
62770025d76Sjohnny 			return (pci_status);
62870025d76Sjohnny 
62970025d76Sjohnny 		/* For fixed interrupts only: handle config space first */
63070025d76Sjohnny 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
63170025d76Sjohnny 		    pci_status == DDI_SUCCESS)
63270025d76Sjohnny 			break;
63370025d76Sjohnny 
63470025d76Sjohnny 		/* For fixed interrupts only: confer with pcplusmp next */
63570025d76Sjohnny 		if (psm_intr_ops != NULL) {
63670025d76Sjohnny 			/* If interrupt is shared; do nothing */
63770025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
63870025d76Sjohnny 			    PSM_INTR_OP_GET_SHARED, &psm_status);
63970025d76Sjohnny 
64070025d76Sjohnny 			if (psm_rval == PSM_FAILURE || psm_status == 1)
64170025d76Sjohnny 				return (pci_status);
64270025d76Sjohnny 
64370025d76Sjohnny 			/* Now, pcplusmp should try to set/clear the mask */
64470025d76Sjohnny 			if (intr_op == DDI_INTROP_SETMASK)
64570025d76Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
64670025d76Sjohnny 				    PSM_INTR_OP_SET_MASK, NULL);
64770025d76Sjohnny 			else
64870025d76Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
64970025d76Sjohnny 				    PSM_INTR_OP_CLEAR_MASK, NULL);
65070025d76Sjohnny 		}
65170025d76Sjohnny 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
65270025d76Sjohnny 	case DDI_INTROP_GETPENDING:
65370025d76Sjohnny 		/*
65470025d76Sjohnny 		 * First check the config space and/or
65570025d76Sjohnny 		 * MSI capability register(s)
65670025d76Sjohnny 		 */
65770025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
65870025d76Sjohnny 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
65970025d76Sjohnny 			    hdlp->ih_inum, &pci_status);
66070025d76Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
66170025d76Sjohnny 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
66270025d76Sjohnny 
66370025d76Sjohnny 		/* On failure; next try with pcplusmp */
66470025d76Sjohnny 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
66570025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
66670025d76Sjohnny 			    PSM_INTR_OP_GET_PENDING, &psm_status);
66770025d76Sjohnny 
66870025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
66970025d76Sjohnny 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
67070025d76Sjohnny 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
67170025d76Sjohnny 		    pci_status));
67270025d76Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
67370025d76Sjohnny 			*(int *)result = 0;
67470025d76Sjohnny 			return (DDI_FAILURE);
67570025d76Sjohnny 		}
67670025d76Sjohnny 
67770025d76Sjohnny 		if (psm_rval != PSM_FAILURE)
67870025d76Sjohnny 			*(int *)result = psm_status;
67970025d76Sjohnny 		else if (pci_rval != DDI_FAILURE)
68070025d76Sjohnny 			*(int *)result = pci_status;
68170025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
68270025d76Sjohnny 		    *(int *)result));
68370025d76Sjohnny 		break;
68470025d76Sjohnny 	default:
68570025d76Sjohnny 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
68670025d76Sjohnny 	}
68770025d76Sjohnny 
68870025d76Sjohnny 	return (DDI_SUCCESS);
68970025d76Sjohnny }
69070025d76Sjohnny 
6917a364d25Sschwartz int
6927a364d25Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
6937a364d25Sschwartz     int vecirq, boolean_t is_irq)
6947a364d25Sschwartz {
6957a364d25Sschwartz 	ddi_intr_handle_impl_t	get_info_ii_hdl;
6967a364d25Sschwartz 
6977a364d25Sschwartz 	if (is_irq)
6987a364d25Sschwartz 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
6997a364d25Sschwartz 
7007a364d25Sschwartz 	/*
7017a364d25Sschwartz 	 * For this locally-declared and used handle, ih_private will contain a
7027a364d25Sschwartz 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
7037a364d25Sschwartz 	 * global interrupt handling.
7047a364d25Sschwartz 	 */
7057a364d25Sschwartz 	get_info_ii_hdl.ih_private = intrinfo_p;
7067a364d25Sschwartz 	get_info_ii_hdl.ih_vector = (ushort_t)vecirq;
7077a364d25Sschwartz 
7087a364d25Sschwartz 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
7097a364d25Sschwartz 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
7107a364d25Sschwartz 		return (DDI_FAILURE);
7117a364d25Sschwartz 
7127a364d25Sschwartz 	return (DDI_SUCCESS);
7137a364d25Sschwartz }
7147a364d25Sschwartz 
7157a364d25Sschwartz 
7167a364d25Sschwartz int
7177a364d25Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
7187a364d25Sschwartz {
7197a364d25Sschwartz 	int rval;
7207a364d25Sschwartz 
7217a364d25Sschwartz 	apic_get_intr_t	intrinfo;
7227a364d25Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
7237a364d25Sschwartz 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
7247a364d25Sschwartz 
7257a364d25Sschwartz 	if (rval == DDI_SUCCESS)
7267a364d25Sschwartz 		return (intrinfo.avgi_cpu_id);
7277a364d25Sschwartz 	else
7287a364d25Sschwartz 		return (-1);
7297a364d25Sschwartz }
7307a364d25Sschwartz 
73170025d76Sjohnny 
73270025d76Sjohnny static int
73370025d76Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
73470025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
73570025d76Sjohnny {
73670025d76Sjohnny 	struct intrspec	*ispec;
7377a364d25Sschwartz 	int		irq;
7387a364d25Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
73970025d76Sjohnny 
74070025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
74170025d76Sjohnny 	    (void *)hdlp, inum));
74270025d76Sjohnny 
74370025d76Sjohnny 	/* Translate the interrupt if needed */
74470025d76Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
7458d9a0e26Sanish 	if (ispec == NULL)
7468d9a0e26Sanish 		return (DDI_FAILURE);
7478d9a0e26Sanish 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
74870025d76Sjohnny 		ispec->intrspec_vec = inum;
7497a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
75070025d76Sjohnny 
75170025d76Sjohnny 	/* translate the interrupt if needed */
7527a364d25Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
7537a364d25Sschwartz 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
7547a364d25Sschwartz 	    hdlp->ih_pri, irq));
75570025d76Sjohnny 
75670025d76Sjohnny 	/* Add the interrupt handler */
75770025d76Sjohnny 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
7587a364d25Sschwartz 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
7597a364d25Sschwartz 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
76070025d76Sjohnny 		return (DDI_FAILURE);
76170025d76Sjohnny 
7627a364d25Sschwartz 	/* Note this really is an irq. */
7637a364d25Sschwartz 	hdlp->ih_vector = (ushort_t)irq;
7647a364d25Sschwartz 
76570025d76Sjohnny 	return (DDI_SUCCESS);
76670025d76Sjohnny }
76770025d76Sjohnny 
76870025d76Sjohnny 
76970025d76Sjohnny static void
77070025d76Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
77170025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
77270025d76Sjohnny {
7737a364d25Sschwartz 	int		irq;
77470025d76Sjohnny 	struct intrspec	*ispec;
7757a364d25Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
77670025d76Sjohnny 
77770025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
77870025d76Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
7798d9a0e26Sanish 	if (ispec == NULL)
7808d9a0e26Sanish 		return;
7818d9a0e26Sanish 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
78270025d76Sjohnny 		ispec->intrspec_vec = inum;
7837a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
78470025d76Sjohnny 
78570025d76Sjohnny 	/* translate the interrupt if needed */
7867a364d25Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
78770025d76Sjohnny 
78870025d76Sjohnny 	/* Disable the interrupt handler */
7897a364d25Sschwartz 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
7907a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = NULL;
79170025d76Sjohnny }
79270025d76Sjohnny 
79370025d76Sjohnny /*
79470025d76Sjohnny  * Miscellaneous library function
79570025d76Sjohnny  */
79670025d76Sjohnny int
79770025d76Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
79870025d76Sjohnny {
79970025d76Sjohnny 	int		i;
80070025d76Sjohnny 	int 		number;
80170025d76Sjohnny 	int		assigned_addr_len;
80270025d76Sjohnny 	uint_t		phys_hi = pci_rp->pci_phys_hi;
80370025d76Sjohnny 	pci_regspec_t	*assigned_addr;
80470025d76Sjohnny 
80570025d76Sjohnny 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
80670025d76Sjohnny 	    (phys_hi & PCI_RELOCAT_B))
80770025d76Sjohnny 		return (DDI_SUCCESS);
80870025d76Sjohnny 
80970025d76Sjohnny 	/*
81070025d76Sjohnny 	 * the "reg" property specifies relocatable, get and interpret the
81170025d76Sjohnny 	 * "assigned-addresses" property.
81270025d76Sjohnny 	 */
81370025d76Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
81470025d76Sjohnny 	    "assigned-addresses", (int **)&assigned_addr,
81570025d76Sjohnny 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
81670025d76Sjohnny 		return (DDI_FAILURE);
81770025d76Sjohnny 
81870025d76Sjohnny 	/*
81970025d76Sjohnny 	 * Scan the "assigned-addresses" for one that matches the specified
82070025d76Sjohnny 	 * "reg" property entry.
82170025d76Sjohnny 	 */
82270025d76Sjohnny 	phys_hi &= PCI_CONF_ADDR_MASK;
82370025d76Sjohnny 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
82470025d76Sjohnny 	for (i = 0; i < number; i++) {
82570025d76Sjohnny 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
82670025d76Sjohnny 		    phys_hi) {
82770025d76Sjohnny 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
82870025d76Sjohnny 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
82970025d76Sjohnny 			ddi_prop_free(assigned_addr);
83070025d76Sjohnny 			return (DDI_SUCCESS);
83170025d76Sjohnny 		}
83270025d76Sjohnny 	}
83370025d76Sjohnny 
83470025d76Sjohnny 	ddi_prop_free(assigned_addr);
83570025d76Sjohnny 	return (DDI_FAILURE);
83670025d76Sjohnny }
83770025d76Sjohnny 
83870025d76Sjohnny 
83970025d76Sjohnny /*
84070025d76Sjohnny  * For pci_tools
84170025d76Sjohnny  */
84270025d76Sjohnny 
84370025d76Sjohnny int
84470025d76Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
84570025d76Sjohnny     int mode, cred_t *credp, int *rvalp)
84670025d76Sjohnny {
84770025d76Sjohnny 	int rv = ENOTTY;
84870025d76Sjohnny 
84970025d76Sjohnny 	minor_t minor = getminor(dev);
85070025d76Sjohnny 
85170025d76Sjohnny 	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
85270025d76Sjohnny 	case PCI_TOOL_REG_MINOR_NUM:
85370025d76Sjohnny 
85470025d76Sjohnny 		switch (cmd) {
85570025d76Sjohnny 		case PCITOOL_DEVICE_SET_REG:
85670025d76Sjohnny 		case PCITOOL_DEVICE_GET_REG:
85770025d76Sjohnny 
85870025d76Sjohnny 			/* Require full privileges. */
85970025d76Sjohnny 			if (secpolicy_kmdb(credp))
86070025d76Sjohnny 				rv = EPERM;
86170025d76Sjohnny 			else
86270025d76Sjohnny 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
86370025d76Sjohnny 				    cmd, mode);
86470025d76Sjohnny 			break;
86570025d76Sjohnny 
86670025d76Sjohnny 		case PCITOOL_NEXUS_SET_REG:
86770025d76Sjohnny 		case PCITOOL_NEXUS_GET_REG:
86870025d76Sjohnny 
86970025d76Sjohnny 			/* Require full privileges. */
87070025d76Sjohnny 			if (secpolicy_kmdb(credp))
87170025d76Sjohnny 				rv = EPERM;
87270025d76Sjohnny 			else
87370025d76Sjohnny 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
87470025d76Sjohnny 				    cmd, mode);
87570025d76Sjohnny 			break;
87670025d76Sjohnny 		}
87770025d76Sjohnny 		break;
87870025d76Sjohnny 
87970025d76Sjohnny 	case PCI_TOOL_INTR_MINOR_NUM:
88070025d76Sjohnny 
88170025d76Sjohnny 		switch (cmd) {
88270025d76Sjohnny 		case PCITOOL_DEVICE_SET_INTR:
88370025d76Sjohnny 
88470025d76Sjohnny 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
88570025d76Sjohnny 			if (secpolicy_ponline(credp)) {
88670025d76Sjohnny 				rv = EPERM;
88770025d76Sjohnny 				break;
88870025d76Sjohnny 			}
88970025d76Sjohnny 
89070025d76Sjohnny 		/*FALLTHRU*/
89170025d76Sjohnny 		/* These require no special privileges. */
89270025d76Sjohnny 		case PCITOOL_DEVICE_GET_INTR:
8932917a9c9Sschwartz 		case PCITOOL_SYSTEM_INTR_INFO:
89470025d76Sjohnny 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
89570025d76Sjohnny 			break;
89670025d76Sjohnny 		}
89770025d76Sjohnny 		break;
89870025d76Sjohnny 
89970025d76Sjohnny 	/*
90070025d76Sjohnny 	 * All non-PCItool ioctls go through here, including:
90170025d76Sjohnny 	 *   devctl ioctls with minor number PCIHP_DEVCTL_MINOR and
90270025d76Sjohnny 	 *   those for attachment points with where minor number is the
90370025d76Sjohnny 	 *   device number.
90470025d76Sjohnny 	 */
90570025d76Sjohnny 	default:
90670025d76Sjohnny 		rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
90770025d76Sjohnny 		    credp, rvalp);
90870025d76Sjohnny 		break;
90970025d76Sjohnny 	}
91070025d76Sjohnny 
91170025d76Sjohnny 	return (rv);
91270025d76Sjohnny }
913649d4cceSanish 
914649d4cceSanish 
91500d0963fSdilpreet int
91600d0963fSdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
91700d0963fSdilpreet {
91800d0963fSdilpreet 	size_t size = in_args->size;
91900d0963fSdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
92000d0963fSdilpreet 	uintptr_t host_addr = in_args->host_addr;
92100d0963fSdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
92200d0963fSdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
92300d0963fSdilpreet 	size_t repcount = in_args->repcount;
92400d0963fSdilpreet 	uint_t flags = in_args->flags;
92500d0963fSdilpreet 	int err = DDI_SUCCESS;
92600d0963fSdilpreet 
92700d0963fSdilpreet 	/*
92800d0963fSdilpreet 	 * if no handle then this is a poke. We have to return failure here
92900d0963fSdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
93000d0963fSdilpreet 	 */
93100d0963fSdilpreet 	if (in_args->handle == NULL)
93200d0963fSdilpreet 		return (DDI_FAILURE);
93300d0963fSdilpreet 
93400d0963fSdilpreet 	/*
93500d0963fSdilpreet 	 * rest of this function is actually for cautious puts
93600d0963fSdilpreet 	 */
93700d0963fSdilpreet 	for (; repcount; repcount--) {
93800d0963fSdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
93900d0963fSdilpreet 			switch (size) {
94000d0963fSdilpreet 			case sizeof (uint8_t):
94100d0963fSdilpreet 				pci_config_wr8(hp, (uint8_t *)dev_addr,
94200d0963fSdilpreet 				    *(uint8_t *)host_addr);
94300d0963fSdilpreet 				break;
94400d0963fSdilpreet 			case sizeof (uint16_t):
94500d0963fSdilpreet 				pci_config_wr16(hp, (uint16_t *)dev_addr,
94600d0963fSdilpreet 				    *(uint16_t *)host_addr);
94700d0963fSdilpreet 				break;
94800d0963fSdilpreet 			case sizeof (uint32_t):
94900d0963fSdilpreet 				pci_config_wr32(hp, (uint32_t *)dev_addr,
95000d0963fSdilpreet 				    *(uint32_t *)host_addr);
95100d0963fSdilpreet 				break;
95200d0963fSdilpreet 			case sizeof (uint64_t):
95300d0963fSdilpreet 				pci_config_wr64(hp, (uint64_t *)dev_addr,
95400d0963fSdilpreet 				    *(uint64_t *)host_addr);
95500d0963fSdilpreet 				break;
95600d0963fSdilpreet 			default:
95700d0963fSdilpreet 				err = DDI_FAILURE;
95800d0963fSdilpreet 				break;
95900d0963fSdilpreet 			}
96000d0963fSdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
96100d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
96200d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
96300d0963fSdilpreet 				switch (size) {
96400d0963fSdilpreet 				case sizeof (uint8_t):
96500d0963fSdilpreet 					i_ddi_io_put8(hp,
96600d0963fSdilpreet 					    (uint8_t *)dev_addr,
96700d0963fSdilpreet 					    *(uint8_t *)host_addr);
96800d0963fSdilpreet 					break;
96900d0963fSdilpreet 				case sizeof (uint16_t):
97000d0963fSdilpreet 					i_ddi_io_swap_put16(hp,
97100d0963fSdilpreet 					    (uint16_t *)dev_addr,
97200d0963fSdilpreet 					    *(uint16_t *)host_addr);
97300d0963fSdilpreet 					break;
97400d0963fSdilpreet 				case sizeof (uint32_t):
97500d0963fSdilpreet 					i_ddi_io_swap_put32(hp,
97600d0963fSdilpreet 					    (uint32_t *)dev_addr,
97700d0963fSdilpreet 					    *(uint32_t *)host_addr);
97800d0963fSdilpreet 					break;
97900d0963fSdilpreet 				/*
98000d0963fSdilpreet 				 * note the 64-bit case is a dummy
98100d0963fSdilpreet 				 * function - so no need to swap
98200d0963fSdilpreet 				 */
98300d0963fSdilpreet 				case sizeof (uint64_t):
98400d0963fSdilpreet 					i_ddi_io_put64(hp,
98500d0963fSdilpreet 					    (uint64_t *)dev_addr,
98600d0963fSdilpreet 					    *(uint64_t *)host_addr);
98700d0963fSdilpreet 					break;
98800d0963fSdilpreet 				default:
98900d0963fSdilpreet 					err = DDI_FAILURE;
99000d0963fSdilpreet 					break;
99100d0963fSdilpreet 				}
99200d0963fSdilpreet 			} else {
99300d0963fSdilpreet 				switch (size) {
99400d0963fSdilpreet 				case sizeof (uint8_t):
99500d0963fSdilpreet 					i_ddi_io_put8(hp,
99600d0963fSdilpreet 					    (uint8_t *)dev_addr,
99700d0963fSdilpreet 					    *(uint8_t *)host_addr);
99800d0963fSdilpreet 					break;
99900d0963fSdilpreet 				case sizeof (uint16_t):
100000d0963fSdilpreet 					i_ddi_io_put16(hp,
100100d0963fSdilpreet 					    (uint16_t *)dev_addr,
100200d0963fSdilpreet 					    *(uint16_t *)host_addr);
100300d0963fSdilpreet 					break;
100400d0963fSdilpreet 				case sizeof (uint32_t):
100500d0963fSdilpreet 					i_ddi_io_put32(hp,
100600d0963fSdilpreet 					    (uint32_t *)dev_addr,
100700d0963fSdilpreet 					    *(uint32_t *)host_addr);
100800d0963fSdilpreet 					break;
100900d0963fSdilpreet 				case sizeof (uint64_t):
101000d0963fSdilpreet 					i_ddi_io_put64(hp,
101100d0963fSdilpreet 					    (uint64_t *)dev_addr,
101200d0963fSdilpreet 					    *(uint64_t *)host_addr);
101300d0963fSdilpreet 					break;
101400d0963fSdilpreet 				default:
101500d0963fSdilpreet 					err = DDI_FAILURE;
101600d0963fSdilpreet 					break;
101700d0963fSdilpreet 				}
101800d0963fSdilpreet 			}
101900d0963fSdilpreet 		} else {
102000d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
102100d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
102200d0963fSdilpreet 				switch (size) {
102300d0963fSdilpreet 				case sizeof (uint8_t):
102400d0963fSdilpreet 					*(uint8_t *)dev_addr =
102500d0963fSdilpreet 					    *(uint8_t *)host_addr;
102600d0963fSdilpreet 					break;
102700d0963fSdilpreet 				case sizeof (uint16_t):
102800d0963fSdilpreet 					*(uint16_t *)dev_addr =
102900d0963fSdilpreet 					    ddi_swap16(*(uint16_t *)host_addr);
103000d0963fSdilpreet 					break;
103100d0963fSdilpreet 				case sizeof (uint32_t):
103200d0963fSdilpreet 					*(uint32_t *)dev_addr =
103300d0963fSdilpreet 					    ddi_swap32(*(uint32_t *)host_addr);
103400d0963fSdilpreet 					break;
103500d0963fSdilpreet 				case sizeof (uint64_t):
103600d0963fSdilpreet 					*(uint64_t *)dev_addr =
103700d0963fSdilpreet 					    ddi_swap64(*(uint64_t *)host_addr);
103800d0963fSdilpreet 					break;
103900d0963fSdilpreet 				default:
104000d0963fSdilpreet 					err = DDI_FAILURE;
104100d0963fSdilpreet 					break;
104200d0963fSdilpreet 				}
104300d0963fSdilpreet 			} else {
104400d0963fSdilpreet 				switch (size) {
104500d0963fSdilpreet 				case sizeof (uint8_t):
104600d0963fSdilpreet 					*(uint8_t *)dev_addr =
104700d0963fSdilpreet 					    *(uint8_t *)host_addr;
104800d0963fSdilpreet 					break;
104900d0963fSdilpreet 				case sizeof (uint16_t):
105000d0963fSdilpreet 					*(uint16_t *)dev_addr =
105100d0963fSdilpreet 					    *(uint16_t *)host_addr;
105200d0963fSdilpreet 					break;
105300d0963fSdilpreet 				case sizeof (uint32_t):
105400d0963fSdilpreet 					*(uint32_t *)dev_addr =
105500d0963fSdilpreet 					    *(uint32_t *)host_addr;
105600d0963fSdilpreet 					break;
105700d0963fSdilpreet 				case sizeof (uint64_t):
105800d0963fSdilpreet 					*(uint64_t *)dev_addr =
105900d0963fSdilpreet 					    *(uint64_t *)host_addr;
106000d0963fSdilpreet 					break;
106100d0963fSdilpreet 				default:
106200d0963fSdilpreet 					err = DDI_FAILURE;
106300d0963fSdilpreet 					break;
106400d0963fSdilpreet 				}
106500d0963fSdilpreet 			}
106600d0963fSdilpreet 		}
106700d0963fSdilpreet 		host_addr += size;
106800d0963fSdilpreet 		if (flags == DDI_DEV_AUTOINCR)
106900d0963fSdilpreet 			dev_addr += size;
107000d0963fSdilpreet 	}
107100d0963fSdilpreet 	return (err);
107200d0963fSdilpreet }
107300d0963fSdilpreet 
107400d0963fSdilpreet 
107500d0963fSdilpreet int
107600d0963fSdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
107700d0963fSdilpreet {
107800d0963fSdilpreet 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
107900d0963fSdilpreet 
108000d0963fSdilpreet 	/* endian-ness check */
108100d0963fSdilpreet 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
108200d0963fSdilpreet 		return (DDI_FAILURE);
108300d0963fSdilpreet 
108400d0963fSdilpreet 	/*
108500d0963fSdilpreet 	 * range check
108600d0963fSdilpreet 	 */
108700d0963fSdilpreet 	if ((offset >= PCI_CONF_HDR_SIZE) ||
108800d0963fSdilpreet 	    (len > PCI_CONF_HDR_SIZE) ||
108900d0963fSdilpreet 	    (offset + len > PCI_CONF_HDR_SIZE))
109000d0963fSdilpreet 		return (DDI_FAILURE);
109100d0963fSdilpreet 
109200d0963fSdilpreet 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
109300d0963fSdilpreet 	/*
109400d0963fSdilpreet 	 * always use cautious mechanism for config space gets
109500d0963fSdilpreet 	 */
109600d0963fSdilpreet 	ap->ahi_get8 = i_ddi_caut_get8;
109700d0963fSdilpreet 	ap->ahi_get16 = i_ddi_caut_get16;
109800d0963fSdilpreet 	ap->ahi_get32 = i_ddi_caut_get32;
109900d0963fSdilpreet 	ap->ahi_get64 = i_ddi_caut_get64;
110000d0963fSdilpreet 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
110100d0963fSdilpreet 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
110200d0963fSdilpreet 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
110300d0963fSdilpreet 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
110400d0963fSdilpreet 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
110500d0963fSdilpreet 		ap->ahi_put8 = i_ddi_caut_put8;
110600d0963fSdilpreet 		ap->ahi_put16 = i_ddi_caut_put16;
110700d0963fSdilpreet 		ap->ahi_put32 = i_ddi_caut_put32;
110800d0963fSdilpreet 		ap->ahi_put64 = i_ddi_caut_put64;
110900d0963fSdilpreet 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
111000d0963fSdilpreet 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
111100d0963fSdilpreet 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
111200d0963fSdilpreet 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
111300d0963fSdilpreet 	} else {
111400d0963fSdilpreet 		ap->ahi_put8 = pci_config_wr8;
111500d0963fSdilpreet 		ap->ahi_put16 = pci_config_wr16;
111600d0963fSdilpreet 		ap->ahi_put32 = pci_config_wr32;
111700d0963fSdilpreet 		ap->ahi_put64 = pci_config_wr64;
111800d0963fSdilpreet 		ap->ahi_rep_put8 = pci_config_rep_wr8;
111900d0963fSdilpreet 		ap->ahi_rep_put16 = pci_config_rep_wr16;
112000d0963fSdilpreet 		ap->ahi_rep_put32 = pci_config_rep_wr32;
112100d0963fSdilpreet 		ap->ahi_rep_put64 = pci_config_rep_wr64;
112200d0963fSdilpreet 	}
112300d0963fSdilpreet 
112400d0963fSdilpreet 	/* Initialize to default check/notify functions */
112500d0963fSdilpreet 	ap->ahi_fault_check = i_ddi_acc_fault_check;
112600d0963fSdilpreet 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
112700d0963fSdilpreet 	ap->ahi_fault = 0;
112800d0963fSdilpreet 	impl_acc_err_init(hp);
112900d0963fSdilpreet 	return (DDI_SUCCESS);
113000d0963fSdilpreet }
113100d0963fSdilpreet 
113200d0963fSdilpreet 
113300d0963fSdilpreet int
113400d0963fSdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
113500d0963fSdilpreet {
113600d0963fSdilpreet 	size_t size = in_args->size;
113700d0963fSdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
113800d0963fSdilpreet 	uintptr_t host_addr = in_args->host_addr;
113900d0963fSdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
114000d0963fSdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
114100d0963fSdilpreet 	size_t repcount = in_args->repcount;
114200d0963fSdilpreet 	uint_t flags = in_args->flags;
114300d0963fSdilpreet 	int err = DDI_SUCCESS;
114400d0963fSdilpreet 
114500d0963fSdilpreet 	/*
114600d0963fSdilpreet 	 * if no handle then this is a peek. We have to return failure here
114700d0963fSdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
114800d0963fSdilpreet 	 */
114900d0963fSdilpreet 	if (in_args->handle == NULL)
115000d0963fSdilpreet 		return (DDI_FAILURE);
115100d0963fSdilpreet 
115200d0963fSdilpreet 	for (; repcount; repcount--) {
115300d0963fSdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
115400d0963fSdilpreet 			switch (size) {
115500d0963fSdilpreet 			case sizeof (uint8_t):
115600d0963fSdilpreet 				*(uint8_t *)host_addr = pci_config_rd8(hp,
115700d0963fSdilpreet 				    (uint8_t *)dev_addr);
115800d0963fSdilpreet 				break;
115900d0963fSdilpreet 			case sizeof (uint16_t):
116000d0963fSdilpreet 				*(uint16_t *)host_addr = pci_config_rd16(hp,
116100d0963fSdilpreet 				    (uint16_t *)dev_addr);
116200d0963fSdilpreet 				break;
116300d0963fSdilpreet 			case sizeof (uint32_t):
116400d0963fSdilpreet 				*(uint32_t *)host_addr = pci_config_rd32(hp,
116500d0963fSdilpreet 				    (uint32_t *)dev_addr);
116600d0963fSdilpreet 				break;
116700d0963fSdilpreet 			case sizeof (uint64_t):
116800d0963fSdilpreet 				*(uint64_t *)host_addr = pci_config_rd64(hp,
116900d0963fSdilpreet 				    (uint64_t *)dev_addr);
117000d0963fSdilpreet 				break;
117100d0963fSdilpreet 			default:
117200d0963fSdilpreet 				err = DDI_FAILURE;
117300d0963fSdilpreet 				break;
117400d0963fSdilpreet 			}
117500d0963fSdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
117600d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
117700d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
117800d0963fSdilpreet 				switch (size) {
117900d0963fSdilpreet 				case sizeof (uint8_t):
118000d0963fSdilpreet 					*(uint8_t *)host_addr =
118100d0963fSdilpreet 					    i_ddi_io_get8(hp,
118200d0963fSdilpreet 					    (uint8_t *)dev_addr);
118300d0963fSdilpreet 					break;
118400d0963fSdilpreet 				case sizeof (uint16_t):
118500d0963fSdilpreet 					*(uint16_t *)host_addr =
118600d0963fSdilpreet 					    i_ddi_io_swap_get16(hp,
118700d0963fSdilpreet 					    (uint16_t *)dev_addr);
118800d0963fSdilpreet 					break;
118900d0963fSdilpreet 				case sizeof (uint32_t):
119000d0963fSdilpreet 					*(uint32_t *)host_addr =
119100d0963fSdilpreet 					    i_ddi_io_swap_get32(hp,
119200d0963fSdilpreet 					    (uint32_t *)dev_addr);
119300d0963fSdilpreet 					break;
119400d0963fSdilpreet 				/*
119500d0963fSdilpreet 				 * note the 64-bit case is a dummy
119600d0963fSdilpreet 				 * function - so no need to swap
119700d0963fSdilpreet 				 */
119800d0963fSdilpreet 				case sizeof (uint64_t):
119900d0963fSdilpreet 					*(uint64_t *)host_addr =
120000d0963fSdilpreet 					    i_ddi_io_get64(hp,
120100d0963fSdilpreet 					    (uint64_t *)dev_addr);
120200d0963fSdilpreet 					break;
120300d0963fSdilpreet 				default:
120400d0963fSdilpreet 					err = DDI_FAILURE;
120500d0963fSdilpreet 					break;
120600d0963fSdilpreet 				}
120700d0963fSdilpreet 			} else {
120800d0963fSdilpreet 				switch (size) {
120900d0963fSdilpreet 				case sizeof (uint8_t):
121000d0963fSdilpreet 					*(uint8_t *)host_addr =
121100d0963fSdilpreet 					    i_ddi_io_get8(hp,
121200d0963fSdilpreet 					    (uint8_t *)dev_addr);
121300d0963fSdilpreet 					break;
121400d0963fSdilpreet 				case sizeof (uint16_t):
121500d0963fSdilpreet 					*(uint16_t *)host_addr =
121600d0963fSdilpreet 					    i_ddi_io_get16(hp,
121700d0963fSdilpreet 					    (uint16_t *)dev_addr);
121800d0963fSdilpreet 					break;
121900d0963fSdilpreet 				case sizeof (uint32_t):
122000d0963fSdilpreet 					*(uint32_t *)host_addr =
122100d0963fSdilpreet 					    i_ddi_io_get32(hp,
122200d0963fSdilpreet 					    (uint32_t *)dev_addr);
122300d0963fSdilpreet 					break;
122400d0963fSdilpreet 				case sizeof (uint64_t):
122500d0963fSdilpreet 					*(uint64_t *)host_addr =
122600d0963fSdilpreet 					    i_ddi_io_get64(hp,
122700d0963fSdilpreet 					    (uint64_t *)dev_addr);
122800d0963fSdilpreet 					break;
122900d0963fSdilpreet 				default:
123000d0963fSdilpreet 					err = DDI_FAILURE;
123100d0963fSdilpreet 					break;
123200d0963fSdilpreet 				}
123300d0963fSdilpreet 			}
123400d0963fSdilpreet 		} else {
123500d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
123600d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
123700d0963fSdilpreet 				switch (in_args->size) {
123800d0963fSdilpreet 				case sizeof (uint8_t):
123900d0963fSdilpreet 					*(uint8_t *)host_addr =
124000d0963fSdilpreet 					    *(uint8_t *)dev_addr;
124100d0963fSdilpreet 					break;
124200d0963fSdilpreet 				case sizeof (uint16_t):
124300d0963fSdilpreet 					*(uint16_t *)host_addr =
124400d0963fSdilpreet 					    ddi_swap16(*(uint16_t *)dev_addr);
124500d0963fSdilpreet 					break;
124600d0963fSdilpreet 				case sizeof (uint32_t):
124700d0963fSdilpreet 					*(uint32_t *)host_addr =
124800d0963fSdilpreet 					    ddi_swap32(*(uint32_t *)dev_addr);
124900d0963fSdilpreet 					break;
125000d0963fSdilpreet 				case sizeof (uint64_t):
125100d0963fSdilpreet 					*(uint64_t *)host_addr =
125200d0963fSdilpreet 					    ddi_swap64(*(uint64_t *)dev_addr);
125300d0963fSdilpreet 					break;
125400d0963fSdilpreet 				default:
125500d0963fSdilpreet 					err = DDI_FAILURE;
125600d0963fSdilpreet 					break;
125700d0963fSdilpreet 				}
125800d0963fSdilpreet 			} else {
125900d0963fSdilpreet 				switch (in_args->size) {
126000d0963fSdilpreet 				case sizeof (uint8_t):
126100d0963fSdilpreet 					*(uint8_t *)host_addr =
126200d0963fSdilpreet 					    *(uint8_t *)dev_addr;
126300d0963fSdilpreet 					break;
126400d0963fSdilpreet 				case sizeof (uint16_t):
126500d0963fSdilpreet 					*(uint16_t *)host_addr =
126600d0963fSdilpreet 					    *(uint16_t *)dev_addr;
126700d0963fSdilpreet 					break;
126800d0963fSdilpreet 				case sizeof (uint32_t):
126900d0963fSdilpreet 					*(uint32_t *)host_addr =
127000d0963fSdilpreet 					    *(uint32_t *)dev_addr;
127100d0963fSdilpreet 					break;
127200d0963fSdilpreet 				case sizeof (uint64_t):
127300d0963fSdilpreet 					*(uint64_t *)host_addr =
127400d0963fSdilpreet 					    *(uint64_t *)dev_addr;
127500d0963fSdilpreet 					break;
127600d0963fSdilpreet 				default:
127700d0963fSdilpreet 					err = DDI_FAILURE;
127800d0963fSdilpreet 					break;
127900d0963fSdilpreet 				}
128000d0963fSdilpreet 			}
128100d0963fSdilpreet 		}
128200d0963fSdilpreet 		host_addr += size;
128300d0963fSdilpreet 		if (flags == DDI_DEV_AUTOINCR)
128400d0963fSdilpreet 			dev_addr += size;
128500d0963fSdilpreet 	}
128600d0963fSdilpreet 	return (err);
128700d0963fSdilpreet }
128800d0963fSdilpreet 
128900d0963fSdilpreet /*ARGSUSED*/
129000d0963fSdilpreet int
129100d0963fSdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
129200d0963fSdilpreet 	ddi_ctl_enum_t ctlop, void *arg, void *result)
129300d0963fSdilpreet {
129400d0963fSdilpreet 	if (ctlop == DDI_CTLOPS_PEEK)
129500d0963fSdilpreet 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
129600d0963fSdilpreet 	else
129700d0963fSdilpreet 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
129800d0963fSdilpreet }
129900d0963fSdilpreet 
1300649d4cceSanish /*
1301649d4cceSanish  * These are the get and put functions to be shared with drivers. The
1302649d4cceSanish  * mutex locking is done inside the functions referenced, rather than
1303649d4cceSanish  * here, and is thus shared across PCI child drivers and any other
1304649d4cceSanish  * consumers of PCI config space (such as the ACPI subsystem).
1305649d4cceSanish  *
1306649d4cceSanish  * The configuration space addresses come in as pointers.  This is fine on
1307649d4cceSanish  * a 32-bit system, where the VM space and configuration space are the same
1308649d4cceSanish  * size.  It's not such a good idea on a 64-bit system, where memory
1309649d4cceSanish  * addresses are twice as large as configuration space addresses.  At some
1310649d4cceSanish  * point in the call tree we need to take a stand and say "you are 32-bit
1311649d4cceSanish  * from this time forth", and this seems like a nice self-contained place.
1312649d4cceSanish  */
1313649d4cceSanish 
1314649d4cceSanish uint8_t
1315649d4cceSanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1316649d4cceSanish {
1317649d4cceSanish 	pci_acc_cfblk_t *cfp;
1318649d4cceSanish 	uint8_t	rval;
1319649d4cceSanish 	int reg;
1320649d4cceSanish 
1321649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1322649d4cceSanish 
1323649d4cceSanish 	reg = (int)(uintptr_t)addr;
1324649d4cceSanish 
1325649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1326649d4cceSanish 
1327649d4cceSanish 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1328649d4cceSanish 	    reg);
1329649d4cceSanish 
1330649d4cceSanish 	return (rval);
1331649d4cceSanish }
1332649d4cceSanish 
1333649d4cceSanish void
1334649d4cceSanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1335649d4cceSanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1336649d4cceSanish {
1337649d4cceSanish 	uint8_t *h, *d;
1338649d4cceSanish 
1339649d4cceSanish 	h = host_addr;
1340649d4cceSanish 	d = dev_addr;
1341649d4cceSanish 
1342649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1343649d4cceSanish 		for (; repcount; repcount--)
1344649d4cceSanish 			*h++ = pci_config_rd8(hdlp, d++);
1345649d4cceSanish 	else
1346649d4cceSanish 		for (; repcount; repcount--)
1347649d4cceSanish 			*h++ = pci_config_rd8(hdlp, d);
1348649d4cceSanish }
1349649d4cceSanish 
1350649d4cceSanish uint16_t
1351649d4cceSanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1352649d4cceSanish {
1353649d4cceSanish 	pci_acc_cfblk_t *cfp;
1354649d4cceSanish 	uint16_t rval;
1355649d4cceSanish 	int reg;
1356649d4cceSanish 
1357649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1358649d4cceSanish 
1359649d4cceSanish 	reg = (int)(uintptr_t)addr;
1360649d4cceSanish 
1361649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1362649d4cceSanish 
1363649d4cceSanish 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1364649d4cceSanish 	    reg);
1365649d4cceSanish 
1366649d4cceSanish 	return (rval);
1367649d4cceSanish }
1368649d4cceSanish 
1369649d4cceSanish void
1370649d4cceSanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1371649d4cceSanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1372649d4cceSanish {
1373649d4cceSanish 	uint16_t *h, *d;
1374649d4cceSanish 
1375649d4cceSanish 	h = host_addr;
1376649d4cceSanish 	d = dev_addr;
1377649d4cceSanish 
1378649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1379649d4cceSanish 		for (; repcount; repcount--)
1380649d4cceSanish 			*h++ = pci_config_rd16(hdlp, d++);
1381649d4cceSanish 	else
1382649d4cceSanish 		for (; repcount; repcount--)
1383649d4cceSanish 			*h++ = pci_config_rd16(hdlp, d);
1384649d4cceSanish }
1385649d4cceSanish 
1386649d4cceSanish uint32_t
1387649d4cceSanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1388649d4cceSanish {
1389649d4cceSanish 	pci_acc_cfblk_t *cfp;
1390649d4cceSanish 	uint32_t rval;
1391649d4cceSanish 	int reg;
1392649d4cceSanish 
1393649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1394649d4cceSanish 
1395649d4cceSanish 	reg = (int)(uintptr_t)addr;
1396649d4cceSanish 
1397649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1398649d4cceSanish 
1399649d4cceSanish 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1400649d4cceSanish 	    cfp->c_funcnum, reg);
1401649d4cceSanish 
1402649d4cceSanish 	return (rval);
1403649d4cceSanish }
1404649d4cceSanish 
1405649d4cceSanish void
1406649d4cceSanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1407649d4cceSanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1408649d4cceSanish {
1409649d4cceSanish 	uint32_t *h, *d;
1410649d4cceSanish 
1411649d4cceSanish 	h = host_addr;
1412649d4cceSanish 	d = dev_addr;
1413649d4cceSanish 
1414649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1415649d4cceSanish 		for (; repcount; repcount--)
1416649d4cceSanish 			*h++ = pci_config_rd32(hdlp, d++);
1417649d4cceSanish 	else
1418649d4cceSanish 		for (; repcount; repcount--)
1419649d4cceSanish 			*h++ = pci_config_rd32(hdlp, d);
1420649d4cceSanish }
1421649d4cceSanish 
1422649d4cceSanish 
1423649d4cceSanish void
1424649d4cceSanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1425649d4cceSanish {
1426649d4cceSanish 	pci_acc_cfblk_t *cfp;
1427649d4cceSanish 	int reg;
1428649d4cceSanish 
1429649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1430649d4cceSanish 
1431649d4cceSanish 	reg = (int)(uintptr_t)addr;
1432649d4cceSanish 
1433649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1434649d4cceSanish 
1435649d4cceSanish 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1436649d4cceSanish 	    cfp->c_funcnum, reg, value);
1437649d4cceSanish }
1438649d4cceSanish 
1439649d4cceSanish void
1440649d4cceSanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1441649d4cceSanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1442649d4cceSanish {
1443649d4cceSanish 	uint8_t *h, *d;
1444649d4cceSanish 
1445649d4cceSanish 	h = host_addr;
1446649d4cceSanish 	d = dev_addr;
1447649d4cceSanish 
1448649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1449649d4cceSanish 		for (; repcount; repcount--)
1450649d4cceSanish 			pci_config_wr8(hdlp, d++, *h++);
1451649d4cceSanish 	else
1452649d4cceSanish 		for (; repcount; repcount--)
1453649d4cceSanish 			pci_config_wr8(hdlp, d, *h++);
1454649d4cceSanish }
1455649d4cceSanish 
1456649d4cceSanish void
1457649d4cceSanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1458649d4cceSanish {
1459649d4cceSanish 	pci_acc_cfblk_t *cfp;
1460649d4cceSanish 	int reg;
1461649d4cceSanish 
1462649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1463649d4cceSanish 
1464649d4cceSanish 	reg = (int)(uintptr_t)addr;
1465649d4cceSanish 
1466649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1467649d4cceSanish 
1468649d4cceSanish 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1469649d4cceSanish 	    cfp->c_funcnum, reg, value);
1470649d4cceSanish }
1471649d4cceSanish 
1472649d4cceSanish void
1473649d4cceSanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1474649d4cceSanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1475649d4cceSanish {
1476649d4cceSanish 	uint16_t *h, *d;
1477649d4cceSanish 
1478649d4cceSanish 	h = host_addr;
1479649d4cceSanish 	d = dev_addr;
1480649d4cceSanish 
1481649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1482649d4cceSanish 		for (; repcount; repcount--)
1483649d4cceSanish 			pci_config_wr16(hdlp, d++, *h++);
1484649d4cceSanish 	else
1485649d4cceSanish 		for (; repcount; repcount--)
1486649d4cceSanish 			pci_config_wr16(hdlp, d, *h++);
1487649d4cceSanish }
1488649d4cceSanish 
1489649d4cceSanish void
1490649d4cceSanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1491649d4cceSanish {
1492649d4cceSanish 	pci_acc_cfblk_t *cfp;
1493649d4cceSanish 	int reg;
1494649d4cceSanish 
1495649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1496649d4cceSanish 
1497649d4cceSanish 	reg = (int)(uintptr_t)addr;
1498649d4cceSanish 
1499649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1500649d4cceSanish 
1501649d4cceSanish 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1502649d4cceSanish 	    cfp->c_funcnum, reg, value);
1503649d4cceSanish }
1504649d4cceSanish 
1505649d4cceSanish void
1506649d4cceSanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1507649d4cceSanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1508649d4cceSanish {
1509649d4cceSanish 	uint32_t *h, *d;
1510649d4cceSanish 
1511649d4cceSanish 	h = host_addr;
1512649d4cceSanish 	d = dev_addr;
1513649d4cceSanish 
1514649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1515649d4cceSanish 		for (; repcount; repcount--)
1516649d4cceSanish 			pci_config_wr32(hdlp, d++, *h++);
1517649d4cceSanish 	else
1518649d4cceSanish 		for (; repcount; repcount--)
1519649d4cceSanish 			pci_config_wr32(hdlp, d, *h++);
1520649d4cceSanish }
1521649d4cceSanish 
1522649d4cceSanish uint64_t
1523649d4cceSanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1524649d4cceSanish {
1525649d4cceSanish 	uint32_t lw_val;
1526649d4cceSanish 	uint32_t hi_val;
1527649d4cceSanish 	uint32_t *dp;
1528649d4cceSanish 	uint64_t val;
1529649d4cceSanish 
1530649d4cceSanish 	dp = (uint32_t *)addr;
1531649d4cceSanish 	lw_val = pci_config_rd32(hdlp, dp);
1532649d4cceSanish 	dp++;
1533649d4cceSanish 	hi_val = pci_config_rd32(hdlp, dp);
1534649d4cceSanish 	val = ((uint64_t)hi_val << 32) | lw_val;
1535649d4cceSanish 	return (val);
1536649d4cceSanish }
1537649d4cceSanish 
1538649d4cceSanish void
1539649d4cceSanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1540649d4cceSanish {
1541649d4cceSanish 	uint32_t lw_val;
1542649d4cceSanish 	uint32_t hi_val;
1543649d4cceSanish 	uint32_t *dp;
1544649d4cceSanish 
1545649d4cceSanish 	dp = (uint32_t *)addr;
1546649d4cceSanish 	lw_val = (uint32_t)(value & 0xffffffff);
1547649d4cceSanish 	hi_val = (uint32_t)(value >> 32);
1548649d4cceSanish 	pci_config_wr32(hdlp, dp, lw_val);
1549649d4cceSanish 	dp++;
1550649d4cceSanish 	pci_config_wr32(hdlp, dp, hi_val);
1551649d4cceSanish }
1552649d4cceSanish 
1553649d4cceSanish void
1554649d4cceSanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1555649d4cceSanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1556649d4cceSanish {
1557649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR) {
1558649d4cceSanish 		for (; repcount; repcount--)
1559649d4cceSanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1560649d4cceSanish 	} else {
1561649d4cceSanish 		for (; repcount; repcount--)
1562649d4cceSanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
1563649d4cceSanish 	}
1564649d4cceSanish }
1565649d4cceSanish 
1566649d4cceSanish void
1567649d4cceSanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1568649d4cceSanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1569649d4cceSanish {
1570649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR) {
1571649d4cceSanish 		for (; repcount; repcount--)
1572649d4cceSanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1573649d4cceSanish 	} else {
1574649d4cceSanish 		for (; repcount; repcount--)
1575649d4cceSanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
1576649d4cceSanish 	}
1577649d4cceSanish }
1578