xref: /illumos-gate/usr/src/uts/i86pc/io/pci/pci_common.c (revision 68565200)
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 /*
23102cb92eSjohnny  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2470025d76Sjohnny  * Use is subject to license terms.
2570025d76Sjohnny  */
2670025d76Sjohnny 
2770025d76Sjohnny #pragma ident	"%Z%%M%	%I%	%E% SMI"
2870025d76Sjohnny 
2970025d76Sjohnny /*
3070025d76Sjohnny  *	File that has code which is common between pci(7d) and npe(7d)
3170025d76Sjohnny  *	It shares the following:
3270025d76Sjohnny  *	- interrupt code
3370025d76Sjohnny  *	- pci_tools ioctl code
3470025d76Sjohnny  *	- name_child code
3570025d76Sjohnny  *	- set_parent_private_data code
3670025d76Sjohnny  */
3770025d76Sjohnny 
3870025d76Sjohnny #include <sys/conf.h>
3970025d76Sjohnny #include <sys/pci.h>
4070025d76Sjohnny #include <sys/sunndi.h>
417a364d25Sschwartz #include <sys/mach_intr.h>
4270025d76Sjohnny #include <sys/hotplug/pci/pcihp.h>
4370025d76Sjohnny #include <sys/pci_intr_lib.h>
4470025d76Sjohnny #include <sys/psm.h>
4570025d76Sjohnny #include <sys/policy.h>
4670025d76Sjohnny #include <sys/sysmacros.h>
477a364d25Sschwartz #include <sys/clock.h>
487a364d25Sschwartz #include <io/pcplusmp/apic.h>
4970025d76Sjohnny #include <sys/pci_tools.h>
5070025d76Sjohnny #include <io/pci/pci_var.h>
5170025d76Sjohnny #include <io/pci/pci_tools_ext.h>
5270025d76Sjohnny #include <io/pci/pci_common.h>
53649d4cceSanish #include <sys/pci_cfgspace.h>
54649d4cceSanish #include <sys/pci_impl.h>
5570025d76Sjohnny 
5670025d76Sjohnny /*
5770025d76Sjohnny  * Function prototypes
5870025d76Sjohnny  */
5970025d76Sjohnny static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
6070025d76Sjohnny static int	pci_get_nintrs(dev_info_t *, int, int *);
6170025d76Sjohnny static int	pci_enable_intr(dev_info_t *, dev_info_t *,
6270025d76Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
6370025d76Sjohnny static void	pci_disable_intr(dev_info_t *, dev_info_t *,
6470025d76Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
6570025d76Sjohnny 
6670025d76Sjohnny /* Extern decalration for pcplusmp module */
6770025d76Sjohnny extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
6870025d76Sjohnny 		    psm_intr_op_t, int *);
6970025d76Sjohnny 
7070025d76Sjohnny 
7170025d76Sjohnny /*
7270025d76Sjohnny  * pci_name_child:
7370025d76Sjohnny  *
7470025d76Sjohnny  *	Assign the address portion of the node name
7570025d76Sjohnny  */
7670025d76Sjohnny int
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
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
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)) {
16970025d76Sjohnny 			int class = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
17070025d76Sjohnny 			    DDI_PROP_DONTPASS, "class-code", -1);
17170025d76Sjohnny 
17270025d76Sjohnny 			*pri = (class == -1) ? 1 : pci_devclass_to_ipl(class);
17370025d76Sjohnny 			pci_common_set_parent_private_data(hdlp->ih_dip);
17470025d76Sjohnny 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
17570025d76Sjohnny 			    hdlp->ih_inum);
17670025d76Sjohnny 			return (DDI_SUCCESS);
17770025d76Sjohnny 		}
17870025d76Sjohnny 		return (DDI_FAILURE);
17970025d76Sjohnny 	}
18070025d76Sjohnny 
18170025d76Sjohnny 	*pri = ispec->intrspec_pri;
18270025d76Sjohnny 	return (DDI_SUCCESS);
18370025d76Sjohnny }
18470025d76Sjohnny 
18570025d76Sjohnny 
18670025d76Sjohnny /*
18770025d76Sjohnny  * pci_get_nintrs:
18870025d76Sjohnny  *	Figure out how many interrupts the device supports
18970025d76Sjohnny  */
19070025d76Sjohnny static int
19170025d76Sjohnny pci_get_nintrs(dev_info_t *dip, int type, int *nintrs)
19270025d76Sjohnny {
19370025d76Sjohnny 	int	ret;
19470025d76Sjohnny 
19570025d76Sjohnny 	*nintrs = 0;
19670025d76Sjohnny 
19770025d76Sjohnny 	if (DDI_INTR_IS_MSI_OR_MSIX(type))
19870025d76Sjohnny 		ret = pci_msi_get_nintrs(dip, type, nintrs);
19970025d76Sjohnny 	else {
20070025d76Sjohnny 		ret = DDI_FAILURE;
20170025d76Sjohnny 		if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
20270025d76Sjohnny 		    "interrupts", -1) != -1) {
20370025d76Sjohnny 			*nintrs = 1;
20470025d76Sjohnny 			ret = DDI_SUCCESS;
20570025d76Sjohnny 		}
20670025d76Sjohnny 	}
20770025d76Sjohnny 
20870025d76Sjohnny 	return (ret);
20970025d76Sjohnny }
21070025d76Sjohnny 
21170025d76Sjohnny static int pcie_pci_intr_pri_counter = 0;
21270025d76Sjohnny 
21370025d76Sjohnny /*
21470025d76Sjohnny  * pci_common_intr_ops: bus_intr_op() function for interrupt support
21570025d76Sjohnny  */
21670025d76Sjohnny int
21770025d76Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
21870025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
21970025d76Sjohnny {
22070025d76Sjohnny 	int			priority = 0;
22170025d76Sjohnny 	int			psm_status = 0;
22270025d76Sjohnny 	int			pci_status = 0;
22370025d76Sjohnny 	int			pci_rval, psm_rval = PSM_FAILURE;
22470025d76Sjohnny 	int			types = 0;
22570025d76Sjohnny 	int			pciepci = 0;
226102cb92eSjohnny 	int			i, j, count;
22770025d76Sjohnny 	int			behavior;
228d12abe7cSanish 	int			cap_ptr;
22970025d76Sjohnny 	ddi_intrspec_t		isp;
23070025d76Sjohnny 	struct intrspec		*ispec;
23170025d76Sjohnny 	ddi_intr_handle_impl_t	tmp_hdl;
23270025d76Sjohnny 	ddi_intr_msix_t		*msix_p;
233e1d9f4e6Sschwartz 	ihdl_plat_t		*ihdl_plat_datap;
234102cb92eSjohnny 	ddi_intr_handle_t	*h_array;
235d12abe7cSanish 	ddi_acc_handle_t	handle;
23670025d76Sjohnny 
23770025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT,
23870025d76Sjohnny 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
23970025d76Sjohnny 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
24070025d76Sjohnny 
24170025d76Sjohnny 	/* Process the request */
24270025d76Sjohnny 	switch (intr_op) {
24370025d76Sjohnny 	case DDI_INTROP_SUPPORTED_TYPES:
24470025d76Sjohnny 		/* Fixed supported by default */
24570025d76Sjohnny 		*(int *)result = DDI_INTR_TYPE_FIXED;
24670025d76Sjohnny 
24770025d76Sjohnny 		/* Figure out if MSI or MSI-X is supported? */
24870025d76Sjohnny 		if (pci_msi_get_supported_type(rdip, &types) != DDI_SUCCESS)
24970025d76Sjohnny 			return (DDI_SUCCESS);
25070025d76Sjohnny 
25170025d76Sjohnny 		if (psm_intr_ops != NULL) {
25220036fe5Segillett 			/*
25320036fe5Segillett 			 * Only support MSI for now, OR it in
25420036fe5Segillett 			 */
25520036fe5Segillett 			*(int *)result |= (types & DDI_INTR_TYPE_MSI);
25670025d76Sjohnny 
25770025d76Sjohnny 			tmp_hdl.ih_type = *(int *)result;
25870025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, &tmp_hdl,
25970025d76Sjohnny 			    PSM_INTR_OP_CHECK_MSI, result);
26070025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
26170025d76Sjohnny 			    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
26270025d76Sjohnny 			    *(int *)result));
26370025d76Sjohnny 		}
26470025d76Sjohnny 		break;
26570025d76Sjohnny 	case DDI_INTROP_NINTRS:
26670025d76Sjohnny 		if (pci_get_nintrs(rdip, hdlp->ih_type, result) != DDI_SUCCESS)
26770025d76Sjohnny 			return (DDI_FAILURE);
26870025d76Sjohnny 		break;
26970025d76Sjohnny 	case DDI_INTROP_ALLOC:
27070025d76Sjohnny 		/*
27170025d76Sjohnny 		 * MSI or MSIX (figure out number of vectors available)
27270025d76Sjohnny 		 * FIXED interrupts: just return available interrupts
27370025d76Sjohnny 		 */
27470025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
27570025d76Sjohnny 		    (psm_intr_ops != NULL) &&
27670025d76Sjohnny 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
27770025d76Sjohnny 			/*
27870025d76Sjohnny 			 * Following check is a special case for 'pcie_pci'.
27970025d76Sjohnny 			 * This makes sure vectors with the right priority
28070025d76Sjohnny 			 * are allocated for pcie_pci during ALLOC time.
28170025d76Sjohnny 			 */
28270025d76Sjohnny 			if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) {
28370025d76Sjohnny 				hdlp->ih_pri =
28470025d76Sjohnny 				    (pcie_pci_intr_pri_counter % 2) ? 4 : 7;
28570025d76Sjohnny 				pciepci = 1;
28670025d76Sjohnny 			} else
28770025d76Sjohnny 				hdlp->ih_pri = priority;
28880ab886dSwesolows 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
289d12abe7cSanish 
290d12abe7cSanish 			/*
291d12abe7cSanish 			 * Cache in the config handle and cap_ptr
292d12abe7cSanish 			 */
293d12abe7cSanish 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
294d12abe7cSanish 				if (pci_config_setup(rdip, &handle) !=
295d12abe7cSanish 				    DDI_SUCCESS)
296d12abe7cSanish 					return (DDI_FAILURE);
297d12abe7cSanish 				i_ddi_set_pci_config_handle(rdip, handle);
298d12abe7cSanish 			}
299d12abe7cSanish 
300d12abe7cSanish 			if (i_ddi_get_msi_msix_cap_ptr(rdip) == 0) {
301d12abe7cSanish 				char *prop =
302d12abe7cSanish 				    (hdlp->ih_type == DDI_INTR_TYPE_MSI) ?
303d12abe7cSanish 				    "pci-msi-capid-pointer" :
304d12abe7cSanish 				    "pci-msix-capid-pointer";
305d12abe7cSanish 
306d12abe7cSanish 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
307d12abe7cSanish 				    DDI_PROP_DONTPASS, prop,
308d12abe7cSanish 				    PCI_CAP_NEXT_PTR_NULL);
309d12abe7cSanish 				i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
310d12abe7cSanish 			}
311d12abe7cSanish 
312d12abe7cSanish 
31370025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
31470025d76Sjohnny 			    PSM_INTR_OP_ALLOC_VECTORS, result);
31570025d76Sjohnny 
31670025d76Sjohnny 			/* verify behavior flag and take appropriate action */
31770025d76Sjohnny 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
31870025d76Sjohnny 			    (*(int *)result < hdlp->ih_scratch1)) {
31970025d76Sjohnny 				DDI_INTR_NEXDBG((CE_CONT,
32070025d76Sjohnny 				    "pci_common_intr_ops: behavior %x, "
32170025d76Sjohnny 				    "couldn't get enough intrs\n", behavior));
32270025d76Sjohnny 				hdlp->ih_scratch1 = *(int *)result;
32370025d76Sjohnny 				(void) (*psm_intr_ops)(rdip, hdlp,
32470025d76Sjohnny 				    PSM_INTR_OP_FREE_VECTORS, NULL);
32570025d76Sjohnny 				return (DDI_EAGAIN);
32670025d76Sjohnny 			}
32770025d76Sjohnny 
32870025d76Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
32970025d76Sjohnny 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
33070025d76Sjohnny 					msix_p = pci_msix_init(hdlp->ih_dip);
33170025d76Sjohnny 					if (msix_p)
33270025d76Sjohnny 						i_ddi_set_msix(hdlp->ih_dip,
33370025d76Sjohnny 						    msix_p);
33470025d76Sjohnny 				}
33570025d76Sjohnny 			}
33670025d76Sjohnny 
33770025d76Sjohnny 			if (pciepci) {
33870025d76Sjohnny 				/* update priority in ispec */
33970025d76Sjohnny 				isp = pci_intx_get_ispec(pdip, rdip,
34070025d76Sjohnny 					(int)hdlp->ih_inum);
34170025d76Sjohnny 				ispec = (struct intrspec *)isp;
34270025d76Sjohnny 				if (ispec)
34370025d76Sjohnny 					ispec->intrspec_pri = hdlp->ih_pri;
34470025d76Sjohnny 				++pcie_pci_intr_pri_counter;
34570025d76Sjohnny 			}
34670025d76Sjohnny 
34770025d76Sjohnny 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
34870025d76Sjohnny 			/* Figure out if this device supports MASKING */
34970025d76Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
35070025d76Sjohnny 			if (pci_rval == DDI_SUCCESS && pci_status)
35170025d76Sjohnny 				hdlp->ih_cap |= pci_status;
35270025d76Sjohnny 			*(int *)result = 1;	/* DDI_INTR_TYPE_FIXED */
35370025d76Sjohnny 		} else
35470025d76Sjohnny 			return (DDI_FAILURE);
35570025d76Sjohnny 		break;
35670025d76Sjohnny 	case DDI_INTROP_FREE:
35770025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
35870025d76Sjohnny 		    (psm_intr_ops != NULL)) {
359*68565200Sanish 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
360*68565200Sanish 			    0) {
361d12abe7cSanish 				if (handle = i_ddi_get_pci_config_handle(
362d12abe7cSanish 				    rdip)) {
363d12abe7cSanish 					(void) pci_config_teardown(&handle);
364d12abe7cSanish 					i_ddi_set_pci_config_handle(rdip, NULL);
365d12abe7cSanish 				}
366d12abe7cSanish 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
367d12abe7cSanish 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
368d12abe7cSanish 			}
369d12abe7cSanish 
37070025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
37170025d76Sjohnny 			    PSM_INTR_OP_FREE_VECTORS, NULL);
37270025d76Sjohnny 
37370025d76Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
37470025d76Sjohnny 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
37570025d76Sjohnny 				if (msix_p &&
376*68565200Sanish 				    (i_ddi_intr_get_current_nintrs(
377*68565200Sanish 					hdlp->ih_dip) - 1) == 0) {
37870025d76Sjohnny 					pci_msix_fini(msix_p);
37970025d76Sjohnny 					i_ddi_set_msix(hdlp->ih_dip, NULL);
38070025d76Sjohnny 				}
38170025d76Sjohnny 			}
38270025d76Sjohnny 		}
38370025d76Sjohnny 		break;
38470025d76Sjohnny 	case DDI_INTROP_GETPRI:
38570025d76Sjohnny 		/* Get the priority */
38670025d76Sjohnny 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
38770025d76Sjohnny 			return (DDI_FAILURE);
38870025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
38970025d76Sjohnny 		    "priority = 0x%x\n", priority));
39070025d76Sjohnny 		*(int *)result = priority;
39170025d76Sjohnny 		break;
39270025d76Sjohnny 	case DDI_INTROP_SETPRI:
39370025d76Sjohnny 		/* Validate the interrupt priority passed */
39470025d76Sjohnny 		if (*(int *)result > LOCK_LEVEL)
39570025d76Sjohnny 			return (DDI_FAILURE);
39670025d76Sjohnny 
39770025d76Sjohnny 		/* Ensure that PSM is all initialized */
39870025d76Sjohnny 		if (psm_intr_ops == NULL)
39970025d76Sjohnny 			return (DDI_FAILURE);
40070025d76Sjohnny 
40170025d76Sjohnny 		/* Change the priority */
40270025d76Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
40370025d76Sjohnny 		    PSM_FAILURE)
40470025d76Sjohnny 			return (DDI_FAILURE);
40570025d76Sjohnny 
40670025d76Sjohnny 		/* update ispec */
40770025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
40870025d76Sjohnny 		ispec = (struct intrspec *)isp;
40970025d76Sjohnny 		if (ispec)
41070025d76Sjohnny 			ispec->intrspec_pri = *(int *)result;
41170025d76Sjohnny 		break;
41270025d76Sjohnny 	case DDI_INTROP_ADDISR:
41370025d76Sjohnny 		/* update ispec */
41470025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
41570025d76Sjohnny 		ispec = (struct intrspec *)isp;
416e1d9f4e6Sschwartz 		if (ispec) {
41770025d76Sjohnny 			ispec->intrspec_func = hdlp->ih_cb_func;
418e1d9f4e6Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
419e1d9f4e6Sschwartz 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
420e1d9f4e6Sschwartz 		}
42170025d76Sjohnny 		break;
42270025d76Sjohnny 	case DDI_INTROP_REMISR:
42370025d76Sjohnny 		/* Get the interrupt structure pointer */
42470025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
42570025d76Sjohnny 		ispec = (struct intrspec *)isp;
426e1d9f4e6Sschwartz 		if (ispec) {
42770025d76Sjohnny 			ispec->intrspec_func = (uint_t (*)()) 0;
428e1d9f4e6Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
429e1d9f4e6Sschwartz 			if (ihdl_plat_datap->ip_ksp != NULL)
430e1d9f4e6Sschwartz 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
431e1d9f4e6Sschwartz 		}
43270025d76Sjohnny 		break;
43370025d76Sjohnny 	case DDI_INTROP_GETCAP:
43470025d76Sjohnny 		/*
43570025d76Sjohnny 		 * First check the config space and/or
43670025d76Sjohnny 		 * MSI capability register(s)
43770025d76Sjohnny 		 */
43870025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
43970025d76Sjohnny 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
44070025d76Sjohnny 			    &pci_status);
44170025d76Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
44270025d76Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
44370025d76Sjohnny 
44470025d76Sjohnny 		/* next check with pcplusmp */
44570025d76Sjohnny 		if (psm_intr_ops != NULL)
44670025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
44770025d76Sjohnny 			    PSM_INTR_OP_GET_CAP, &psm_status);
44870025d76Sjohnny 
44970025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
45070025d76Sjohnny 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
45170025d76Sjohnny 		    psm_rval, psm_status, pci_rval, pci_status));
45270025d76Sjohnny 
45370025d76Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
45470025d76Sjohnny 			*(int *)result = 0;
45570025d76Sjohnny 			return (DDI_FAILURE);
45670025d76Sjohnny 		}
45770025d76Sjohnny 
45870025d76Sjohnny 		if (psm_rval == PSM_SUCCESS)
45970025d76Sjohnny 			*(int *)result = psm_status;
46070025d76Sjohnny 
46170025d76Sjohnny 		if (pci_rval == DDI_SUCCESS)
46270025d76Sjohnny 			*(int *)result |= pci_status;
46370025d76Sjohnny 
46470025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
46570025d76Sjohnny 		    *(int *)result));
46670025d76Sjohnny 		break;
46770025d76Sjohnny 	case DDI_INTROP_SETCAP:
46870025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
46970025d76Sjohnny 		    "SETCAP cap=0x%x\n", *(int *)result));
47070025d76Sjohnny 		if (psm_intr_ops == NULL)
47170025d76Sjohnny 			return (DDI_FAILURE);
47270025d76Sjohnny 
47370025d76Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
47470025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
47570025d76Sjohnny 			    " returned failure\n"));
47670025d76Sjohnny 			return (DDI_FAILURE);
47770025d76Sjohnny 		}
47870025d76Sjohnny 		break;
47970025d76Sjohnny 	case DDI_INTROP_ENABLE:
48070025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
48170025d76Sjohnny 		if (psm_intr_ops == NULL)
48270025d76Sjohnny 			return (DDI_FAILURE);
48370025d76Sjohnny 
48470025d76Sjohnny 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
48570025d76Sjohnny 		    DDI_SUCCESS)
48670025d76Sjohnny 			return (DDI_FAILURE);
48770025d76Sjohnny 
48870025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
48970025d76Sjohnny 		    "vector=0x%x\n", hdlp->ih_vector));
49070025d76Sjohnny 		break;
49170025d76Sjohnny 	case DDI_INTROP_DISABLE:
49270025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
49370025d76Sjohnny 		if (psm_intr_ops == NULL)
49470025d76Sjohnny 			return (DDI_FAILURE);
49570025d76Sjohnny 
49670025d76Sjohnny 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
49770025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
49870025d76Sjohnny 		    "vector = %x\n", hdlp->ih_vector));
49970025d76Sjohnny 		break;
50070025d76Sjohnny 	case DDI_INTROP_BLOCKENABLE:
50170025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
50270025d76Sjohnny 		    "BLOCKENABLE\n"));
50370025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
50470025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
50570025d76Sjohnny 			return (DDI_FAILURE);
50670025d76Sjohnny 		}
50770025d76Sjohnny 
50870025d76Sjohnny 		/* Check if psm_intr_ops is NULL? */
50970025d76Sjohnny 		if (psm_intr_ops == NULL)
51070025d76Sjohnny 			return (DDI_FAILURE);
51170025d76Sjohnny 
512102cb92eSjohnny 		count = hdlp->ih_scratch1;
513102cb92eSjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
514102cb92eSjohnny 		for (i = 0; i < count; i++) {
515102cb92eSjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
51670025d76Sjohnny 			if (pci_enable_intr(pdip, rdip, hdlp,
517102cb92eSjohnny 			    hdlp->ih_inum) != DDI_SUCCESS) {
51870025d76Sjohnny 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
51970025d76Sjohnny 				    "pci_enable_intr failed for %d\n", i));
520102cb92eSjohnny 				for (j = 0; j < i; j++) {
521102cb92eSjohnny 				    hdlp = (ddi_intr_handle_impl_t *)h_array[j];
52270025d76Sjohnny 				    pci_disable_intr(pdip, rdip, hdlp,
523102cb92eSjohnny 					    hdlp->ih_inum);
524102cb92eSjohnny 				}
52570025d76Sjohnny 				return (DDI_FAILURE);
52670025d76Sjohnny 			}
52770025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
528102cb92eSjohnny 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
52970025d76Sjohnny 		}
53070025d76Sjohnny 		break;
53170025d76Sjohnny 	case DDI_INTROP_BLOCKDISABLE:
53270025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
53370025d76Sjohnny 		    "BLOCKDISABLE\n"));
53470025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
53570025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
53670025d76Sjohnny 			return (DDI_FAILURE);
53770025d76Sjohnny 		}
53870025d76Sjohnny 
53970025d76Sjohnny 		/* Check if psm_intr_ops is present */
54070025d76Sjohnny 		if (psm_intr_ops == NULL)
54170025d76Sjohnny 			return (DDI_FAILURE);
54270025d76Sjohnny 
543102cb92eSjohnny 		count = hdlp->ih_scratch1;
544102cb92eSjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
545102cb92eSjohnny 		for (i = 0; i < count; i++) {
546102cb92eSjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
547102cb92eSjohnny 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
54870025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
549102cb92eSjohnny 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
55070025d76Sjohnny 		}
55170025d76Sjohnny 		break;
55270025d76Sjohnny 	case DDI_INTROP_SETMASK:
55370025d76Sjohnny 	case DDI_INTROP_CLRMASK:
55470025d76Sjohnny 		/*
55570025d76Sjohnny 		 * First handle in the config space
55670025d76Sjohnny 		 */
55770025d76Sjohnny 		if (intr_op == DDI_INTROP_SETMASK) {
55870025d76Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
55970025d76Sjohnny 				pci_status = pci_msi_set_mask(rdip,
56070025d76Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
56170025d76Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
56270025d76Sjohnny 				pci_status = pci_intx_set_mask(rdip);
56370025d76Sjohnny 		} else {
56470025d76Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
56570025d76Sjohnny 				pci_status = pci_msi_clr_mask(rdip,
56670025d76Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
56770025d76Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
56870025d76Sjohnny 				pci_status = pci_intx_clr_mask(rdip);
56970025d76Sjohnny 		}
57070025d76Sjohnny 
57170025d76Sjohnny 		/* For MSI/X; no need to check with pcplusmp */
57270025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
57370025d76Sjohnny 			return (pci_status);
57470025d76Sjohnny 
57570025d76Sjohnny 		/* For fixed interrupts only: handle config space first */
57670025d76Sjohnny 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
57770025d76Sjohnny 		    pci_status == DDI_SUCCESS)
57870025d76Sjohnny 			break;
57970025d76Sjohnny 
58070025d76Sjohnny 		/* For fixed interrupts only: confer with pcplusmp next */
58170025d76Sjohnny 		if (psm_intr_ops != NULL) {
58270025d76Sjohnny 			/* If interrupt is shared; do nothing */
58370025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
58470025d76Sjohnny 			    PSM_INTR_OP_GET_SHARED, &psm_status);
58570025d76Sjohnny 
58670025d76Sjohnny 			if (psm_rval == PSM_FAILURE || psm_status == 1)
58770025d76Sjohnny 				return (pci_status);
58870025d76Sjohnny 
58970025d76Sjohnny 			/* Now, pcplusmp should try to set/clear the mask */
59070025d76Sjohnny 			if (intr_op == DDI_INTROP_SETMASK)
59170025d76Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
59270025d76Sjohnny 				    PSM_INTR_OP_SET_MASK, NULL);
59370025d76Sjohnny 			else
59470025d76Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
59570025d76Sjohnny 				    PSM_INTR_OP_CLEAR_MASK, NULL);
59670025d76Sjohnny 		}
59770025d76Sjohnny 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
59870025d76Sjohnny 	case DDI_INTROP_GETPENDING:
59970025d76Sjohnny 		/*
60070025d76Sjohnny 		 * First check the config space and/or
60170025d76Sjohnny 		 * MSI capability register(s)
60270025d76Sjohnny 		 */
60370025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
60470025d76Sjohnny 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
60570025d76Sjohnny 			    hdlp->ih_inum, &pci_status);
60670025d76Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
60770025d76Sjohnny 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
60870025d76Sjohnny 
60970025d76Sjohnny 		/* On failure; next try with pcplusmp */
61070025d76Sjohnny 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
61170025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
61270025d76Sjohnny 			    PSM_INTR_OP_GET_PENDING, &psm_status);
61370025d76Sjohnny 
61470025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
61570025d76Sjohnny 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
61670025d76Sjohnny 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
61770025d76Sjohnny 		    pci_status));
61870025d76Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
61970025d76Sjohnny 			*(int *)result = 0;
62070025d76Sjohnny 			return (DDI_FAILURE);
62170025d76Sjohnny 		}
62270025d76Sjohnny 
62370025d76Sjohnny 		if (psm_rval != PSM_FAILURE)
62470025d76Sjohnny 			*(int *)result = psm_status;
62570025d76Sjohnny 		else if (pci_rval != DDI_FAILURE)
62670025d76Sjohnny 			*(int *)result = pci_status;
62770025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
62870025d76Sjohnny 		    *(int *)result));
62970025d76Sjohnny 		break;
63070025d76Sjohnny 	case DDI_INTROP_NAVAIL:
63170025d76Sjohnny 		if ((psm_intr_ops != NULL) && (pci_get_priority(rdip,
63270025d76Sjohnny 		    hdlp, &priority) == DDI_SUCCESS)) {
63370025d76Sjohnny 			/* Priority in the handle not initialized yet */
63470025d76Sjohnny 			hdlp->ih_pri = priority;
63570025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
63670025d76Sjohnny 			    PSM_INTR_OP_NAVAIL_VECTORS, result);
63770025d76Sjohnny 		} else {
63870025d76Sjohnny 			*(int *)result = 1;
63970025d76Sjohnny 		}
64070025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: NAVAIL returned = %x\n",
64170025d76Sjohnny 		    *(int *)result));
64270025d76Sjohnny 		break;
64370025d76Sjohnny 	default:
64470025d76Sjohnny 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
64570025d76Sjohnny 	}
64670025d76Sjohnny 
64770025d76Sjohnny 	return (DDI_SUCCESS);
64870025d76Sjohnny }
64970025d76Sjohnny 
6507a364d25Sschwartz int
6517a364d25Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
6527a364d25Sschwartz     int vecirq, boolean_t is_irq)
6537a364d25Sschwartz {
6547a364d25Sschwartz 	ddi_intr_handle_impl_t	get_info_ii_hdl;
6557a364d25Sschwartz 
6567a364d25Sschwartz 	if (is_irq)
6577a364d25Sschwartz 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
6587a364d25Sschwartz 
6597a364d25Sschwartz 	/*
6607a364d25Sschwartz 	 * For this locally-declared and used handle, ih_private will contain a
6617a364d25Sschwartz 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
6627a364d25Sschwartz 	 * global interrupt handling.
6637a364d25Sschwartz 	 */
6647a364d25Sschwartz 	get_info_ii_hdl.ih_private = intrinfo_p;
6657a364d25Sschwartz 	get_info_ii_hdl.ih_vector = (ushort_t)vecirq;
6667a364d25Sschwartz 
6677a364d25Sschwartz 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
6687a364d25Sschwartz 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
6697a364d25Sschwartz 		return (DDI_FAILURE);
6707a364d25Sschwartz 
6717a364d25Sschwartz 	return (DDI_SUCCESS);
6727a364d25Sschwartz }
6737a364d25Sschwartz 
6747a364d25Sschwartz 
6757a364d25Sschwartz int
6767a364d25Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
6777a364d25Sschwartz {
6787a364d25Sschwartz 	int rval;
6797a364d25Sschwartz 
6807a364d25Sschwartz 	apic_get_intr_t	intrinfo;
6817a364d25Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
6827a364d25Sschwartz 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
6837a364d25Sschwartz 
6847a364d25Sschwartz 	if (rval == DDI_SUCCESS)
6857a364d25Sschwartz 		return (intrinfo.avgi_cpu_id);
6867a364d25Sschwartz 	else
6877a364d25Sschwartz 		return (-1);
6887a364d25Sschwartz }
6897a364d25Sschwartz 
69070025d76Sjohnny 
69170025d76Sjohnny static int
69270025d76Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
69370025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
69470025d76Sjohnny {
69570025d76Sjohnny 	struct intrspec	*ispec;
6967a364d25Sschwartz 	int		irq;
6977a364d25Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
69870025d76Sjohnny 
69970025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
70070025d76Sjohnny 	    (void *)hdlp, inum));
70170025d76Sjohnny 
70270025d76Sjohnny 	/* Translate the interrupt if needed */
70370025d76Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
70470025d76Sjohnny 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && ispec)
70570025d76Sjohnny 		ispec->intrspec_vec = inum;
7067a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
70770025d76Sjohnny 
70870025d76Sjohnny 	/* translate the interrupt if needed */
7097a364d25Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
7107a364d25Sschwartz 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
7117a364d25Sschwartz 	    hdlp->ih_pri, irq));
71270025d76Sjohnny 
71370025d76Sjohnny 	/* Add the interrupt handler */
71470025d76Sjohnny 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
7157a364d25Sschwartz 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
7167a364d25Sschwartz 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
71770025d76Sjohnny 		return (DDI_FAILURE);
71870025d76Sjohnny 
7197a364d25Sschwartz 	/* Note this really is an irq. */
7207a364d25Sschwartz 	hdlp->ih_vector = (ushort_t)irq;
7217a364d25Sschwartz 
72270025d76Sjohnny 	return (DDI_SUCCESS);
72370025d76Sjohnny }
72470025d76Sjohnny 
72570025d76Sjohnny 
72670025d76Sjohnny static void
72770025d76Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
72870025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
72970025d76Sjohnny {
7307a364d25Sschwartz 	int		irq;
73170025d76Sjohnny 	struct intrspec	*ispec;
7327a364d25Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
73370025d76Sjohnny 
73470025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
73570025d76Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
73670025d76Sjohnny 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && ispec)
73770025d76Sjohnny 		ispec->intrspec_vec = inum;
7387a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
73970025d76Sjohnny 
74070025d76Sjohnny 	/* translate the interrupt if needed */
7417a364d25Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
74270025d76Sjohnny 
74370025d76Sjohnny 	/* Disable the interrupt handler */
7447a364d25Sschwartz 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
7457a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = NULL;
74670025d76Sjohnny }
74770025d76Sjohnny 
74870025d76Sjohnny /*
74970025d76Sjohnny  * Miscellaneous library function
75070025d76Sjohnny  */
75170025d76Sjohnny int
75270025d76Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
75370025d76Sjohnny {
75470025d76Sjohnny 	int		i;
75570025d76Sjohnny 	int 		number;
75670025d76Sjohnny 	int		assigned_addr_len;
75770025d76Sjohnny 	uint_t		phys_hi = pci_rp->pci_phys_hi;
75870025d76Sjohnny 	pci_regspec_t	*assigned_addr;
75970025d76Sjohnny 
76070025d76Sjohnny 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
76170025d76Sjohnny 	    (phys_hi & PCI_RELOCAT_B))
76270025d76Sjohnny 		return (DDI_SUCCESS);
76370025d76Sjohnny 
76470025d76Sjohnny 	/*
76570025d76Sjohnny 	 * the "reg" property specifies relocatable, get and interpret the
76670025d76Sjohnny 	 * "assigned-addresses" property.
76770025d76Sjohnny 	 */
76870025d76Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
76970025d76Sjohnny 	    "assigned-addresses", (int **)&assigned_addr,
77070025d76Sjohnny 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
77170025d76Sjohnny 		return (DDI_FAILURE);
77270025d76Sjohnny 
77370025d76Sjohnny 	/*
77470025d76Sjohnny 	 * Scan the "assigned-addresses" for one that matches the specified
77570025d76Sjohnny 	 * "reg" property entry.
77670025d76Sjohnny 	 */
77770025d76Sjohnny 	phys_hi &= PCI_CONF_ADDR_MASK;
77870025d76Sjohnny 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
77970025d76Sjohnny 	for (i = 0; i < number; i++) {
78070025d76Sjohnny 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
78170025d76Sjohnny 		    phys_hi) {
78270025d76Sjohnny 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
78370025d76Sjohnny 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
78470025d76Sjohnny 			ddi_prop_free(assigned_addr);
78570025d76Sjohnny 			return (DDI_SUCCESS);
78670025d76Sjohnny 		}
78770025d76Sjohnny 	}
78870025d76Sjohnny 
78970025d76Sjohnny 	ddi_prop_free(assigned_addr);
79070025d76Sjohnny 	return (DDI_FAILURE);
79170025d76Sjohnny }
79270025d76Sjohnny 
79370025d76Sjohnny 
79470025d76Sjohnny /*
79570025d76Sjohnny  * For pci_tools
79670025d76Sjohnny  */
79770025d76Sjohnny 
79870025d76Sjohnny int
79970025d76Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
80070025d76Sjohnny     int mode, cred_t *credp, int *rvalp)
80170025d76Sjohnny {
80270025d76Sjohnny 	int rv = ENOTTY;
80370025d76Sjohnny 
80470025d76Sjohnny 	minor_t minor = getminor(dev);
80570025d76Sjohnny 
80670025d76Sjohnny 	switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
80770025d76Sjohnny 	case PCI_TOOL_REG_MINOR_NUM:
80870025d76Sjohnny 
80970025d76Sjohnny 		switch (cmd) {
81070025d76Sjohnny 		case PCITOOL_DEVICE_SET_REG:
81170025d76Sjohnny 		case PCITOOL_DEVICE_GET_REG:
81270025d76Sjohnny 
81370025d76Sjohnny 			/* Require full privileges. */
81470025d76Sjohnny 			if (secpolicy_kmdb(credp))
81570025d76Sjohnny 				rv = EPERM;
81670025d76Sjohnny 			else
81770025d76Sjohnny 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
81870025d76Sjohnny 				    cmd, mode);
81970025d76Sjohnny 			break;
82070025d76Sjohnny 
82170025d76Sjohnny 		case PCITOOL_NEXUS_SET_REG:
82270025d76Sjohnny 		case PCITOOL_NEXUS_GET_REG:
82370025d76Sjohnny 
82470025d76Sjohnny 			/* Require full privileges. */
82570025d76Sjohnny 			if (secpolicy_kmdb(credp))
82670025d76Sjohnny 				rv = EPERM;
82770025d76Sjohnny 			else
82870025d76Sjohnny 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
82970025d76Sjohnny 				    cmd, mode);
83070025d76Sjohnny 			break;
83170025d76Sjohnny 		}
83270025d76Sjohnny 		break;
83370025d76Sjohnny 
83470025d76Sjohnny 	case PCI_TOOL_INTR_MINOR_NUM:
83570025d76Sjohnny 
83670025d76Sjohnny 		switch (cmd) {
83770025d76Sjohnny 		case PCITOOL_DEVICE_SET_INTR:
83870025d76Sjohnny 
83970025d76Sjohnny 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
84070025d76Sjohnny 			if (secpolicy_ponline(credp)) {
84170025d76Sjohnny 				rv = EPERM;
84270025d76Sjohnny 				break;
84370025d76Sjohnny 			}
84470025d76Sjohnny 
84570025d76Sjohnny 		/*FALLTHRU*/
84670025d76Sjohnny 		/* These require no special privileges. */
84770025d76Sjohnny 		case PCITOOL_DEVICE_GET_INTR:
84870025d76Sjohnny 		case PCITOOL_DEVICE_NUM_INTR:
84970025d76Sjohnny 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
85070025d76Sjohnny 			break;
85170025d76Sjohnny 		}
85270025d76Sjohnny 		break;
85370025d76Sjohnny 
85470025d76Sjohnny 	/*
85570025d76Sjohnny 	 * All non-PCItool ioctls go through here, including:
85670025d76Sjohnny 	 *   devctl ioctls with minor number PCIHP_DEVCTL_MINOR and
85770025d76Sjohnny 	 *   those for attachment points with where minor number is the
85870025d76Sjohnny 	 *   device number.
85970025d76Sjohnny 	 */
86070025d76Sjohnny 	default:
86170025d76Sjohnny 		rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode,
86270025d76Sjohnny 		    credp, rvalp);
86370025d76Sjohnny 		break;
86470025d76Sjohnny 	}
86570025d76Sjohnny 
86670025d76Sjohnny 	return (rv);
86770025d76Sjohnny }
868649d4cceSanish 
869649d4cceSanish 
87000d0963fSdilpreet int
87100d0963fSdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
87200d0963fSdilpreet {
87300d0963fSdilpreet 	size_t size = in_args->size;
87400d0963fSdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
87500d0963fSdilpreet 	uintptr_t host_addr = in_args->host_addr;
87600d0963fSdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
87700d0963fSdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
87800d0963fSdilpreet 	size_t repcount = in_args->repcount;
87900d0963fSdilpreet 	uint_t flags = in_args->flags;
88000d0963fSdilpreet 	int err = DDI_SUCCESS;
88100d0963fSdilpreet 
88200d0963fSdilpreet 	/*
88300d0963fSdilpreet 	 * if no handle then this is a poke. We have to return failure here
88400d0963fSdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
88500d0963fSdilpreet 	 */
88600d0963fSdilpreet 	if (in_args->handle == NULL)
88700d0963fSdilpreet 		return (DDI_FAILURE);
88800d0963fSdilpreet 
88900d0963fSdilpreet 	/*
89000d0963fSdilpreet 	 * rest of this function is actually for cautious puts
89100d0963fSdilpreet 	 */
89200d0963fSdilpreet 	for (; repcount; repcount--) {
89300d0963fSdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
89400d0963fSdilpreet 			switch (size) {
89500d0963fSdilpreet 			case sizeof (uint8_t):
89600d0963fSdilpreet 				pci_config_wr8(hp, (uint8_t *)dev_addr,
89700d0963fSdilpreet 				    *(uint8_t *)host_addr);
89800d0963fSdilpreet 				break;
89900d0963fSdilpreet 			case sizeof (uint16_t):
90000d0963fSdilpreet 				pci_config_wr16(hp, (uint16_t *)dev_addr,
90100d0963fSdilpreet 				    *(uint16_t *)host_addr);
90200d0963fSdilpreet 				break;
90300d0963fSdilpreet 			case sizeof (uint32_t):
90400d0963fSdilpreet 				pci_config_wr32(hp, (uint32_t *)dev_addr,
90500d0963fSdilpreet 				    *(uint32_t *)host_addr);
90600d0963fSdilpreet 				break;
90700d0963fSdilpreet 			case sizeof (uint64_t):
90800d0963fSdilpreet 				pci_config_wr64(hp, (uint64_t *)dev_addr,
90900d0963fSdilpreet 				    *(uint64_t *)host_addr);
91000d0963fSdilpreet 				break;
91100d0963fSdilpreet 			default:
91200d0963fSdilpreet 				err = DDI_FAILURE;
91300d0963fSdilpreet 				break;
91400d0963fSdilpreet 			}
91500d0963fSdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
91600d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
91700d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
91800d0963fSdilpreet 				switch (size) {
91900d0963fSdilpreet 				case sizeof (uint8_t):
92000d0963fSdilpreet 					i_ddi_io_put8(hp,
92100d0963fSdilpreet 					    (uint8_t *)dev_addr,
92200d0963fSdilpreet 					    *(uint8_t *)host_addr);
92300d0963fSdilpreet 					break;
92400d0963fSdilpreet 				case sizeof (uint16_t):
92500d0963fSdilpreet 					i_ddi_io_swap_put16(hp,
92600d0963fSdilpreet 					    (uint16_t *)dev_addr,
92700d0963fSdilpreet 					    *(uint16_t *)host_addr);
92800d0963fSdilpreet 					break;
92900d0963fSdilpreet 				case sizeof (uint32_t):
93000d0963fSdilpreet 					i_ddi_io_swap_put32(hp,
93100d0963fSdilpreet 					    (uint32_t *)dev_addr,
93200d0963fSdilpreet 					    *(uint32_t *)host_addr);
93300d0963fSdilpreet 					break;
93400d0963fSdilpreet 				/*
93500d0963fSdilpreet 				 * note the 64-bit case is a dummy
93600d0963fSdilpreet 				 * function - so no need to swap
93700d0963fSdilpreet 				 */
93800d0963fSdilpreet 				case sizeof (uint64_t):
93900d0963fSdilpreet 					i_ddi_io_put64(hp,
94000d0963fSdilpreet 					    (uint64_t *)dev_addr,
94100d0963fSdilpreet 					    *(uint64_t *)host_addr);
94200d0963fSdilpreet 					break;
94300d0963fSdilpreet 				default:
94400d0963fSdilpreet 					err = DDI_FAILURE;
94500d0963fSdilpreet 					break;
94600d0963fSdilpreet 				}
94700d0963fSdilpreet 			} else {
94800d0963fSdilpreet 				switch (size) {
94900d0963fSdilpreet 				case sizeof (uint8_t):
95000d0963fSdilpreet 					i_ddi_io_put8(hp,
95100d0963fSdilpreet 					    (uint8_t *)dev_addr,
95200d0963fSdilpreet 					    *(uint8_t *)host_addr);
95300d0963fSdilpreet 					break;
95400d0963fSdilpreet 				case sizeof (uint16_t):
95500d0963fSdilpreet 					i_ddi_io_put16(hp,
95600d0963fSdilpreet 					    (uint16_t *)dev_addr,
95700d0963fSdilpreet 					    *(uint16_t *)host_addr);
95800d0963fSdilpreet 					break;
95900d0963fSdilpreet 				case sizeof (uint32_t):
96000d0963fSdilpreet 					i_ddi_io_put32(hp,
96100d0963fSdilpreet 					    (uint32_t *)dev_addr,
96200d0963fSdilpreet 					    *(uint32_t *)host_addr);
96300d0963fSdilpreet 					break;
96400d0963fSdilpreet 				case sizeof (uint64_t):
96500d0963fSdilpreet 					i_ddi_io_put64(hp,
96600d0963fSdilpreet 					    (uint64_t *)dev_addr,
96700d0963fSdilpreet 					    *(uint64_t *)host_addr);
96800d0963fSdilpreet 					break;
96900d0963fSdilpreet 				default:
97000d0963fSdilpreet 					err = DDI_FAILURE;
97100d0963fSdilpreet 					break;
97200d0963fSdilpreet 				}
97300d0963fSdilpreet 			}
97400d0963fSdilpreet 		} else {
97500d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
97600d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
97700d0963fSdilpreet 				switch (size) {
97800d0963fSdilpreet 				case sizeof (uint8_t):
97900d0963fSdilpreet 					*(uint8_t *)dev_addr =
98000d0963fSdilpreet 					    *(uint8_t *)host_addr;
98100d0963fSdilpreet 					break;
98200d0963fSdilpreet 				case sizeof (uint16_t):
98300d0963fSdilpreet 					*(uint16_t *)dev_addr =
98400d0963fSdilpreet 					    ddi_swap16(*(uint16_t *)host_addr);
98500d0963fSdilpreet 					break;
98600d0963fSdilpreet 				case sizeof (uint32_t):
98700d0963fSdilpreet 					*(uint32_t *)dev_addr =
98800d0963fSdilpreet 					    ddi_swap32(*(uint32_t *)host_addr);
98900d0963fSdilpreet 					break;
99000d0963fSdilpreet 				case sizeof (uint64_t):
99100d0963fSdilpreet 					*(uint64_t *)dev_addr =
99200d0963fSdilpreet 					    ddi_swap64(*(uint64_t *)host_addr);
99300d0963fSdilpreet 					break;
99400d0963fSdilpreet 				default:
99500d0963fSdilpreet 					err = DDI_FAILURE;
99600d0963fSdilpreet 					break;
99700d0963fSdilpreet 				}
99800d0963fSdilpreet 			} else {
99900d0963fSdilpreet 				switch (size) {
100000d0963fSdilpreet 				case sizeof (uint8_t):
100100d0963fSdilpreet 					*(uint8_t *)dev_addr =
100200d0963fSdilpreet 					    *(uint8_t *)host_addr;
100300d0963fSdilpreet 					break;
100400d0963fSdilpreet 				case sizeof (uint16_t):
100500d0963fSdilpreet 					*(uint16_t *)dev_addr =
100600d0963fSdilpreet 					    *(uint16_t *)host_addr;
100700d0963fSdilpreet 					break;
100800d0963fSdilpreet 				case sizeof (uint32_t):
100900d0963fSdilpreet 					*(uint32_t *)dev_addr =
101000d0963fSdilpreet 					    *(uint32_t *)host_addr;
101100d0963fSdilpreet 					break;
101200d0963fSdilpreet 				case sizeof (uint64_t):
101300d0963fSdilpreet 					*(uint64_t *)dev_addr =
101400d0963fSdilpreet 					    *(uint64_t *)host_addr;
101500d0963fSdilpreet 					break;
101600d0963fSdilpreet 				default:
101700d0963fSdilpreet 					err = DDI_FAILURE;
101800d0963fSdilpreet 					break;
101900d0963fSdilpreet 				}
102000d0963fSdilpreet 			}
102100d0963fSdilpreet 		}
102200d0963fSdilpreet 		host_addr += size;
102300d0963fSdilpreet 		if (flags == DDI_DEV_AUTOINCR)
102400d0963fSdilpreet 			dev_addr += size;
102500d0963fSdilpreet 	}
102600d0963fSdilpreet 	return (err);
102700d0963fSdilpreet }
102800d0963fSdilpreet 
102900d0963fSdilpreet 
103000d0963fSdilpreet int
103100d0963fSdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
103200d0963fSdilpreet {
103300d0963fSdilpreet 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
103400d0963fSdilpreet 
103500d0963fSdilpreet 	/* endian-ness check */
103600d0963fSdilpreet 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
103700d0963fSdilpreet 		return (DDI_FAILURE);
103800d0963fSdilpreet 
103900d0963fSdilpreet 	/*
104000d0963fSdilpreet 	 * range check
104100d0963fSdilpreet 	 */
104200d0963fSdilpreet 	if ((offset >= PCI_CONF_HDR_SIZE) ||
104300d0963fSdilpreet 	    (len > PCI_CONF_HDR_SIZE) ||
104400d0963fSdilpreet 	    (offset + len > PCI_CONF_HDR_SIZE))
104500d0963fSdilpreet 		return (DDI_FAILURE);
104600d0963fSdilpreet 
104700d0963fSdilpreet 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
104800d0963fSdilpreet 	/*
104900d0963fSdilpreet 	 * always use cautious mechanism for config space gets
105000d0963fSdilpreet 	 */
105100d0963fSdilpreet 	ap->ahi_get8 = i_ddi_caut_get8;
105200d0963fSdilpreet 	ap->ahi_get16 = i_ddi_caut_get16;
105300d0963fSdilpreet 	ap->ahi_get32 = i_ddi_caut_get32;
105400d0963fSdilpreet 	ap->ahi_get64 = i_ddi_caut_get64;
105500d0963fSdilpreet 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
105600d0963fSdilpreet 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
105700d0963fSdilpreet 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
105800d0963fSdilpreet 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
105900d0963fSdilpreet 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
106000d0963fSdilpreet 		ap->ahi_put8 = i_ddi_caut_put8;
106100d0963fSdilpreet 		ap->ahi_put16 = i_ddi_caut_put16;
106200d0963fSdilpreet 		ap->ahi_put32 = i_ddi_caut_put32;
106300d0963fSdilpreet 		ap->ahi_put64 = i_ddi_caut_put64;
106400d0963fSdilpreet 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
106500d0963fSdilpreet 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
106600d0963fSdilpreet 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
106700d0963fSdilpreet 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
106800d0963fSdilpreet 	} else {
106900d0963fSdilpreet 		ap->ahi_put8 = pci_config_wr8;
107000d0963fSdilpreet 		ap->ahi_put16 = pci_config_wr16;
107100d0963fSdilpreet 		ap->ahi_put32 = pci_config_wr32;
107200d0963fSdilpreet 		ap->ahi_put64 = pci_config_wr64;
107300d0963fSdilpreet 		ap->ahi_rep_put8 = pci_config_rep_wr8;
107400d0963fSdilpreet 		ap->ahi_rep_put16 = pci_config_rep_wr16;
107500d0963fSdilpreet 		ap->ahi_rep_put32 = pci_config_rep_wr32;
107600d0963fSdilpreet 		ap->ahi_rep_put64 = pci_config_rep_wr64;
107700d0963fSdilpreet 	}
107800d0963fSdilpreet 
107900d0963fSdilpreet 	/* Initialize to default check/notify functions */
108000d0963fSdilpreet 	ap->ahi_fault_check = i_ddi_acc_fault_check;
108100d0963fSdilpreet 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
108200d0963fSdilpreet 	ap->ahi_fault = 0;
108300d0963fSdilpreet 	impl_acc_err_init(hp);
108400d0963fSdilpreet 	return (DDI_SUCCESS);
108500d0963fSdilpreet }
108600d0963fSdilpreet 
108700d0963fSdilpreet 
108800d0963fSdilpreet int
108900d0963fSdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
109000d0963fSdilpreet {
109100d0963fSdilpreet 	size_t size = in_args->size;
109200d0963fSdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
109300d0963fSdilpreet 	uintptr_t host_addr = in_args->host_addr;
109400d0963fSdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
109500d0963fSdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
109600d0963fSdilpreet 	size_t repcount = in_args->repcount;
109700d0963fSdilpreet 	uint_t flags = in_args->flags;
109800d0963fSdilpreet 	int err = DDI_SUCCESS;
109900d0963fSdilpreet 
110000d0963fSdilpreet 	/*
110100d0963fSdilpreet 	 * if no handle then this is a peek. We have to return failure here
110200d0963fSdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
110300d0963fSdilpreet 	 */
110400d0963fSdilpreet 	if (in_args->handle == NULL)
110500d0963fSdilpreet 		return (DDI_FAILURE);
110600d0963fSdilpreet 
110700d0963fSdilpreet 	for (; repcount; repcount--) {
110800d0963fSdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
110900d0963fSdilpreet 			switch (size) {
111000d0963fSdilpreet 			case sizeof (uint8_t):
111100d0963fSdilpreet 				*(uint8_t *)host_addr = pci_config_rd8(hp,
111200d0963fSdilpreet 				    (uint8_t *)dev_addr);
111300d0963fSdilpreet 				break;
111400d0963fSdilpreet 			case sizeof (uint16_t):
111500d0963fSdilpreet 				*(uint16_t *)host_addr = pci_config_rd16(hp,
111600d0963fSdilpreet 				    (uint16_t *)dev_addr);
111700d0963fSdilpreet 				break;
111800d0963fSdilpreet 			case sizeof (uint32_t):
111900d0963fSdilpreet 				*(uint32_t *)host_addr = pci_config_rd32(hp,
112000d0963fSdilpreet 				    (uint32_t *)dev_addr);
112100d0963fSdilpreet 				break;
112200d0963fSdilpreet 			case sizeof (uint64_t):
112300d0963fSdilpreet 				*(uint64_t *)host_addr = pci_config_rd64(hp,
112400d0963fSdilpreet 				    (uint64_t *)dev_addr);
112500d0963fSdilpreet 				break;
112600d0963fSdilpreet 			default:
112700d0963fSdilpreet 				err = DDI_FAILURE;
112800d0963fSdilpreet 				break;
112900d0963fSdilpreet 			}
113000d0963fSdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
113100d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
113200d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
113300d0963fSdilpreet 				switch (size) {
113400d0963fSdilpreet 				case sizeof (uint8_t):
113500d0963fSdilpreet 					*(uint8_t *)host_addr =
113600d0963fSdilpreet 					    i_ddi_io_get8(hp,
113700d0963fSdilpreet 					    (uint8_t *)dev_addr);
113800d0963fSdilpreet 					break;
113900d0963fSdilpreet 				case sizeof (uint16_t):
114000d0963fSdilpreet 					*(uint16_t *)host_addr =
114100d0963fSdilpreet 					    i_ddi_io_swap_get16(hp,
114200d0963fSdilpreet 					    (uint16_t *)dev_addr);
114300d0963fSdilpreet 					break;
114400d0963fSdilpreet 				case sizeof (uint32_t):
114500d0963fSdilpreet 					*(uint32_t *)host_addr =
114600d0963fSdilpreet 					    i_ddi_io_swap_get32(hp,
114700d0963fSdilpreet 					    (uint32_t *)dev_addr);
114800d0963fSdilpreet 					break;
114900d0963fSdilpreet 				/*
115000d0963fSdilpreet 				 * note the 64-bit case is a dummy
115100d0963fSdilpreet 				 * function - so no need to swap
115200d0963fSdilpreet 				 */
115300d0963fSdilpreet 				case sizeof (uint64_t):
115400d0963fSdilpreet 					*(uint64_t *)host_addr =
115500d0963fSdilpreet 					    i_ddi_io_get64(hp,
115600d0963fSdilpreet 					    (uint64_t *)dev_addr);
115700d0963fSdilpreet 					break;
115800d0963fSdilpreet 				default:
115900d0963fSdilpreet 					err = DDI_FAILURE;
116000d0963fSdilpreet 					break;
116100d0963fSdilpreet 				}
116200d0963fSdilpreet 			} else {
116300d0963fSdilpreet 				switch (size) {
116400d0963fSdilpreet 				case sizeof (uint8_t):
116500d0963fSdilpreet 					*(uint8_t *)host_addr =
116600d0963fSdilpreet 					    i_ddi_io_get8(hp,
116700d0963fSdilpreet 					    (uint8_t *)dev_addr);
116800d0963fSdilpreet 					break;
116900d0963fSdilpreet 				case sizeof (uint16_t):
117000d0963fSdilpreet 					*(uint16_t *)host_addr =
117100d0963fSdilpreet 					    i_ddi_io_get16(hp,
117200d0963fSdilpreet 					    (uint16_t *)dev_addr);
117300d0963fSdilpreet 					break;
117400d0963fSdilpreet 				case sizeof (uint32_t):
117500d0963fSdilpreet 					*(uint32_t *)host_addr =
117600d0963fSdilpreet 					    i_ddi_io_get32(hp,
117700d0963fSdilpreet 					    (uint32_t *)dev_addr);
117800d0963fSdilpreet 					break;
117900d0963fSdilpreet 				case sizeof (uint64_t):
118000d0963fSdilpreet 					*(uint64_t *)host_addr =
118100d0963fSdilpreet 					    i_ddi_io_get64(hp,
118200d0963fSdilpreet 					    (uint64_t *)dev_addr);
118300d0963fSdilpreet 					break;
118400d0963fSdilpreet 				default:
118500d0963fSdilpreet 					err = DDI_FAILURE;
118600d0963fSdilpreet 					break;
118700d0963fSdilpreet 				}
118800d0963fSdilpreet 			}
118900d0963fSdilpreet 		} else {
119000d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
119100d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
119200d0963fSdilpreet 				switch (in_args->size) {
119300d0963fSdilpreet 				case sizeof (uint8_t):
119400d0963fSdilpreet 					*(uint8_t *)host_addr =
119500d0963fSdilpreet 					    *(uint8_t *)dev_addr;
119600d0963fSdilpreet 					break;
119700d0963fSdilpreet 				case sizeof (uint16_t):
119800d0963fSdilpreet 					*(uint16_t *)host_addr =
119900d0963fSdilpreet 					    ddi_swap16(*(uint16_t *)dev_addr);
120000d0963fSdilpreet 					break;
120100d0963fSdilpreet 				case sizeof (uint32_t):
120200d0963fSdilpreet 					*(uint32_t *)host_addr =
120300d0963fSdilpreet 					    ddi_swap32(*(uint32_t *)dev_addr);
120400d0963fSdilpreet 					break;
120500d0963fSdilpreet 				case sizeof (uint64_t):
120600d0963fSdilpreet 					*(uint64_t *)host_addr =
120700d0963fSdilpreet 					    ddi_swap64(*(uint64_t *)dev_addr);
120800d0963fSdilpreet 					break;
120900d0963fSdilpreet 				default:
121000d0963fSdilpreet 					err = DDI_FAILURE;
121100d0963fSdilpreet 					break;
121200d0963fSdilpreet 				}
121300d0963fSdilpreet 			} else {
121400d0963fSdilpreet 				switch (in_args->size) {
121500d0963fSdilpreet 				case sizeof (uint8_t):
121600d0963fSdilpreet 					*(uint8_t *)host_addr =
121700d0963fSdilpreet 					    *(uint8_t *)dev_addr;
121800d0963fSdilpreet 					break;
121900d0963fSdilpreet 				case sizeof (uint16_t):
122000d0963fSdilpreet 					*(uint16_t *)host_addr =
122100d0963fSdilpreet 					    *(uint16_t *)dev_addr;
122200d0963fSdilpreet 					break;
122300d0963fSdilpreet 				case sizeof (uint32_t):
122400d0963fSdilpreet 					*(uint32_t *)host_addr =
122500d0963fSdilpreet 					    *(uint32_t *)dev_addr;
122600d0963fSdilpreet 					break;
122700d0963fSdilpreet 				case sizeof (uint64_t):
122800d0963fSdilpreet 					*(uint64_t *)host_addr =
122900d0963fSdilpreet 					    *(uint64_t *)dev_addr;
123000d0963fSdilpreet 					break;
123100d0963fSdilpreet 				default:
123200d0963fSdilpreet 					err = DDI_FAILURE;
123300d0963fSdilpreet 					break;
123400d0963fSdilpreet 				}
123500d0963fSdilpreet 			}
123600d0963fSdilpreet 		}
123700d0963fSdilpreet 		host_addr += size;
123800d0963fSdilpreet 		if (flags == DDI_DEV_AUTOINCR)
123900d0963fSdilpreet 			dev_addr += size;
124000d0963fSdilpreet 	}
124100d0963fSdilpreet 	return (err);
124200d0963fSdilpreet }
124300d0963fSdilpreet 
124400d0963fSdilpreet /*ARGSUSED*/
124500d0963fSdilpreet int
124600d0963fSdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
124700d0963fSdilpreet 	ddi_ctl_enum_t ctlop, void *arg, void *result)
124800d0963fSdilpreet {
124900d0963fSdilpreet 	if (ctlop == DDI_CTLOPS_PEEK)
125000d0963fSdilpreet 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
125100d0963fSdilpreet 	else
125200d0963fSdilpreet 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
125300d0963fSdilpreet }
125400d0963fSdilpreet 
1255649d4cceSanish /*
1256649d4cceSanish  * These are the get and put functions to be shared with drivers. The
1257649d4cceSanish  * mutex locking is done inside the functions referenced, rather than
1258649d4cceSanish  * here, and is thus shared across PCI child drivers and any other
1259649d4cceSanish  * consumers of PCI config space (such as the ACPI subsystem).
1260649d4cceSanish  *
1261649d4cceSanish  * The configuration space addresses come in as pointers.  This is fine on
1262649d4cceSanish  * a 32-bit system, where the VM space and configuration space are the same
1263649d4cceSanish  * size.  It's not such a good idea on a 64-bit system, where memory
1264649d4cceSanish  * addresses are twice as large as configuration space addresses.  At some
1265649d4cceSanish  * point in the call tree we need to take a stand and say "you are 32-bit
1266649d4cceSanish  * from this time forth", and this seems like a nice self-contained place.
1267649d4cceSanish  */
1268649d4cceSanish 
1269649d4cceSanish uint8_t
1270649d4cceSanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1271649d4cceSanish {
1272649d4cceSanish 	pci_acc_cfblk_t *cfp;
1273649d4cceSanish 	uint8_t	rval;
1274649d4cceSanish 	int reg;
1275649d4cceSanish 
1276649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1277649d4cceSanish 
1278649d4cceSanish 	reg = (int)(uintptr_t)addr;
1279649d4cceSanish 
1280649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1281649d4cceSanish 
1282649d4cceSanish 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1283649d4cceSanish 	    reg);
1284649d4cceSanish 
1285649d4cceSanish 	return (rval);
1286649d4cceSanish }
1287649d4cceSanish 
1288649d4cceSanish void
1289649d4cceSanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1290649d4cceSanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1291649d4cceSanish {
1292649d4cceSanish 	uint8_t *h, *d;
1293649d4cceSanish 
1294649d4cceSanish 	h = host_addr;
1295649d4cceSanish 	d = dev_addr;
1296649d4cceSanish 
1297649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1298649d4cceSanish 		for (; repcount; repcount--)
1299649d4cceSanish 			*h++ = pci_config_rd8(hdlp, d++);
1300649d4cceSanish 	else
1301649d4cceSanish 		for (; repcount; repcount--)
1302649d4cceSanish 			*h++ = pci_config_rd8(hdlp, d);
1303649d4cceSanish }
1304649d4cceSanish 
1305649d4cceSanish uint16_t
1306649d4cceSanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1307649d4cceSanish {
1308649d4cceSanish 	pci_acc_cfblk_t *cfp;
1309649d4cceSanish 	uint16_t rval;
1310649d4cceSanish 	int reg;
1311649d4cceSanish 
1312649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1313649d4cceSanish 
1314649d4cceSanish 	reg = (int)(uintptr_t)addr;
1315649d4cceSanish 
1316649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1317649d4cceSanish 
1318649d4cceSanish 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1319649d4cceSanish 	    reg);
1320649d4cceSanish 
1321649d4cceSanish 	return (rval);
1322649d4cceSanish }
1323649d4cceSanish 
1324649d4cceSanish void
1325649d4cceSanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1326649d4cceSanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1327649d4cceSanish {
1328649d4cceSanish 	uint16_t *h, *d;
1329649d4cceSanish 
1330649d4cceSanish 	h = host_addr;
1331649d4cceSanish 	d = dev_addr;
1332649d4cceSanish 
1333649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1334649d4cceSanish 		for (; repcount; repcount--)
1335649d4cceSanish 			*h++ = pci_config_rd16(hdlp, d++);
1336649d4cceSanish 	else
1337649d4cceSanish 		for (; repcount; repcount--)
1338649d4cceSanish 			*h++ = pci_config_rd16(hdlp, d);
1339649d4cceSanish }
1340649d4cceSanish 
1341649d4cceSanish uint32_t
1342649d4cceSanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1343649d4cceSanish {
1344649d4cceSanish 	pci_acc_cfblk_t *cfp;
1345649d4cceSanish 	uint32_t rval;
1346649d4cceSanish 	int reg;
1347649d4cceSanish 
1348649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1349649d4cceSanish 
1350649d4cceSanish 	reg = (int)(uintptr_t)addr;
1351649d4cceSanish 
1352649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1353649d4cceSanish 
1354649d4cceSanish 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1355649d4cceSanish 	    cfp->c_funcnum, reg);
1356649d4cceSanish 
1357649d4cceSanish 	return (rval);
1358649d4cceSanish }
1359649d4cceSanish 
1360649d4cceSanish void
1361649d4cceSanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1362649d4cceSanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1363649d4cceSanish {
1364649d4cceSanish 	uint32_t *h, *d;
1365649d4cceSanish 
1366649d4cceSanish 	h = host_addr;
1367649d4cceSanish 	d = dev_addr;
1368649d4cceSanish 
1369649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1370649d4cceSanish 		for (; repcount; repcount--)
1371649d4cceSanish 			*h++ = pci_config_rd32(hdlp, d++);
1372649d4cceSanish 	else
1373649d4cceSanish 		for (; repcount; repcount--)
1374649d4cceSanish 			*h++ = pci_config_rd32(hdlp, d);
1375649d4cceSanish }
1376649d4cceSanish 
1377649d4cceSanish 
1378649d4cceSanish void
1379649d4cceSanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1380649d4cceSanish {
1381649d4cceSanish 	pci_acc_cfblk_t *cfp;
1382649d4cceSanish 	int reg;
1383649d4cceSanish 
1384649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1385649d4cceSanish 
1386649d4cceSanish 	reg = (int)(uintptr_t)addr;
1387649d4cceSanish 
1388649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1389649d4cceSanish 
1390649d4cceSanish 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1391649d4cceSanish 	    cfp->c_funcnum, reg, value);
1392649d4cceSanish }
1393649d4cceSanish 
1394649d4cceSanish void
1395649d4cceSanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1396649d4cceSanish 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1397649d4cceSanish {
1398649d4cceSanish 	uint8_t *h, *d;
1399649d4cceSanish 
1400649d4cceSanish 	h = host_addr;
1401649d4cceSanish 	d = dev_addr;
1402649d4cceSanish 
1403649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1404649d4cceSanish 		for (; repcount; repcount--)
1405649d4cceSanish 			pci_config_wr8(hdlp, d++, *h++);
1406649d4cceSanish 	else
1407649d4cceSanish 		for (; repcount; repcount--)
1408649d4cceSanish 			pci_config_wr8(hdlp, d, *h++);
1409649d4cceSanish }
1410649d4cceSanish 
1411649d4cceSanish void
1412649d4cceSanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1413649d4cceSanish {
1414649d4cceSanish 	pci_acc_cfblk_t *cfp;
1415649d4cceSanish 	int reg;
1416649d4cceSanish 
1417649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1418649d4cceSanish 
1419649d4cceSanish 	reg = (int)(uintptr_t)addr;
1420649d4cceSanish 
1421649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1422649d4cceSanish 
1423649d4cceSanish 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1424649d4cceSanish 	    cfp->c_funcnum, reg, value);
1425649d4cceSanish }
1426649d4cceSanish 
1427649d4cceSanish void
1428649d4cceSanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1429649d4cceSanish 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1430649d4cceSanish {
1431649d4cceSanish 	uint16_t *h, *d;
1432649d4cceSanish 
1433649d4cceSanish 	h = host_addr;
1434649d4cceSanish 	d = dev_addr;
1435649d4cceSanish 
1436649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1437649d4cceSanish 		for (; repcount; repcount--)
1438649d4cceSanish 			pci_config_wr16(hdlp, d++, *h++);
1439649d4cceSanish 	else
1440649d4cceSanish 		for (; repcount; repcount--)
1441649d4cceSanish 			pci_config_wr16(hdlp, d, *h++);
1442649d4cceSanish }
1443649d4cceSanish 
1444649d4cceSanish void
1445649d4cceSanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1446649d4cceSanish {
1447649d4cceSanish 	pci_acc_cfblk_t *cfp;
1448649d4cceSanish 	int reg;
1449649d4cceSanish 
1450649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1451649d4cceSanish 
1452649d4cceSanish 	reg = (int)(uintptr_t)addr;
1453649d4cceSanish 
1454649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1455649d4cceSanish 
1456649d4cceSanish 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1457649d4cceSanish 	    cfp->c_funcnum, reg, value);
1458649d4cceSanish }
1459649d4cceSanish 
1460649d4cceSanish void
1461649d4cceSanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1462649d4cceSanish 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1463649d4cceSanish {
1464649d4cceSanish 	uint32_t *h, *d;
1465649d4cceSanish 
1466649d4cceSanish 	h = host_addr;
1467649d4cceSanish 	d = dev_addr;
1468649d4cceSanish 
1469649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1470649d4cceSanish 		for (; repcount; repcount--)
1471649d4cceSanish 			pci_config_wr32(hdlp, d++, *h++);
1472649d4cceSanish 	else
1473649d4cceSanish 		for (; repcount; repcount--)
1474649d4cceSanish 			pci_config_wr32(hdlp, d, *h++);
1475649d4cceSanish }
1476649d4cceSanish 
1477649d4cceSanish uint64_t
1478649d4cceSanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1479649d4cceSanish {
1480649d4cceSanish 	uint32_t lw_val;
1481649d4cceSanish 	uint32_t hi_val;
1482649d4cceSanish 	uint32_t *dp;
1483649d4cceSanish 	uint64_t val;
1484649d4cceSanish 
1485649d4cceSanish 	dp = (uint32_t *)addr;
1486649d4cceSanish 	lw_val = pci_config_rd32(hdlp, dp);
1487649d4cceSanish 	dp++;
1488649d4cceSanish 	hi_val = pci_config_rd32(hdlp, dp);
1489649d4cceSanish 	val = ((uint64_t)hi_val << 32) | lw_val;
1490649d4cceSanish 	return (val);
1491649d4cceSanish }
1492649d4cceSanish 
1493649d4cceSanish void
1494649d4cceSanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1495649d4cceSanish {
1496649d4cceSanish 	uint32_t lw_val;
1497649d4cceSanish 	uint32_t hi_val;
1498649d4cceSanish 	uint32_t *dp;
1499649d4cceSanish 
1500649d4cceSanish 	dp = (uint32_t *)addr;
1501649d4cceSanish 	lw_val = (uint32_t)(value & 0xffffffff);
1502649d4cceSanish 	hi_val = (uint32_t)(value >> 32);
1503649d4cceSanish 	pci_config_wr32(hdlp, dp, lw_val);
1504649d4cceSanish 	dp++;
1505649d4cceSanish 	pci_config_wr32(hdlp, dp, hi_val);
1506649d4cceSanish }
1507649d4cceSanish 
1508649d4cceSanish void
1509649d4cceSanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1510649d4cceSanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1511649d4cceSanish {
1512649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR) {
1513649d4cceSanish 		for (; repcount; repcount--)
1514649d4cceSanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1515649d4cceSanish 	} else {
1516649d4cceSanish 		for (; repcount; repcount--)
1517649d4cceSanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
1518649d4cceSanish 	}
1519649d4cceSanish }
1520649d4cceSanish 
1521649d4cceSanish void
1522649d4cceSanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1523649d4cceSanish 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1524649d4cceSanish {
1525649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR) {
1526649d4cceSanish 		for (; repcount; repcount--)
1527649d4cceSanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1528649d4cceSanish 	} else {
1529649d4cceSanish 		for (; repcount; repcount--)
1530649d4cceSanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
1531649d4cceSanish 	}
1532649d4cceSanish }
1533649d4cceSanish 
1534649d4cceSanish 
1535649d4cceSanish /*
1536649d4cceSanish  * Enable Legacy PCI config space access for the following four north bridges
1537649d4cceSanish  *	Host bridge: AMD HyperTransport Technology Configuration
1538649d4cceSanish  *	Host bridge: AMD Address Map
1539649d4cceSanish  *	Host bridge: AMD DRAM Controller
1540649d4cceSanish  *	Host bridge: AMD Miscellaneous Control
1541649d4cceSanish  */
1542649d4cceSanish int
1543649d4cceSanish is_amd_northbridge(dev_info_t *dip)
1544649d4cceSanish {
1545649d4cceSanish 	int vendor_id, device_id;
1546649d4cceSanish 
1547649d4cceSanish 	vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1548649d4cceSanish 			"vendor-id", -1);
1549649d4cceSanish 	device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1550649d4cceSanish 			"device-id", -1);
1551649d4cceSanish 
1552649d4cceSanish 	if (IS_AMD_NTBRIDGE(vendor_id, device_id))
1553649d4cceSanish 		return (0);
1554649d4cceSanish 
1555649d4cceSanish 	return (1);
1556649d4cceSanish }
1557