xref: /illumos-gate/usr/src/uts/i86pc/io/pci/pci_common.c (revision a2d42228)
170025d76Sjohnny /*
270025d76Sjohnny  * CDDL HEADER START
370025d76Sjohnny  *
470025d76Sjohnny  * The contents of this file are subject to the terms of the
5102cb92eSjohnny  * Common Development and Distribution License (the "License").
6102cb92eSjohnny  * You may not use this file except in compliance with the License.
770025d76Sjohnny  *
870025d76Sjohnny  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
970025d76Sjohnny  * or http://www.opensolaris.org/os/licensing.
1070025d76Sjohnny  * See the License for the specific language governing permissions
1170025d76Sjohnny  * and limitations under the License.
1270025d76Sjohnny  *
1370025d76Sjohnny  * When distributing Covered Code, include this CDDL HEADER in each
1470025d76Sjohnny  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1570025d76Sjohnny  * If applicable, add the following below this CDDL HEADER, with the
1670025d76Sjohnny  * fields enclosed by brackets "[]" replaced with your own identifying
1770025d76Sjohnny  * information: Portions Copyright [yyyy] [name of copyright owner]
1870025d76Sjohnny  *
1970025d76Sjohnny  * CDDL HEADER END
2070025d76Sjohnny  */
2170025d76Sjohnny 
2270025d76Sjohnny /*
235cd376e8SJimmy Vetayases  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24*a2d42228SRobert Mustacchi  * Copyright 2022 Oxide Computer Company
2570025d76Sjohnny  */
2670025d76Sjohnny 
2770025d76Sjohnny /*
28bbf21555SRichard Lowe  *	File that has code which is common between pci(4D) and npe(4D)
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/pci_intr_lib.h>
4170025d76Sjohnny #include <sys/psm.h>
4270025d76Sjohnny #include <sys/policy.h>
4370025d76Sjohnny #include <sys/sysmacros.h>
447a364d25Sschwartz #include <sys/clock.h>
45ae115bc7Smrj #include <sys/apic.h>
4670025d76Sjohnny #include <sys/pci_tools.h>
4770025d76Sjohnny #include <io/pci/pci_var.h>
4870025d76Sjohnny #include <io/pci/pci_tools_ext.h>
4970025d76Sjohnny #include <io/pci/pci_common.h>
50649d4cceSanish #include <sys/pci_cfgspace.h>
51649d4cceSanish #include <sys/pci_impl.h>
52600d7745Sjveta #include <sys/pci_cap.h>
5370025d76Sjohnny 
5470025d76Sjohnny /*
5570025d76Sjohnny  * Function prototypes
5670025d76Sjohnny  */
5770025d76Sjohnny static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
5870025d76Sjohnny static int	pci_enable_intr(dev_info_t *, dev_info_t *,
5970025d76Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
6070025d76Sjohnny static void	pci_disable_intr(dev_info_t *, dev_info_t *,
6170025d76Sjohnny 		    ddi_intr_handle_impl_t *, uint32_t);
627ff178cdSJimmy Vetayases static int	pci_alloc_intr_fixed(dev_info_t *, dev_info_t *,
637ff178cdSJimmy Vetayases 		    ddi_intr_handle_impl_t *, void *);
647ff178cdSJimmy Vetayases static int	pci_free_intr_fixed(dev_info_t *, dev_info_t *,
657ff178cdSJimmy Vetayases 		    ddi_intr_handle_impl_t *);
6670025d76Sjohnny 
677ff178cdSJimmy Vetayases /* Extern declarations for PSM module */
6870025d76Sjohnny extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
6970025d76Sjohnny 		    psm_intr_op_t, int *);
707ff178cdSJimmy Vetayases extern ddi_irm_pool_t *apix_irm_pool_p;
7170025d76Sjohnny 
7270025d76Sjohnny /*
7370025d76Sjohnny  * pci_name_child:
7470025d76Sjohnny  *
7570025d76Sjohnny  *	Assign the address portion of the node name
7670025d76Sjohnny  */
7770025d76Sjohnny int
pci_common_name_child(dev_info_t * child,char * name,int namelen)7870025d76Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen)
7970025d76Sjohnny {
8070025d76Sjohnny 	int		dev, func, length;
8170025d76Sjohnny 	char		**unit_addr;
8270025d76Sjohnny 	uint_t		n;
8370025d76Sjohnny 	pci_regspec_t	*pci_rp;
8470025d76Sjohnny 
8570025d76Sjohnny 	if (ndi_dev_is_persistent_node(child) == 0) {
8670025d76Sjohnny 		/*
8770025d76Sjohnny 		 * For .conf node, use "unit-address" property
8870025d76Sjohnny 		 */
8970025d76Sjohnny 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
9070025d76Sjohnny 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
9170025d76Sjohnny 		    DDI_PROP_SUCCESS) {
9270025d76Sjohnny 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
9370025d76Sjohnny 			    ddi_get_name(child));
9470025d76Sjohnny 			return (DDI_FAILURE);
9570025d76Sjohnny 		}
9670025d76Sjohnny 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
9770025d76Sjohnny 			cmn_err(CE_WARN, "unit-address property in %s.conf"
9870025d76Sjohnny 			    " not well-formed", ddi_get_name(child));
9970025d76Sjohnny 			ddi_prop_free(unit_addr);
10070025d76Sjohnny 			return (DDI_FAILURE);
10170025d76Sjohnny 		}
10270025d76Sjohnny 		(void) snprintf(name, namelen, "%s", *unit_addr);
10370025d76Sjohnny 		ddi_prop_free(unit_addr);
10470025d76Sjohnny 		return (DDI_SUCCESS);
10570025d76Sjohnny 	}
10670025d76Sjohnny 
10770025d76Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
10870025d76Sjohnny 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
10970025d76Sjohnny 		cmn_err(CE_WARN, "cannot find reg property in %s",
11070025d76Sjohnny 		    ddi_get_name(child));
11170025d76Sjohnny 		return (DDI_FAILURE);
11270025d76Sjohnny 	}
11370025d76Sjohnny 
11470025d76Sjohnny 	/* copy the device identifications */
11570025d76Sjohnny 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
11670025d76Sjohnny 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
11770025d76Sjohnny 
11870025d76Sjohnny 	/*
11970025d76Sjohnny 	 * free the memory allocated by ddi_prop_lookup_int_array
12070025d76Sjohnny 	 */
12170025d76Sjohnny 	ddi_prop_free(pci_rp);
12270025d76Sjohnny 
12370025d76Sjohnny 	if (func != 0) {
12470025d76Sjohnny 		(void) snprintf(name, namelen, "%x,%x", dev, func);
12570025d76Sjohnny 	} else {
12670025d76Sjohnny 		(void) snprintf(name, namelen, "%x", dev);
12770025d76Sjohnny 	}
12870025d76Sjohnny 
12970025d76Sjohnny 	return (DDI_SUCCESS);
13070025d76Sjohnny }
13170025d76Sjohnny 
13270025d76Sjohnny /*
13370025d76Sjohnny  * Interrupt related code:
13470025d76Sjohnny  *
13570025d76Sjohnny  * The following busop is common to npe and pci drivers
13670025d76Sjohnny  *	bus_introp
13770025d76Sjohnny  */
13870025d76Sjohnny 
13970025d76Sjohnny /*
14070025d76Sjohnny  * Create the ddi_parent_private_data for a pseudo child.
14170025d76Sjohnny  */
14270025d76Sjohnny void
pci_common_set_parent_private_data(dev_info_t * dip)14370025d76Sjohnny pci_common_set_parent_private_data(dev_info_t *dip)
14470025d76Sjohnny {
14570025d76Sjohnny 	struct ddi_parent_private_data *pdptr;
14670025d76Sjohnny 
14770025d76Sjohnny 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
14870025d76Sjohnny 	    (sizeof (struct ddi_parent_private_data) +
1492917a9c9Sschwartz 	    sizeof (struct intrspec)), KM_SLEEP);
15070025d76Sjohnny 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
15170025d76Sjohnny 	pdptr->par_nintr = 1;
15270025d76Sjohnny 	ddi_set_parent_data(dip, pdptr);
15370025d76Sjohnny }
15470025d76Sjohnny 
15570025d76Sjohnny /*
15670025d76Sjohnny  * pci_get_priority:
15770025d76Sjohnny  *	Figure out the priority of the device
15870025d76Sjohnny  */
15970025d76Sjohnny static int
pci_get_priority(dev_info_t * dip,ddi_intr_handle_impl_t * hdlp,int * pri)16070025d76Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
16170025d76Sjohnny {
16270025d76Sjohnny 	struct intrspec *ispec;
16370025d76Sjohnny 
16470025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
16570025d76Sjohnny 	    (void *)dip, (void *)hdlp));
16670025d76Sjohnny 
16770025d76Sjohnny 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
16870025d76Sjohnny 	    hdlp->ih_inum)) == NULL) {
16970025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
170614edcaeSEvan Yan 			*pri = pci_class_to_pil(dip);
17170025d76Sjohnny 			pci_common_set_parent_private_data(hdlp->ih_dip);
17270025d76Sjohnny 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
17370025d76Sjohnny 			    hdlp->ih_inum);
17470025d76Sjohnny 			return (DDI_SUCCESS);
17570025d76Sjohnny 		}
17670025d76Sjohnny 		return (DDI_FAILURE);
17770025d76Sjohnny 	}
17870025d76Sjohnny 
17970025d76Sjohnny 	*pri = ispec->intrspec_pri;
18070025d76Sjohnny 	return (DDI_SUCCESS);
18170025d76Sjohnny }
18270025d76Sjohnny 
18370025d76Sjohnny 
18470025d76Sjohnny 
185d4bc0535SKrishna Elango static int pcieb_intr_pri_counter = 0;
18670025d76Sjohnny 
18770025d76Sjohnny /*
18870025d76Sjohnny  * pci_common_intr_ops: bus_intr_op() function for interrupt support
18970025d76Sjohnny  */
19070025d76Sjohnny int
pci_common_intr_ops(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)19170025d76Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
19270025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, void *result)
19370025d76Sjohnny {
19470025d76Sjohnny 	int			priority = 0;
19570025d76Sjohnny 	int			psm_status = 0;
19670025d76Sjohnny 	int			pci_status = 0;
19770025d76Sjohnny 	int			pci_rval, psm_rval = PSM_FAILURE;
19870025d76Sjohnny 	int			types = 0;
19970025d76Sjohnny 	int			pciepci = 0;
200102cb92eSjohnny 	int			i, j, count;
201600d7745Sjveta 	int			rv;
20270025d76Sjohnny 	int			behavior;
203d12abe7cSanish 	int			cap_ptr;
204600d7745Sjveta 	uint16_t		msi_cap_base, msix_cap_base, cap_ctrl;
205600d7745Sjveta 	char			*prop;
20670025d76Sjohnny 	ddi_intrspec_t		isp;
20770025d76Sjohnny 	struct intrspec		*ispec;
20870025d76Sjohnny 	ddi_intr_handle_impl_t	tmp_hdl;
20970025d76Sjohnny 	ddi_intr_msix_t		*msix_p;
210e1d9f4e6Sschwartz 	ihdl_plat_t		*ihdl_plat_datap;
211102cb92eSjohnny 	ddi_intr_handle_t	*h_array;
212d12abe7cSanish 	ddi_acc_handle_t	handle;
2137ff178cdSJimmy Vetayases 	apic_get_intr_t		intrinfo;
21470025d76Sjohnny 
21570025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT,
21670025d76Sjohnny 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
21770025d76Sjohnny 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
21870025d76Sjohnny 
21970025d76Sjohnny 	/* Process the request */
22070025d76Sjohnny 	switch (intr_op) {
22170025d76Sjohnny 	case DDI_INTROP_SUPPORTED_TYPES:
222600d7745Sjveta 		/*
223600d7745Sjveta 		 * First we determine the interrupt types supported by the
224600d7745Sjveta 		 * device itself, then we filter them through what the OS
225600d7745Sjveta 		 * and system supports.  We determine system-level
226600d7745Sjveta 		 * interrupt type support for anything other than fixed intrs
227600d7745Sjveta 		 * through the psm_intr_ops vector
228600d7745Sjveta 		 */
229600d7745Sjveta 		rv = DDI_FAILURE;
230600d7745Sjveta 
23170025d76Sjohnny 		/* Fixed supported by default */
232600d7745Sjveta 		types = DDI_INTR_TYPE_FIXED;
23370025d76Sjohnny 
234600d7745Sjveta 		if (psm_intr_ops == NULL) {
235600d7745Sjveta 			*(int *)result = types;
23670025d76Sjohnny 			return (DDI_SUCCESS);
237600d7745Sjveta 		}
238600d7745Sjveta 		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
239600d7745Sjveta 			return (DDI_FAILURE);
24070025d76Sjohnny 
241600d7745Sjveta 		/* Sanity test cap control values if found */
242600d7745Sjveta 
243600d7745Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
244600d7745Sjveta 		    DDI_SUCCESS) {
245600d7745Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
246600d7745Sjveta 			    PCI_MSI_CTRL);
247600d7745Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
248600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
249600d7745Sjveta 
250600d7745Sjveta 			types |= DDI_INTR_TYPE_MSI;
25170025d76Sjohnny 		}
252600d7745Sjveta 
253600d7745Sjveta 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
254600d7745Sjveta 		    DDI_SUCCESS) {
255600d7745Sjveta 			cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
256600d7745Sjveta 			    PCI_MSIX_CTRL);
257600d7745Sjveta 			if (cap_ctrl == PCI_CAP_EINVAL16)
258600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
259600d7745Sjveta 
260600d7745Sjveta 			types |= DDI_INTR_TYPE_MSIX;
261600d7745Sjveta 		}
262600d7745Sjveta 
263600d7745Sjveta 		/*
264600d7745Sjveta 		 * Filter device-level types through system-level support
265600d7745Sjveta 		 */
266600d7745Sjveta 		tmp_hdl.ih_type = types;
267600d7745Sjveta 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
268600d7745Sjveta 		    &types) != PSM_SUCCESS)
269600d7745Sjveta 			goto SUPPORTED_TYPES_OUT;
270600d7745Sjveta 
271600d7745Sjveta 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
272600d7745Sjveta 		    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
2737ff178cdSJimmy Vetayases 		    types));
274600d7745Sjveta 
275600d7745Sjveta 		/*
276600d7745Sjveta 		 * Export any MSI/MSI-X cap locations via properties
277600d7745Sjveta 		 */
278600d7745Sjveta 		if (types & DDI_INTR_TYPE_MSI) {
279600d7745Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
280600d7745Sjveta 			    "pci-msi-capid-pointer", (int)msi_cap_base) !=
281600d7745Sjveta 			    DDI_PROP_SUCCESS)
282600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
283600d7745Sjveta 		}
284600d7745Sjveta 		if (types & DDI_INTR_TYPE_MSIX) {
285600d7745Sjveta 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
286600d7745Sjveta 			    "pci-msix-capid-pointer", (int)msix_cap_base) !=
287600d7745Sjveta 			    DDI_PROP_SUCCESS)
288600d7745Sjveta 				goto SUPPORTED_TYPES_OUT;
289600d7745Sjveta 		}
290600d7745Sjveta 
291600d7745Sjveta 		rv = DDI_SUCCESS;
292600d7745Sjveta 
293600d7745Sjveta SUPPORTED_TYPES_OUT:
294600d7745Sjveta 		*(int *)result = types;
295600d7745Sjveta 		pci_config_teardown(&handle);
296600d7745Sjveta 		return (rv);
297600d7745Sjveta 
298a54f81fbSanish 	case DDI_INTROP_NAVAIL:
29970025d76Sjohnny 	case DDI_INTROP_NINTRS:
300a54f81fbSanish 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
301a54f81fbSanish 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
302a54f81fbSanish 			    result) != DDI_SUCCESS)
303a54f81fbSanish 				return (DDI_FAILURE);
304a54f81fbSanish 		} else {
305a54f81fbSanish 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
306a54f81fbSanish 			if (*(int *)result == 0)
307a54f81fbSanish 				return (DDI_FAILURE);
308a54f81fbSanish 		}
30970025d76Sjohnny 		break;
31070025d76Sjohnny 	case DDI_INTROP_ALLOC:
3117ff178cdSJimmy Vetayases 
3127ff178cdSJimmy Vetayases 		/*
3137ff178cdSJimmy Vetayases 		 * FIXED type
3147ff178cdSJimmy Vetayases 		 */
3157ff178cdSJimmy Vetayases 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
3167ff178cdSJimmy Vetayases 			return (pci_alloc_intr_fixed(pdip, rdip, hdlp, result));
31770025d76Sjohnny 		/*
31870025d76Sjohnny 		 * MSI or MSIX (figure out number of vectors available)
31970025d76Sjohnny 		 */
32070025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
32170025d76Sjohnny 		    (psm_intr_ops != NULL) &&
32270025d76Sjohnny 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
32370025d76Sjohnny 			/*
324d4bc0535SKrishna Elango 			 * Following check is a special case for 'pcieb'.
32570025d76Sjohnny 			 * This makes sure vectors with the right priority
326d4bc0535SKrishna Elango 			 * are allocated for pcieb during ALLOC time.
32770025d76Sjohnny 			 */
328d4bc0535SKrishna Elango 			if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) {
32970025d76Sjohnny 				hdlp->ih_pri =
330d4bc0535SKrishna Elango 				    (pcieb_intr_pri_counter % 2) ? 4 : 7;
33170025d76Sjohnny 				pciepci = 1;
33270025d76Sjohnny 			} else
33370025d76Sjohnny 				hdlp->ih_pri = priority;
33480ab886dSwesolows 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
335d12abe7cSanish 
336d12abe7cSanish 			/*
337d12abe7cSanish 			 * Cache in the config handle and cap_ptr
338d12abe7cSanish 			 */
339d12abe7cSanish 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
340d12abe7cSanish 				if (pci_config_setup(rdip, &handle) !=
341d12abe7cSanish 				    DDI_SUCCESS)
342d12abe7cSanish 					return (DDI_FAILURE);
343d12abe7cSanish 				i_ddi_set_pci_config_handle(rdip, handle);
344d12abe7cSanish 			}
345d12abe7cSanish 
346600d7745Sjveta 			prop = NULL;
347600d7745Sjveta 			cap_ptr = 0;
348600d7745Sjveta 			if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
349600d7745Sjveta 				prop = "pci-msi-capid-pointer";
350600d7745Sjveta 			else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
351600d7745Sjveta 				prop = "pci-msix-capid-pointer";
352d12abe7cSanish 
353600d7745Sjveta 			/*
354600d7745Sjveta 			 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
355600d7745Sjveta 			 * for MSI(X) before allocation
356600d7745Sjveta 			 */
357600d7745Sjveta 			if (prop != NULL) {
358d12abe7cSanish 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
359600d7745Sjveta 				    DDI_PROP_DONTPASS, prop, 0);
360600d7745Sjveta 				if (cap_ptr == 0) {
361600d7745Sjveta 					DDI_INTR_NEXDBG((CE_CONT,
362600d7745Sjveta 					    "pci_common_intr_ops: rdip: 0x%p "
363600d7745Sjveta 					    "attempted MSI(X) alloc without "
364600d7745Sjveta 					    "cap property\n", (void *)rdip));
365600d7745Sjveta 					return (DDI_FAILURE);
366600d7745Sjveta 				}
367d12abe7cSanish 			}
368600d7745Sjveta 			i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
369d12abe7cSanish 
370600d7745Sjveta 			/*
371600d7745Sjveta 			 * Allocate interrupt vectors
372600d7745Sjveta 			 */
37370025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
37470025d76Sjohnny 			    PSM_INTR_OP_ALLOC_VECTORS, result);
37570025d76Sjohnny 
3761ac1709fSanish 			if (*(int *)result == 0)
3771ac1709fSanish 				return (DDI_INTR_NOTFOUND);
3781ac1709fSanish 
37970025d76Sjohnny 			/* verify behavior flag and take appropriate action */
38070025d76Sjohnny 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
38170025d76Sjohnny 			    (*(int *)result < hdlp->ih_scratch1)) {
38270025d76Sjohnny 				DDI_INTR_NEXDBG((CE_CONT,
38370025d76Sjohnny 				    "pci_common_intr_ops: behavior %x, "
38470025d76Sjohnny 				    "couldn't get enough intrs\n", behavior));
38570025d76Sjohnny 				hdlp->ih_scratch1 = *(int *)result;
38670025d76Sjohnny 				(void) (*psm_intr_ops)(rdip, hdlp,
38770025d76Sjohnny 				    PSM_INTR_OP_FREE_VECTORS, NULL);
38870025d76Sjohnny 				return (DDI_EAGAIN);
38970025d76Sjohnny 			}
39070025d76Sjohnny 
39170025d76Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
39270025d76Sjohnny 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
39370025d76Sjohnny 					msix_p = pci_msix_init(hdlp->ih_dip);
394fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 					if (msix_p) {
39570025d76Sjohnny 						i_ddi_set_msix(hdlp->ih_dip,
39670025d76Sjohnny 						    msix_p);
397fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 					} else {
398fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						DDI_INTR_NEXDBG((CE_CONT,
399fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    "pci_common_intr_ops: MSI-X"
400fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    "table initilization failed"
401fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    ", rdip 0x%p inum 0x%x\n",
402fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    (void *)rdip,
403fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    hdlp->ih_inum));
404fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 
405fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						(void) (*psm_intr_ops)(rdip,
406fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    hdlp,
407fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    PSM_INTR_OP_FREE_VECTORS,
408fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						    NULL);
409fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 
410fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 						return (DDI_FAILURE);
411fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 					}
41270025d76Sjohnny 				}
41370025d76Sjohnny 			}
41470025d76Sjohnny 
41570025d76Sjohnny 			if (pciepci) {
41670025d76Sjohnny 				/* update priority in ispec */
41770025d76Sjohnny 				isp = pci_intx_get_ispec(pdip, rdip,
4182917a9c9Sschwartz 				    (int)hdlp->ih_inum);
41970025d76Sjohnny 				ispec = (struct intrspec *)isp;
42070025d76Sjohnny 				if (ispec)
42170025d76Sjohnny 					ispec->intrspec_pri = hdlp->ih_pri;
422d4bc0535SKrishna Elango 				++pcieb_intr_pri_counter;
42370025d76Sjohnny 			}
42470025d76Sjohnny 
42570025d76Sjohnny 		} else
42670025d76Sjohnny 			return (DDI_FAILURE);
42770025d76Sjohnny 		break;
42870025d76Sjohnny 	case DDI_INTROP_FREE:
42970025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
43070025d76Sjohnny 		    (psm_intr_ops != NULL)) {
43168565200Sanish 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
43268565200Sanish 			    0) {
433d12abe7cSanish 				if (handle = i_ddi_get_pci_config_handle(
434d12abe7cSanish 				    rdip)) {
435d12abe7cSanish 					(void) pci_config_teardown(&handle);
436d12abe7cSanish 					i_ddi_set_pci_config_handle(rdip, NULL);
437d12abe7cSanish 				}
438d12abe7cSanish 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
439d12abe7cSanish 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
440d12abe7cSanish 			}
441d12abe7cSanish 
44270025d76Sjohnny 			(void) (*psm_intr_ops)(rdip, hdlp,
44370025d76Sjohnny 			    PSM_INTR_OP_FREE_VECTORS, NULL);
44470025d76Sjohnny 
44570025d76Sjohnny 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
44670025d76Sjohnny 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
44770025d76Sjohnny 				if (msix_p &&
44868565200Sanish 				    (i_ddi_intr_get_current_nintrs(
4492917a9c9Sschwartz 				    hdlp->ih_dip) - 1) == 0) {
45070025d76Sjohnny 					pci_msix_fini(msix_p);
45170025d76Sjohnny 					i_ddi_set_msix(hdlp->ih_dip, NULL);
45270025d76Sjohnny 				}
45370025d76Sjohnny 			}
4547ff178cdSJimmy Vetayases 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
4557ff178cdSJimmy Vetayases 			return (pci_free_intr_fixed(pdip, rdip, hdlp));
4567ff178cdSJimmy Vetayases 		} else
4577ff178cdSJimmy Vetayases 			return (DDI_FAILURE);
45870025d76Sjohnny 		break;
45970025d76Sjohnny 	case DDI_INTROP_GETPRI:
46070025d76Sjohnny 		/* Get the priority */
46170025d76Sjohnny 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
46270025d76Sjohnny 			return (DDI_FAILURE);
46370025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
46470025d76Sjohnny 		    "priority = 0x%x\n", priority));
46570025d76Sjohnny 		*(int *)result = priority;
46670025d76Sjohnny 		break;
46770025d76Sjohnny 	case DDI_INTROP_SETPRI:
46870025d76Sjohnny 		/* Validate the interrupt priority passed */
46970025d76Sjohnny 		if (*(int *)result > LOCK_LEVEL)
47070025d76Sjohnny 			return (DDI_FAILURE);
47170025d76Sjohnny 
47270025d76Sjohnny 		/* Ensure that PSM is all initialized */
47370025d76Sjohnny 		if (psm_intr_ops == NULL)
47470025d76Sjohnny 			return (DDI_FAILURE);
47570025d76Sjohnny 
47696f82fefSSophia Li 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
47796f82fefSSophia Li 		ispec = (struct intrspec *)isp;
47896f82fefSSophia Li 		if (ispec == NULL)
47996f82fefSSophia Li 			return (DDI_FAILURE);
48096f82fefSSophia Li 
48196f82fefSSophia Li 		/* For fixed interrupts */
48296f82fefSSophia Li 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
48396f82fefSSophia Li 			/* if interrupt is shared, return failure */
48496f82fefSSophia Li 			((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
48596f82fefSSophia Li 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
48696f82fefSSophia Li 			    PSM_INTR_OP_GET_SHARED, &psm_status);
48796f82fefSSophia Li 			/*
48896f82fefSSophia Li 			 * For fixed interrupts, the irq may not have been
48996f82fefSSophia Li 			 * allocated when SET_PRI is called, and the above
49096f82fefSSophia Li 			 * GET_SHARED op may return PSM_FAILURE. This is not
49196f82fefSSophia Li 			 * a real error and is ignored below.
49296f82fefSSophia Li 			 */
49396f82fefSSophia Li 			if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) {
49496f82fefSSophia Li 				DDI_INTR_NEXDBG((CE_CONT,
49596f82fefSSophia Li 				    "pci_common_intr_ops: "
49696f82fefSSophia Li 				    "dip 0x%p cannot setpri, psm_rval=%d,"
49796f82fefSSophia Li 				    "psm_status=%d\n", (void *)rdip, psm_rval,
49896f82fefSSophia Li 				    psm_status));
49996f82fefSSophia Li 				return (DDI_FAILURE);
50096f82fefSSophia Li 			}
50196f82fefSSophia Li 		}
50296f82fefSSophia Li 
50370025d76Sjohnny 		/* Change the priority */
50470025d76Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
50570025d76Sjohnny 		    PSM_FAILURE)
50670025d76Sjohnny 			return (DDI_FAILURE);
50770025d76Sjohnny 
50870025d76Sjohnny 		/* update ispec */
50996f82fefSSophia Li 		ispec->intrspec_pri = *(int *)result;
51070025d76Sjohnny 		break;
51170025d76Sjohnny 	case DDI_INTROP_ADDISR:
51270025d76Sjohnny 		/* update ispec */
51370025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
51470025d76Sjohnny 		ispec = (struct intrspec *)isp;
515e1d9f4e6Sschwartz 		if (ispec) {
51670025d76Sjohnny 			ispec->intrspec_func = hdlp->ih_cb_func;
517e1d9f4e6Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
518e1d9f4e6Sschwartz 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
519e1d9f4e6Sschwartz 		}
52070025d76Sjohnny 		break;
52170025d76Sjohnny 	case DDI_INTROP_REMISR:
52270025d76Sjohnny 		/* Get the interrupt structure pointer */
52370025d76Sjohnny 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
52470025d76Sjohnny 		ispec = (struct intrspec *)isp;
525e1d9f4e6Sschwartz 		if (ispec) {
52670025d76Sjohnny 			ispec->intrspec_func = (uint_t (*)()) 0;
527e1d9f4e6Sschwartz 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
528e1d9f4e6Sschwartz 			if (ihdl_plat_datap->ip_ksp != NULL)
529e1d9f4e6Sschwartz 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
530e1d9f4e6Sschwartz 		}
53170025d76Sjohnny 		break;
53270025d76Sjohnny 	case DDI_INTROP_GETCAP:
53370025d76Sjohnny 		/*
53470025d76Sjohnny 		 * First check the config space and/or
53570025d76Sjohnny 		 * MSI capability register(s)
53670025d76Sjohnny 		 */
537584b574aSToomas Soome 		pci_rval = DDI_FAILURE;
53870025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
53970025d76Sjohnny 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
54070025d76Sjohnny 			    &pci_status);
54170025d76Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
54270025d76Sjohnny 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
54370025d76Sjohnny 
5447ff178cdSJimmy Vetayases 		/* next check with PSM module */
54570025d76Sjohnny 		if (psm_intr_ops != NULL)
54670025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
54770025d76Sjohnny 			    PSM_INTR_OP_GET_CAP, &psm_status);
54870025d76Sjohnny 
54970025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
55070025d76Sjohnny 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
55170025d76Sjohnny 		    psm_rval, psm_status, pci_rval, pci_status));
55270025d76Sjohnny 
55370025d76Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
55470025d76Sjohnny 			*(int *)result = 0;
55570025d76Sjohnny 			return (DDI_FAILURE);
55670025d76Sjohnny 		}
55770025d76Sjohnny 
55870025d76Sjohnny 		if (psm_rval == PSM_SUCCESS)
55970025d76Sjohnny 			*(int *)result = psm_status;
56070025d76Sjohnny 
56170025d76Sjohnny 		if (pci_rval == DDI_SUCCESS)
56270025d76Sjohnny 			*(int *)result |= pci_status;
56370025d76Sjohnny 
56470025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
56570025d76Sjohnny 		    *(int *)result));
56670025d76Sjohnny 		break;
56770025d76Sjohnny 	case DDI_INTROP_SETCAP:
56870025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
56970025d76Sjohnny 		    "SETCAP cap=0x%x\n", *(int *)result));
57070025d76Sjohnny 		if (psm_intr_ops == NULL)
57170025d76Sjohnny 			return (DDI_FAILURE);
57270025d76Sjohnny 
57370025d76Sjohnny 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
57470025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
57570025d76Sjohnny 			    " returned failure\n"));
57670025d76Sjohnny 			return (DDI_FAILURE);
57770025d76Sjohnny 		}
57870025d76Sjohnny 		break;
57970025d76Sjohnny 	case DDI_INTROP_ENABLE:
58070025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
58170025d76Sjohnny 		if (psm_intr_ops == NULL)
58270025d76Sjohnny 			return (DDI_FAILURE);
58370025d76Sjohnny 
58470025d76Sjohnny 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
58570025d76Sjohnny 		    DDI_SUCCESS)
58670025d76Sjohnny 			return (DDI_FAILURE);
58770025d76Sjohnny 
58870025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
58970025d76Sjohnny 		    "vector=0x%x\n", hdlp->ih_vector));
59070025d76Sjohnny 		break;
59170025d76Sjohnny 	case DDI_INTROP_DISABLE:
59270025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
59370025d76Sjohnny 		if (psm_intr_ops == NULL)
59470025d76Sjohnny 			return (DDI_FAILURE);
59570025d76Sjohnny 
59670025d76Sjohnny 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
59770025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
59870025d76Sjohnny 		    "vector = %x\n", hdlp->ih_vector));
59970025d76Sjohnny 		break;
60070025d76Sjohnny 	case DDI_INTROP_BLOCKENABLE:
60170025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
60270025d76Sjohnny 		    "BLOCKENABLE\n"));
60370025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
60470025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
60570025d76Sjohnny 			return (DDI_FAILURE);
60670025d76Sjohnny 		}
60770025d76Sjohnny 
60870025d76Sjohnny 		/* Check if psm_intr_ops is NULL? */
60970025d76Sjohnny 		if (psm_intr_ops == NULL)
61070025d76Sjohnny 			return (DDI_FAILURE);
61170025d76Sjohnny 
612102cb92eSjohnny 		count = hdlp->ih_scratch1;
613102cb92eSjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
614102cb92eSjohnny 		for (i = 0; i < count; i++) {
615102cb92eSjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
61670025d76Sjohnny 			if (pci_enable_intr(pdip, rdip, hdlp,
617102cb92eSjohnny 			    hdlp->ih_inum) != DDI_SUCCESS) {
61870025d76Sjohnny 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
61970025d76Sjohnny 				    "pci_enable_intr failed for %d\n", i));
620102cb92eSjohnny 				for (j = 0; j < i; j++) {
6212917a9c9Sschwartz 					hdlp = (ddi_intr_handle_impl_t *)
6222917a9c9Sschwartz 					    h_array[j];
6232917a9c9Sschwartz 					pci_disable_intr(pdip, rdip, hdlp,
624102cb92eSjohnny 					    hdlp->ih_inum);
625102cb92eSjohnny 				}
62670025d76Sjohnny 				return (DDI_FAILURE);
62770025d76Sjohnny 			}
62870025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
629102cb92eSjohnny 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
63070025d76Sjohnny 		}
63170025d76Sjohnny 		break;
63270025d76Sjohnny 	case DDI_INTROP_BLOCKDISABLE:
63370025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
63470025d76Sjohnny 		    "BLOCKDISABLE\n"));
63570025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
63670025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
63770025d76Sjohnny 			return (DDI_FAILURE);
63870025d76Sjohnny 		}
63970025d76Sjohnny 
64070025d76Sjohnny 		/* Check if psm_intr_ops is present */
64170025d76Sjohnny 		if (psm_intr_ops == NULL)
64270025d76Sjohnny 			return (DDI_FAILURE);
64370025d76Sjohnny 
644102cb92eSjohnny 		count = hdlp->ih_scratch1;
645102cb92eSjohnny 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
646102cb92eSjohnny 		for (i = 0; i < count; i++) {
647102cb92eSjohnny 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
648102cb92eSjohnny 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
64970025d76Sjohnny 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
650102cb92eSjohnny 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
65170025d76Sjohnny 		}
65270025d76Sjohnny 		break;
65370025d76Sjohnny 	case DDI_INTROP_SETMASK:
65470025d76Sjohnny 	case DDI_INTROP_CLRMASK:
65570025d76Sjohnny 		/*
65670025d76Sjohnny 		 * First handle in the config space
65770025d76Sjohnny 		 */
65870025d76Sjohnny 		if (intr_op == DDI_INTROP_SETMASK) {
65970025d76Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
66070025d76Sjohnny 				pci_status = pci_msi_set_mask(rdip,
66170025d76Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
66270025d76Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
66370025d76Sjohnny 				pci_status = pci_intx_set_mask(rdip);
66470025d76Sjohnny 		} else {
66570025d76Sjohnny 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
66670025d76Sjohnny 				pci_status = pci_msi_clr_mask(rdip,
66770025d76Sjohnny 				    hdlp->ih_type, hdlp->ih_inum);
66870025d76Sjohnny 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
66970025d76Sjohnny 				pci_status = pci_intx_clr_mask(rdip);
67070025d76Sjohnny 		}
67170025d76Sjohnny 
6727ff178cdSJimmy Vetayases 		/* For MSI/X; no need to check with PSM module */
67370025d76Sjohnny 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
67470025d76Sjohnny 			return (pci_status);
67570025d76Sjohnny 
67670025d76Sjohnny 		/* For fixed interrupts only: handle config space first */
67770025d76Sjohnny 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
67870025d76Sjohnny 		    pci_status == DDI_SUCCESS)
67970025d76Sjohnny 			break;
68070025d76Sjohnny 
6817ff178cdSJimmy Vetayases 		/* For fixed interrupts only: confer with PSM module next */
68270025d76Sjohnny 		if (psm_intr_ops != NULL) {
68370025d76Sjohnny 			/* If interrupt is shared; do nothing */
68470025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
68570025d76Sjohnny 			    PSM_INTR_OP_GET_SHARED, &psm_status);
68670025d76Sjohnny 
68770025d76Sjohnny 			if (psm_rval == PSM_FAILURE || psm_status == 1)
68870025d76Sjohnny 				return (pci_status);
68970025d76Sjohnny 
6907ff178cdSJimmy Vetayases 			/* Now, PSM module should try to set/clear the mask */
69170025d76Sjohnny 			if (intr_op == DDI_INTROP_SETMASK)
69270025d76Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
69370025d76Sjohnny 				    PSM_INTR_OP_SET_MASK, NULL);
69470025d76Sjohnny 			else
69570025d76Sjohnny 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
69670025d76Sjohnny 				    PSM_INTR_OP_CLEAR_MASK, NULL);
69770025d76Sjohnny 		}
69870025d76Sjohnny 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
69970025d76Sjohnny 	case DDI_INTROP_GETPENDING:
70070025d76Sjohnny 		/*
70170025d76Sjohnny 		 * First check the config space and/or
70270025d76Sjohnny 		 * MSI capability register(s)
70370025d76Sjohnny 		 */
704584b574aSToomas Soome 		pci_rval = DDI_FAILURE;
70570025d76Sjohnny 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
70670025d76Sjohnny 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
70770025d76Sjohnny 			    hdlp->ih_inum, &pci_status);
70870025d76Sjohnny 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
70970025d76Sjohnny 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
71070025d76Sjohnny 
7117ff178cdSJimmy Vetayases 		/* On failure; next try with PSM module */
71270025d76Sjohnny 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
71370025d76Sjohnny 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
71470025d76Sjohnny 			    PSM_INTR_OP_GET_PENDING, &psm_status);
71570025d76Sjohnny 
71670025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
71770025d76Sjohnny 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
71870025d76Sjohnny 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
71970025d76Sjohnny 		    pci_status));
72070025d76Sjohnny 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
72170025d76Sjohnny 			*(int *)result = 0;
72270025d76Sjohnny 			return (DDI_FAILURE);
72370025d76Sjohnny 		}
72470025d76Sjohnny 
72570025d76Sjohnny 		if (psm_rval != PSM_FAILURE)
72670025d76Sjohnny 			*(int *)result = psm_status;
72770025d76Sjohnny 		else if (pci_rval != DDI_FAILURE)
72870025d76Sjohnny 			*(int *)result = pci_status;
72970025d76Sjohnny 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
73070025d76Sjohnny 		    *(int *)result));
73170025d76Sjohnny 		break;
73209b1eac2SEvan Yan 	case DDI_INTROP_GETTARGET:
73309b1eac2SEvan Yan 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n"));
73409b1eac2SEvan Yan 
7357ff178cdSJimmy Vetayases 		bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
7367ff178cdSJimmy Vetayases 		tmp_hdl.ih_private = (void *)&intrinfo;
7377ff178cdSJimmy Vetayases 		intrinfo.avgi_req_flags = PSMGI_INTRBY_DEFAULT;
7387ff178cdSJimmy Vetayases 		intrinfo.avgi_req_flags |= PSMGI_REQ_CPUID;
7397ff178cdSJimmy Vetayases 
7407ff178cdSJimmy Vetayases 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_GET_INTR,
7417ff178cdSJimmy Vetayases 		    NULL) == PSM_FAILURE)
74209b1eac2SEvan Yan 			return (DDI_FAILURE);
7437ff178cdSJimmy Vetayases 
7447ff178cdSJimmy Vetayases 		*(int *)result = intrinfo.avgi_cpu_id;
74509b1eac2SEvan Yan 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET "
7467ff178cdSJimmy Vetayases 		    "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector,
7477ff178cdSJimmy Vetayases 		    *(int *)result));
74809b1eac2SEvan Yan 		break;
74909b1eac2SEvan Yan 	case DDI_INTROP_SETTARGET:
75009b1eac2SEvan Yan 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n"));
75109b1eac2SEvan Yan 
7527ff178cdSJimmy Vetayases 		bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t));
75309b1eac2SEvan Yan 		tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result;
7547ff178cdSJimmy Vetayases 		tmp_hdl.ih_flags = PSMGI_INTRBY_DEFAULT;
75509b1eac2SEvan Yan 
7567ff178cdSJimmy Vetayases 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU,
7577ff178cdSJimmy Vetayases 		    &psm_status) == PSM_FAILURE)
75809b1eac2SEvan Yan 			return (DDI_FAILURE);
7597ff178cdSJimmy Vetayases 
7607ff178cdSJimmy Vetayases 		hdlp->ih_vector = tmp_hdl.ih_vector;
7617ff178cdSJimmy Vetayases 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET "
7627ff178cdSJimmy Vetayases 		    "vector = 0x%x\n", hdlp->ih_vector));
76309b1eac2SEvan Yan 		break;
7647ff178cdSJimmy Vetayases 	case DDI_INTROP_GETPOOL:
7657ff178cdSJimmy Vetayases 		/*
7667ff178cdSJimmy Vetayases 		 * For MSI/X interrupts use global IRM pool if available.
7677ff178cdSJimmy Vetayases 		 */
7687ff178cdSJimmy Vetayases 		if (apix_irm_pool_p && DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
7697ff178cdSJimmy Vetayases 			*(ddi_irm_pool_t **)result = apix_irm_pool_p;
7707ff178cdSJimmy Vetayases 			return (DDI_SUCCESS);
7717ff178cdSJimmy Vetayases 		}
7727ff178cdSJimmy Vetayases 		return (DDI_ENOTSUP);
77370025d76Sjohnny 	default:
77470025d76Sjohnny 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
77570025d76Sjohnny 	}
77670025d76Sjohnny 
77770025d76Sjohnny 	return (DDI_SUCCESS);
77870025d76Sjohnny }
77970025d76Sjohnny 
7807ff178cdSJimmy Vetayases /*
7817ff178cdSJimmy Vetayases  * Allocate a vector for FIXED type interrupt.
7827ff178cdSJimmy Vetayases  */
7837ff178cdSJimmy Vetayases int
pci_alloc_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,void * result)7847ff178cdSJimmy Vetayases pci_alloc_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
7857ff178cdSJimmy Vetayases     ddi_intr_handle_impl_t *hdlp, void *result)
7867ff178cdSJimmy Vetayases {
7877ff178cdSJimmy Vetayases 	struct intrspec		*ispec;
7887ff178cdSJimmy Vetayases 	ddi_intr_handle_impl_t	info_hdl;
7897ff178cdSJimmy Vetayases 	int			ret;
7907ff178cdSJimmy Vetayases 	int			free_phdl = 0;
7917ff178cdSJimmy Vetayases 	int			pci_rval;
7927ff178cdSJimmy Vetayases 	int			pci_status = 0;
7937ff178cdSJimmy Vetayases 	apic_get_type_t		type_info;
7947ff178cdSJimmy Vetayases 
7957ff178cdSJimmy Vetayases 	if (psm_intr_ops == NULL)
7967ff178cdSJimmy Vetayases 		return (DDI_FAILURE);
7977ff178cdSJimmy Vetayases 
7987ff178cdSJimmy Vetayases 	/* Figure out if this device supports MASKING */
7997ff178cdSJimmy Vetayases 	pci_rval = pci_intx_get_cap(rdip, &pci_status);
8007ff178cdSJimmy Vetayases 	if (pci_rval == DDI_SUCCESS && pci_status)
8017ff178cdSJimmy Vetayases 		hdlp->ih_cap |= pci_status;
8027ff178cdSJimmy Vetayases 
8037ff178cdSJimmy Vetayases 	/*
8047ff178cdSJimmy Vetayases 	 * If the PSM module is "APIX" then pass the request for
8057ff178cdSJimmy Vetayases 	 * allocating the vector now.
8067ff178cdSJimmy Vetayases 	 */
8077ff178cdSJimmy Vetayases 	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
8087ff178cdSJimmy Vetayases 	info_hdl.ih_private = &type_info;
8097ff178cdSJimmy Vetayases 	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
8107ff178cdSJimmy Vetayases 	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
8117ff178cdSJimmy Vetayases 		ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
8127ff178cdSJimmy Vetayases 		    (int)hdlp->ih_inum);
8137ff178cdSJimmy Vetayases 		if (ispec == NULL)
8147ff178cdSJimmy Vetayases 			return (DDI_FAILURE);
8157ff178cdSJimmy Vetayases 		if (hdlp->ih_private == NULL) { /* allocate phdl structure */
8167ff178cdSJimmy Vetayases 			free_phdl = 1;
8177ff178cdSJimmy Vetayases 			i_ddi_alloc_intr_phdl(hdlp);
8187ff178cdSJimmy Vetayases 		}
8197ff178cdSJimmy Vetayases 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
8207ff178cdSJimmy Vetayases 		ret = (*psm_intr_ops)(rdip, hdlp,
8217ff178cdSJimmy Vetayases 		    PSM_INTR_OP_ALLOC_VECTORS, result);
8227ff178cdSJimmy Vetayases 		if (free_phdl) { /* free up the phdl structure */
8237ff178cdSJimmy Vetayases 			free_phdl = 0;
8247ff178cdSJimmy Vetayases 			i_ddi_free_intr_phdl(hdlp);
8257ff178cdSJimmy Vetayases 			hdlp->ih_private = NULL;
8267ff178cdSJimmy Vetayases 		}
8277ff178cdSJimmy Vetayases 	} else {
8287ff178cdSJimmy Vetayases 		/*
8297ff178cdSJimmy Vetayases 		 * No APIX module; fall back to the old scheme where the
8307ff178cdSJimmy Vetayases 		 * interrupt vector is allocated during ddi_enable_intr() call.
8317ff178cdSJimmy Vetayases 		 */
8327ff178cdSJimmy Vetayases 		*(int *)result = 1;
8337ff178cdSJimmy Vetayases 		ret = DDI_SUCCESS;
8347ff178cdSJimmy Vetayases 	}
8357ff178cdSJimmy Vetayases 
8367ff178cdSJimmy Vetayases 	return (ret);
8377ff178cdSJimmy Vetayases }
8387ff178cdSJimmy Vetayases 
8397ff178cdSJimmy Vetayases /*
8407ff178cdSJimmy Vetayases  * Free up the vector for FIXED (legacy) type interrupt.
8417ff178cdSJimmy Vetayases  */
8427ff178cdSJimmy Vetayases static int
pci_free_intr_fixed(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)8437ff178cdSJimmy Vetayases pci_free_intr_fixed(dev_info_t *pdip, dev_info_t *rdip,
8447ff178cdSJimmy Vetayases     ddi_intr_handle_impl_t *hdlp)
8457ff178cdSJimmy Vetayases {
8467ff178cdSJimmy Vetayases 	struct intrspec			*ispec;
8477ff178cdSJimmy Vetayases 	ddi_intr_handle_impl_t		info_hdl;
8487ff178cdSJimmy Vetayases 	int				ret;
8497ff178cdSJimmy Vetayases 	apic_get_type_t			type_info;
8507ff178cdSJimmy Vetayases 
8517ff178cdSJimmy Vetayases 	if (psm_intr_ops == NULL)
8527ff178cdSJimmy Vetayases 		return (DDI_FAILURE);
8537ff178cdSJimmy Vetayases 
8547ff178cdSJimmy Vetayases 	/*
8557ff178cdSJimmy Vetayases 	 * If the PSM module is "APIX" then pass the request to it
8567ff178cdSJimmy Vetayases 	 * to free up the vector now.
8577ff178cdSJimmy Vetayases 	 */
8587ff178cdSJimmy Vetayases 	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
8597ff178cdSJimmy Vetayases 	info_hdl.ih_private = &type_info;
8607ff178cdSJimmy Vetayases 	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
8617ff178cdSJimmy Vetayases 	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
8627ff178cdSJimmy Vetayases 		ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip,
8637ff178cdSJimmy Vetayases 		    (int)hdlp->ih_inum);
8647ff178cdSJimmy Vetayases 		if (ispec == NULL)
8657ff178cdSJimmy Vetayases 			return (DDI_FAILURE);
8667ff178cdSJimmy Vetayases 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
8677ff178cdSJimmy Vetayases 		ret = (*psm_intr_ops)(rdip, hdlp,
8687ff178cdSJimmy Vetayases 		    PSM_INTR_OP_FREE_VECTORS, NULL);
8697ff178cdSJimmy Vetayases 	} else {
8707ff178cdSJimmy Vetayases 		/*
8717ff178cdSJimmy Vetayases 		 * No APIX module; fall back to the old scheme where
8727ff178cdSJimmy Vetayases 		 * the interrupt vector was already freed during
8737ff178cdSJimmy Vetayases 		 * ddi_disable_intr() call.
8747ff178cdSJimmy Vetayases 		 */
8757ff178cdSJimmy Vetayases 		ret = DDI_SUCCESS;
8767ff178cdSJimmy Vetayases 	}
8777ff178cdSJimmy Vetayases 
8787ff178cdSJimmy Vetayases 	return (ret);
8797ff178cdSJimmy Vetayases }
8807ff178cdSJimmy Vetayases 
8817a364d25Sschwartz int
pci_get_intr_from_vecirq(apic_get_intr_t * intrinfo_p,int vecirq,boolean_t is_irq)8827a364d25Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
8837a364d25Sschwartz     int vecirq, boolean_t is_irq)
8847a364d25Sschwartz {
8857a364d25Sschwartz 	ddi_intr_handle_impl_t	get_info_ii_hdl;
8867a364d25Sschwartz 
8877a364d25Sschwartz 	if (is_irq)
8887a364d25Sschwartz 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
8897a364d25Sschwartz 
8907a364d25Sschwartz 	/*
8917a364d25Sschwartz 	 * For this locally-declared and used handle, ih_private will contain a
8927a364d25Sschwartz 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
8937a364d25Sschwartz 	 * global interrupt handling.
8947a364d25Sschwartz 	 */
8957a364d25Sschwartz 	get_info_ii_hdl.ih_private = intrinfo_p;
8967ff178cdSJimmy Vetayases 	get_info_ii_hdl.ih_vector = vecirq;
8977a364d25Sschwartz 
8987a364d25Sschwartz 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
8997a364d25Sschwartz 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
9007a364d25Sschwartz 		return (DDI_FAILURE);
9017a364d25Sschwartz 
9027a364d25Sschwartz 	return (DDI_SUCCESS);
9037a364d25Sschwartz }
9047a364d25Sschwartz 
9057a364d25Sschwartz 
9067a364d25Sschwartz int
pci_get_cpu_from_vecirq(int vecirq,boolean_t is_irq)9077a364d25Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
9087a364d25Sschwartz {
9097a364d25Sschwartz 	int rval;
9107a364d25Sschwartz 	apic_get_intr_t	intrinfo;
9117ff178cdSJimmy Vetayases 
9127a364d25Sschwartz 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
9137a364d25Sschwartz 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
9147a364d25Sschwartz 
9157a364d25Sschwartz 	if (rval == DDI_SUCCESS)
9167a364d25Sschwartz 		return (intrinfo.avgi_cpu_id);
9177a364d25Sschwartz 	else
9187a364d25Sschwartz 		return (-1);
9197a364d25Sschwartz }
9207a364d25Sschwartz 
92170025d76Sjohnny 
92270025d76Sjohnny static int
pci_enable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)92370025d76Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
92470025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
92570025d76Sjohnny {
92670025d76Sjohnny 	struct intrspec	*ispec;
9277a364d25Sschwartz 	int		irq;
9287a364d25Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
92970025d76Sjohnny 
93070025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
93170025d76Sjohnny 	    (void *)hdlp, inum));
93270025d76Sjohnny 
93370025d76Sjohnny 	/* Translate the interrupt if needed */
93470025d76Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9358d9a0e26Sanish 	if (ispec == NULL)
9368d9a0e26Sanish 		return (DDI_FAILURE);
93796f82fefSSophia Li 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
93870025d76Sjohnny 		ispec->intrspec_vec = inum;
93996f82fefSSophia Li 		ispec->intrspec_pri = hdlp->ih_pri;
94096f82fefSSophia Li 	}
9417a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
94270025d76Sjohnny 
94370025d76Sjohnny 	/* translate the interrupt if needed */
94486a9c507SGuoli Shu 	if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) ==
94586a9c507SGuoli Shu 	    PSM_FAILURE)
94686a9c507SGuoli Shu 		return (DDI_FAILURE);
9477a364d25Sschwartz 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
9487a364d25Sschwartz 	    hdlp->ih_pri, irq));
94970025d76Sjohnny 
95070025d76Sjohnny 	/* Add the interrupt handler */
95170025d76Sjohnny 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
9527a364d25Sschwartz 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
9537a364d25Sschwartz 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
95470025d76Sjohnny 		return (DDI_FAILURE);
95570025d76Sjohnny 
9567ff178cdSJimmy Vetayases 	hdlp->ih_vector = irq;
9577a364d25Sschwartz 
95870025d76Sjohnny 	return (DDI_SUCCESS);
95970025d76Sjohnny }
96070025d76Sjohnny 
96170025d76Sjohnny 
96270025d76Sjohnny static void
pci_disable_intr(dev_info_t * pdip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,uint32_t inum)96370025d76Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
96470025d76Sjohnny     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
96570025d76Sjohnny {
9667a364d25Sschwartz 	int		irq;
96770025d76Sjohnny 	struct intrspec	*ispec;
9687a364d25Sschwartz 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
96970025d76Sjohnny 
97070025d76Sjohnny 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
97170025d76Sjohnny 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
9728d9a0e26Sanish 	if (ispec == NULL)
9738d9a0e26Sanish 		return;
97496f82fefSSophia Li 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
97570025d76Sjohnny 		ispec->intrspec_vec = inum;
97696f82fefSSophia Li 		ispec->intrspec_pri = hdlp->ih_pri;
97796f82fefSSophia Li 	}
9787a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = ispec;
97970025d76Sjohnny 
98070025d76Sjohnny 	/* translate the interrupt if needed */
9817a364d25Sschwartz 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
98270025d76Sjohnny 
98370025d76Sjohnny 	/* Disable the interrupt handler */
9847a364d25Sschwartz 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
9857a364d25Sschwartz 	ihdl_plat_datap->ip_ispecp = NULL;
98670025d76Sjohnny }
98770025d76Sjohnny 
98870025d76Sjohnny /*
98970025d76Sjohnny  * Miscellaneous library function
99070025d76Sjohnny  */
99170025d76Sjohnny int
pci_common_get_reg_prop(dev_info_t * dip,pci_regspec_t * pci_rp)99270025d76Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
99370025d76Sjohnny {
99470025d76Sjohnny 	int		i;
995584b574aSToomas Soome 	int		number;
99670025d76Sjohnny 	int		assigned_addr_len;
99770025d76Sjohnny 	uint_t		phys_hi = pci_rp->pci_phys_hi;
99870025d76Sjohnny 	pci_regspec_t	*assigned_addr;
99970025d76Sjohnny 
100070025d76Sjohnny 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
100170025d76Sjohnny 	    (phys_hi & PCI_RELOCAT_B))
100270025d76Sjohnny 		return (DDI_SUCCESS);
100370025d76Sjohnny 
100470025d76Sjohnny 	/*
100570025d76Sjohnny 	 * the "reg" property specifies relocatable, get and interpret the
100670025d76Sjohnny 	 * "assigned-addresses" property.
100770025d76Sjohnny 	 */
100870025d76Sjohnny 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
100970025d76Sjohnny 	    "assigned-addresses", (int **)&assigned_addr,
101070025d76Sjohnny 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
101170025d76Sjohnny 		return (DDI_FAILURE);
101270025d76Sjohnny 
101370025d76Sjohnny 	/*
101470025d76Sjohnny 	 * Scan the "assigned-addresses" for one that matches the specified
101570025d76Sjohnny 	 * "reg" property entry.
101670025d76Sjohnny 	 */
101770025d76Sjohnny 	phys_hi &= PCI_CONF_ADDR_MASK;
101870025d76Sjohnny 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
101970025d76Sjohnny 	for (i = 0; i < number; i++) {
102070025d76Sjohnny 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
102170025d76Sjohnny 		    phys_hi) {
1022*a2d42228SRobert Mustacchi 			/*
1023*a2d42228SRobert Mustacchi 			 * When the system does not manage to allocate PCI
1024*a2d42228SRobert Mustacchi 			 * resources for a device, then the value that is stored
1025*a2d42228SRobert Mustacchi 			 * in assigned addresses ends up being the hardware
1026*a2d42228SRobert Mustacchi 			 * default reset value of '0'. On currently supported
1027*a2d42228SRobert Mustacchi 			 * platforms, physical address zero is associated with
1028*a2d42228SRobert Mustacchi 			 * memory; however, on other platforms this may be the
1029*a2d42228SRobert Mustacchi 			 * exception vector table (ARM), etc. and so we opt to
1030*a2d42228SRobert Mustacchi 			 * generally keep the idea in PCI that the reset value
1031*a2d42228SRobert Mustacchi 			 * will not be used for actual MMIO allocations. If such
1032*a2d42228SRobert Mustacchi 			 * a platform comes around where it is worth using that
1033*a2d42228SRobert Mustacchi 			 * bit of MMIO for PCI then we should make this check
1034*a2d42228SRobert Mustacchi 			 * platform-specific.
1035*a2d42228SRobert Mustacchi 			 *
1036*a2d42228SRobert Mustacchi 			 * Note, the +1 in the print statement is because a
1037*a2d42228SRobert Mustacchi 			 * given regs[0] describes B/D/F information for the
1038*a2d42228SRobert Mustacchi 			 * device.
1039*a2d42228SRobert Mustacchi 			 */
1040*a2d42228SRobert Mustacchi 			if (assigned_addr[i].pci_phys_mid == 0 &&
1041*a2d42228SRobert Mustacchi 			    assigned_addr[i].pci_phys_low == 0) {
1042*a2d42228SRobert Mustacchi 				dev_err(dip, CE_WARN, "regs[%u] does not have "
1043*a2d42228SRobert Mustacchi 				    "a valid MMIO address", i + 1);
1044*a2d42228SRobert Mustacchi 				goto err;
1045*a2d42228SRobert Mustacchi 			}
1046*a2d42228SRobert Mustacchi 
104770025d76Sjohnny 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
104870025d76Sjohnny 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
104970025d76Sjohnny 			ddi_prop_free(assigned_addr);
105070025d76Sjohnny 			return (DDI_SUCCESS);
105170025d76Sjohnny 		}
105270025d76Sjohnny 	}
105370025d76Sjohnny 
1054*a2d42228SRobert Mustacchi err:
105570025d76Sjohnny 	ddi_prop_free(assigned_addr);
105670025d76Sjohnny 	return (DDI_FAILURE);
105770025d76Sjohnny }
105870025d76Sjohnny 
105970025d76Sjohnny 
106070025d76Sjohnny /*
106126947304SEvan Yan  * To handle PCI tool ioctls
106270025d76Sjohnny  */
106370025d76Sjohnny 
106426947304SEvan Yan /*ARGSUSED*/
106570025d76Sjohnny int
pci_common_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)106670025d76Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
106770025d76Sjohnny     int mode, cred_t *credp, int *rvalp)
106870025d76Sjohnny {
106926947304SEvan Yan 	minor_t	minor = getminor(dev);
107026947304SEvan Yan 	int	rv = ENOTTY;
107170025d76Sjohnny 
107226947304SEvan Yan 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
107370025d76Sjohnny 	case PCI_TOOL_REG_MINOR_NUM:
107470025d76Sjohnny 
107570025d76Sjohnny 		switch (cmd) {
107670025d76Sjohnny 		case PCITOOL_DEVICE_SET_REG:
107770025d76Sjohnny 		case PCITOOL_DEVICE_GET_REG:
107870025d76Sjohnny 
107970025d76Sjohnny 			/* Require full privileges. */
108070025d76Sjohnny 			if (secpolicy_kmdb(credp))
108170025d76Sjohnny 				rv = EPERM;
108270025d76Sjohnny 			else
108370025d76Sjohnny 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
108470025d76Sjohnny 				    cmd, mode);
108570025d76Sjohnny 			break;
108670025d76Sjohnny 
108770025d76Sjohnny 		case PCITOOL_NEXUS_SET_REG:
108870025d76Sjohnny 		case PCITOOL_NEXUS_GET_REG:
108970025d76Sjohnny 
109070025d76Sjohnny 			/* Require full privileges. */
109170025d76Sjohnny 			if (secpolicy_kmdb(credp))
109270025d76Sjohnny 				rv = EPERM;
109370025d76Sjohnny 			else
109470025d76Sjohnny 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
109570025d76Sjohnny 				    cmd, mode);
109670025d76Sjohnny 			break;
109770025d76Sjohnny 		}
109870025d76Sjohnny 		break;
109970025d76Sjohnny 
110070025d76Sjohnny 	case PCI_TOOL_INTR_MINOR_NUM:
110170025d76Sjohnny 
110270025d76Sjohnny 		switch (cmd) {
110370025d76Sjohnny 		case PCITOOL_DEVICE_SET_INTR:
110470025d76Sjohnny 
110570025d76Sjohnny 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
110670025d76Sjohnny 			if (secpolicy_ponline(credp)) {
110770025d76Sjohnny 				rv = EPERM;
110870025d76Sjohnny 				break;
110970025d76Sjohnny 			}
111070025d76Sjohnny 
111170025d76Sjohnny 		/*FALLTHRU*/
111270025d76Sjohnny 		/* These require no special privileges. */
111370025d76Sjohnny 		case PCITOOL_DEVICE_GET_INTR:
11142917a9c9Sschwartz 		case PCITOOL_SYSTEM_INTR_INFO:
111570025d76Sjohnny 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
111670025d76Sjohnny 			break;
111770025d76Sjohnny 		}
111870025d76Sjohnny 		break;
111970025d76Sjohnny 
112070025d76Sjohnny 	default:
112170025d76Sjohnny 		break;
112270025d76Sjohnny 	}
112370025d76Sjohnny 
112470025d76Sjohnny 	return (rv);
112570025d76Sjohnny }
1126649d4cceSanish 
1127649d4cceSanish 
112800d0963fSdilpreet int
pci_common_ctlops_poke(peekpoke_ctlops_t * in_args)112900d0963fSdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
113000d0963fSdilpreet {
113100d0963fSdilpreet 	size_t size = in_args->size;
113200d0963fSdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
113300d0963fSdilpreet 	uintptr_t host_addr = in_args->host_addr;
113400d0963fSdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
113500d0963fSdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
113600d0963fSdilpreet 	size_t repcount = in_args->repcount;
113700d0963fSdilpreet 	uint_t flags = in_args->flags;
113800d0963fSdilpreet 	int err = DDI_SUCCESS;
113900d0963fSdilpreet 
114000d0963fSdilpreet 	/*
114100d0963fSdilpreet 	 * if no handle then this is a poke. We have to return failure here
114200d0963fSdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
114300d0963fSdilpreet 	 */
114400d0963fSdilpreet 	if (in_args->handle == NULL)
114500d0963fSdilpreet 		return (DDI_FAILURE);
114600d0963fSdilpreet 
114700d0963fSdilpreet 	/*
114800d0963fSdilpreet 	 * rest of this function is actually for cautious puts
114900d0963fSdilpreet 	 */
115000d0963fSdilpreet 	for (; repcount; repcount--) {
115100d0963fSdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
115200d0963fSdilpreet 			switch (size) {
115300d0963fSdilpreet 			case sizeof (uint8_t):
115400d0963fSdilpreet 				pci_config_wr8(hp, (uint8_t *)dev_addr,
115500d0963fSdilpreet 				    *(uint8_t *)host_addr);
115600d0963fSdilpreet 				break;
115700d0963fSdilpreet 			case sizeof (uint16_t):
115800d0963fSdilpreet 				pci_config_wr16(hp, (uint16_t *)dev_addr,
115900d0963fSdilpreet 				    *(uint16_t *)host_addr);
116000d0963fSdilpreet 				break;
116100d0963fSdilpreet 			case sizeof (uint32_t):
116200d0963fSdilpreet 				pci_config_wr32(hp, (uint32_t *)dev_addr,
116300d0963fSdilpreet 				    *(uint32_t *)host_addr);
116400d0963fSdilpreet 				break;
116500d0963fSdilpreet 			case sizeof (uint64_t):
116600d0963fSdilpreet 				pci_config_wr64(hp, (uint64_t *)dev_addr,
116700d0963fSdilpreet 				    *(uint64_t *)host_addr);
116800d0963fSdilpreet 				break;
116900d0963fSdilpreet 			default:
117000d0963fSdilpreet 				err = DDI_FAILURE;
117100d0963fSdilpreet 				break;
117200d0963fSdilpreet 			}
117300d0963fSdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
117400d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
117500d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
117600d0963fSdilpreet 				switch (size) {
117700d0963fSdilpreet 				case sizeof (uint8_t):
117800d0963fSdilpreet 					i_ddi_io_put8(hp,
117900d0963fSdilpreet 					    (uint8_t *)dev_addr,
118000d0963fSdilpreet 					    *(uint8_t *)host_addr);
118100d0963fSdilpreet 					break;
118200d0963fSdilpreet 				case sizeof (uint16_t):
118300d0963fSdilpreet 					i_ddi_io_swap_put16(hp,
118400d0963fSdilpreet 					    (uint16_t *)dev_addr,
118500d0963fSdilpreet 					    *(uint16_t *)host_addr);
118600d0963fSdilpreet 					break;
118700d0963fSdilpreet 				case sizeof (uint32_t):
118800d0963fSdilpreet 					i_ddi_io_swap_put32(hp,
118900d0963fSdilpreet 					    (uint32_t *)dev_addr,
119000d0963fSdilpreet 					    *(uint32_t *)host_addr);
119100d0963fSdilpreet 					break;
119200d0963fSdilpreet 				/*
119300d0963fSdilpreet 				 * note the 64-bit case is a dummy
119400d0963fSdilpreet 				 * function - so no need to swap
119500d0963fSdilpreet 				 */
119600d0963fSdilpreet 				case sizeof (uint64_t):
119700d0963fSdilpreet 					i_ddi_io_put64(hp,
119800d0963fSdilpreet 					    (uint64_t *)dev_addr,
119900d0963fSdilpreet 					    *(uint64_t *)host_addr);
120000d0963fSdilpreet 					break;
120100d0963fSdilpreet 				default:
120200d0963fSdilpreet 					err = DDI_FAILURE;
120300d0963fSdilpreet 					break;
120400d0963fSdilpreet 				}
120500d0963fSdilpreet 			} else {
120600d0963fSdilpreet 				switch (size) {
120700d0963fSdilpreet 				case sizeof (uint8_t):
120800d0963fSdilpreet 					i_ddi_io_put8(hp,
120900d0963fSdilpreet 					    (uint8_t *)dev_addr,
121000d0963fSdilpreet 					    *(uint8_t *)host_addr);
121100d0963fSdilpreet 					break;
121200d0963fSdilpreet 				case sizeof (uint16_t):
121300d0963fSdilpreet 					i_ddi_io_put16(hp,
121400d0963fSdilpreet 					    (uint16_t *)dev_addr,
121500d0963fSdilpreet 					    *(uint16_t *)host_addr);
121600d0963fSdilpreet 					break;
121700d0963fSdilpreet 				case sizeof (uint32_t):
121800d0963fSdilpreet 					i_ddi_io_put32(hp,
121900d0963fSdilpreet 					    (uint32_t *)dev_addr,
122000d0963fSdilpreet 					    *(uint32_t *)host_addr);
122100d0963fSdilpreet 					break;
122200d0963fSdilpreet 				case sizeof (uint64_t):
122300d0963fSdilpreet 					i_ddi_io_put64(hp,
122400d0963fSdilpreet 					    (uint64_t *)dev_addr,
122500d0963fSdilpreet 					    *(uint64_t *)host_addr);
122600d0963fSdilpreet 					break;
122700d0963fSdilpreet 				default:
122800d0963fSdilpreet 					err = DDI_FAILURE;
122900d0963fSdilpreet 					break;
123000d0963fSdilpreet 				}
123100d0963fSdilpreet 			}
123200d0963fSdilpreet 		} else {
123300d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
123400d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
123500d0963fSdilpreet 				switch (size) {
123600d0963fSdilpreet 				case sizeof (uint8_t):
123700d0963fSdilpreet 					*(uint8_t *)dev_addr =
123800d0963fSdilpreet 					    *(uint8_t *)host_addr;
123900d0963fSdilpreet 					break;
124000d0963fSdilpreet 				case sizeof (uint16_t):
124100d0963fSdilpreet 					*(uint16_t *)dev_addr =
124200d0963fSdilpreet 					    ddi_swap16(*(uint16_t *)host_addr);
124300d0963fSdilpreet 					break;
124400d0963fSdilpreet 				case sizeof (uint32_t):
124500d0963fSdilpreet 					*(uint32_t *)dev_addr =
124600d0963fSdilpreet 					    ddi_swap32(*(uint32_t *)host_addr);
124700d0963fSdilpreet 					break;
124800d0963fSdilpreet 				case sizeof (uint64_t):
124900d0963fSdilpreet 					*(uint64_t *)dev_addr =
125000d0963fSdilpreet 					    ddi_swap64(*(uint64_t *)host_addr);
125100d0963fSdilpreet 					break;
125200d0963fSdilpreet 				default:
125300d0963fSdilpreet 					err = DDI_FAILURE;
125400d0963fSdilpreet 					break;
125500d0963fSdilpreet 				}
125600d0963fSdilpreet 			} else {
125700d0963fSdilpreet 				switch (size) {
125800d0963fSdilpreet 				case sizeof (uint8_t):
125900d0963fSdilpreet 					*(uint8_t *)dev_addr =
126000d0963fSdilpreet 					    *(uint8_t *)host_addr;
126100d0963fSdilpreet 					break;
126200d0963fSdilpreet 				case sizeof (uint16_t):
126300d0963fSdilpreet 					*(uint16_t *)dev_addr =
126400d0963fSdilpreet 					    *(uint16_t *)host_addr;
126500d0963fSdilpreet 					break;
126600d0963fSdilpreet 				case sizeof (uint32_t):
126700d0963fSdilpreet 					*(uint32_t *)dev_addr =
126800d0963fSdilpreet 					    *(uint32_t *)host_addr;
126900d0963fSdilpreet 					break;
127000d0963fSdilpreet 				case sizeof (uint64_t):
127100d0963fSdilpreet 					*(uint64_t *)dev_addr =
127200d0963fSdilpreet 					    *(uint64_t *)host_addr;
127300d0963fSdilpreet 					break;
127400d0963fSdilpreet 				default:
127500d0963fSdilpreet 					err = DDI_FAILURE;
127600d0963fSdilpreet 					break;
127700d0963fSdilpreet 				}
127800d0963fSdilpreet 			}
127900d0963fSdilpreet 		}
128000d0963fSdilpreet 		host_addr += size;
128100d0963fSdilpreet 		if (flags == DDI_DEV_AUTOINCR)
128200d0963fSdilpreet 			dev_addr += size;
128300d0963fSdilpreet 	}
128400d0963fSdilpreet 	return (err);
128500d0963fSdilpreet }
128600d0963fSdilpreet 
128700d0963fSdilpreet 
128800d0963fSdilpreet int
pci_fm_acc_setup(ddi_acc_hdl_t * hp,off_t offset,off_t len)128900d0963fSdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
129000d0963fSdilpreet {
129100d0963fSdilpreet 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
129200d0963fSdilpreet 
129300d0963fSdilpreet 	/* endian-ness check */
129400d0963fSdilpreet 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
129500d0963fSdilpreet 		return (DDI_FAILURE);
129600d0963fSdilpreet 
129700d0963fSdilpreet 	/*
129800d0963fSdilpreet 	 * range check
129900d0963fSdilpreet 	 */
130000d0963fSdilpreet 	if ((offset >= PCI_CONF_HDR_SIZE) ||
130100d0963fSdilpreet 	    (len > PCI_CONF_HDR_SIZE) ||
130200d0963fSdilpreet 	    (offset + len > PCI_CONF_HDR_SIZE))
130300d0963fSdilpreet 		return (DDI_FAILURE);
130400d0963fSdilpreet 
130500d0963fSdilpreet 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
130600d0963fSdilpreet 	/*
130700d0963fSdilpreet 	 * always use cautious mechanism for config space gets
130800d0963fSdilpreet 	 */
130900d0963fSdilpreet 	ap->ahi_get8 = i_ddi_caut_get8;
131000d0963fSdilpreet 	ap->ahi_get16 = i_ddi_caut_get16;
131100d0963fSdilpreet 	ap->ahi_get32 = i_ddi_caut_get32;
131200d0963fSdilpreet 	ap->ahi_get64 = i_ddi_caut_get64;
131300d0963fSdilpreet 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
131400d0963fSdilpreet 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
131500d0963fSdilpreet 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
131600d0963fSdilpreet 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
131700d0963fSdilpreet 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
131800d0963fSdilpreet 		ap->ahi_put8 = i_ddi_caut_put8;
131900d0963fSdilpreet 		ap->ahi_put16 = i_ddi_caut_put16;
132000d0963fSdilpreet 		ap->ahi_put32 = i_ddi_caut_put32;
132100d0963fSdilpreet 		ap->ahi_put64 = i_ddi_caut_put64;
132200d0963fSdilpreet 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
132300d0963fSdilpreet 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
132400d0963fSdilpreet 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
132500d0963fSdilpreet 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
132600d0963fSdilpreet 	} else {
132700d0963fSdilpreet 		ap->ahi_put8 = pci_config_wr8;
132800d0963fSdilpreet 		ap->ahi_put16 = pci_config_wr16;
132900d0963fSdilpreet 		ap->ahi_put32 = pci_config_wr32;
133000d0963fSdilpreet 		ap->ahi_put64 = pci_config_wr64;
133100d0963fSdilpreet 		ap->ahi_rep_put8 = pci_config_rep_wr8;
133200d0963fSdilpreet 		ap->ahi_rep_put16 = pci_config_rep_wr16;
133300d0963fSdilpreet 		ap->ahi_rep_put32 = pci_config_rep_wr32;
133400d0963fSdilpreet 		ap->ahi_rep_put64 = pci_config_rep_wr64;
133500d0963fSdilpreet 	}
133600d0963fSdilpreet 
133700d0963fSdilpreet 	/* Initialize to default check/notify functions */
133800d0963fSdilpreet 	ap->ahi_fault_check = i_ddi_acc_fault_check;
133900d0963fSdilpreet 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
134000d0963fSdilpreet 	ap->ahi_fault = 0;
134100d0963fSdilpreet 	impl_acc_err_init(hp);
134200d0963fSdilpreet 	return (DDI_SUCCESS);
134300d0963fSdilpreet }
134400d0963fSdilpreet 
134500d0963fSdilpreet 
134600d0963fSdilpreet int
pci_common_ctlops_peek(peekpoke_ctlops_t * in_args)134700d0963fSdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
134800d0963fSdilpreet {
134900d0963fSdilpreet 	size_t size = in_args->size;
135000d0963fSdilpreet 	uintptr_t dev_addr = in_args->dev_addr;
135100d0963fSdilpreet 	uintptr_t host_addr = in_args->host_addr;
135200d0963fSdilpreet 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
135300d0963fSdilpreet 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
135400d0963fSdilpreet 	size_t repcount = in_args->repcount;
135500d0963fSdilpreet 	uint_t flags = in_args->flags;
135600d0963fSdilpreet 	int err = DDI_SUCCESS;
135700d0963fSdilpreet 
135800d0963fSdilpreet 	/*
135900d0963fSdilpreet 	 * if no handle then this is a peek. We have to return failure here
136000d0963fSdilpreet 	 * as we have no way of knowing whether this is a MEM or IO space access
136100d0963fSdilpreet 	 */
136200d0963fSdilpreet 	if (in_args->handle == NULL)
136300d0963fSdilpreet 		return (DDI_FAILURE);
136400d0963fSdilpreet 
136500d0963fSdilpreet 	for (; repcount; repcount--) {
136600d0963fSdilpreet 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
136700d0963fSdilpreet 			switch (size) {
136800d0963fSdilpreet 			case sizeof (uint8_t):
136900d0963fSdilpreet 				*(uint8_t *)host_addr = pci_config_rd8(hp,
137000d0963fSdilpreet 				    (uint8_t *)dev_addr);
137100d0963fSdilpreet 				break;
137200d0963fSdilpreet 			case sizeof (uint16_t):
137300d0963fSdilpreet 				*(uint16_t *)host_addr = pci_config_rd16(hp,
137400d0963fSdilpreet 				    (uint16_t *)dev_addr);
137500d0963fSdilpreet 				break;
137600d0963fSdilpreet 			case sizeof (uint32_t):
137700d0963fSdilpreet 				*(uint32_t *)host_addr = pci_config_rd32(hp,
137800d0963fSdilpreet 				    (uint32_t *)dev_addr);
137900d0963fSdilpreet 				break;
138000d0963fSdilpreet 			case sizeof (uint64_t):
138100d0963fSdilpreet 				*(uint64_t *)host_addr = pci_config_rd64(hp,
138200d0963fSdilpreet 				    (uint64_t *)dev_addr);
138300d0963fSdilpreet 				break;
138400d0963fSdilpreet 			default:
138500d0963fSdilpreet 				err = DDI_FAILURE;
138600d0963fSdilpreet 				break;
138700d0963fSdilpreet 			}
138800d0963fSdilpreet 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
138900d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
139000d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
139100d0963fSdilpreet 				switch (size) {
139200d0963fSdilpreet 				case sizeof (uint8_t):
139300d0963fSdilpreet 					*(uint8_t *)host_addr =
139400d0963fSdilpreet 					    i_ddi_io_get8(hp,
139500d0963fSdilpreet 					    (uint8_t *)dev_addr);
139600d0963fSdilpreet 					break;
139700d0963fSdilpreet 				case sizeof (uint16_t):
139800d0963fSdilpreet 					*(uint16_t *)host_addr =
139900d0963fSdilpreet 					    i_ddi_io_swap_get16(hp,
140000d0963fSdilpreet 					    (uint16_t *)dev_addr);
140100d0963fSdilpreet 					break;
140200d0963fSdilpreet 				case sizeof (uint32_t):
140300d0963fSdilpreet 					*(uint32_t *)host_addr =
140400d0963fSdilpreet 					    i_ddi_io_swap_get32(hp,
140500d0963fSdilpreet 					    (uint32_t *)dev_addr);
140600d0963fSdilpreet 					break;
140700d0963fSdilpreet 				/*
140800d0963fSdilpreet 				 * note the 64-bit case is a dummy
140900d0963fSdilpreet 				 * function - so no need to swap
141000d0963fSdilpreet 				 */
141100d0963fSdilpreet 				case sizeof (uint64_t):
141200d0963fSdilpreet 					*(uint64_t *)host_addr =
141300d0963fSdilpreet 					    i_ddi_io_get64(hp,
141400d0963fSdilpreet 					    (uint64_t *)dev_addr);
141500d0963fSdilpreet 					break;
141600d0963fSdilpreet 				default:
141700d0963fSdilpreet 					err = DDI_FAILURE;
141800d0963fSdilpreet 					break;
141900d0963fSdilpreet 				}
142000d0963fSdilpreet 			} else {
142100d0963fSdilpreet 				switch (size) {
142200d0963fSdilpreet 				case sizeof (uint8_t):
142300d0963fSdilpreet 					*(uint8_t *)host_addr =
142400d0963fSdilpreet 					    i_ddi_io_get8(hp,
142500d0963fSdilpreet 					    (uint8_t *)dev_addr);
142600d0963fSdilpreet 					break;
142700d0963fSdilpreet 				case sizeof (uint16_t):
142800d0963fSdilpreet 					*(uint16_t *)host_addr =
142900d0963fSdilpreet 					    i_ddi_io_get16(hp,
143000d0963fSdilpreet 					    (uint16_t *)dev_addr);
143100d0963fSdilpreet 					break;
143200d0963fSdilpreet 				case sizeof (uint32_t):
143300d0963fSdilpreet 					*(uint32_t *)host_addr =
143400d0963fSdilpreet 					    i_ddi_io_get32(hp,
143500d0963fSdilpreet 					    (uint32_t *)dev_addr);
143600d0963fSdilpreet 					break;
143700d0963fSdilpreet 				case sizeof (uint64_t):
143800d0963fSdilpreet 					*(uint64_t *)host_addr =
143900d0963fSdilpreet 					    i_ddi_io_get64(hp,
144000d0963fSdilpreet 					    (uint64_t *)dev_addr);
144100d0963fSdilpreet 					break;
144200d0963fSdilpreet 				default:
144300d0963fSdilpreet 					err = DDI_FAILURE;
144400d0963fSdilpreet 					break;
144500d0963fSdilpreet 				}
144600d0963fSdilpreet 			}
144700d0963fSdilpreet 		} else {
144800d0963fSdilpreet 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
144900d0963fSdilpreet 			    DDI_STRUCTURE_BE_ACC) {
145000d0963fSdilpreet 				switch (in_args->size) {
145100d0963fSdilpreet 				case sizeof (uint8_t):
145200d0963fSdilpreet 					*(uint8_t *)host_addr =
145300d0963fSdilpreet 					    *(uint8_t *)dev_addr;
145400d0963fSdilpreet 					break;
145500d0963fSdilpreet 				case sizeof (uint16_t):
145600d0963fSdilpreet 					*(uint16_t *)host_addr =
145700d0963fSdilpreet 					    ddi_swap16(*(uint16_t *)dev_addr);
145800d0963fSdilpreet 					break;
145900d0963fSdilpreet 				case sizeof (uint32_t):
146000d0963fSdilpreet 					*(uint32_t *)host_addr =
146100d0963fSdilpreet 					    ddi_swap32(*(uint32_t *)dev_addr);
146200d0963fSdilpreet 					break;
146300d0963fSdilpreet 				case sizeof (uint64_t):
146400d0963fSdilpreet 					*(uint64_t *)host_addr =
146500d0963fSdilpreet 					    ddi_swap64(*(uint64_t *)dev_addr);
146600d0963fSdilpreet 					break;
146700d0963fSdilpreet 				default:
146800d0963fSdilpreet 					err = DDI_FAILURE;
146900d0963fSdilpreet 					break;
147000d0963fSdilpreet 				}
147100d0963fSdilpreet 			} else {
147200d0963fSdilpreet 				switch (in_args->size) {
147300d0963fSdilpreet 				case sizeof (uint8_t):
147400d0963fSdilpreet 					*(uint8_t *)host_addr =
147500d0963fSdilpreet 					    *(uint8_t *)dev_addr;
147600d0963fSdilpreet 					break;
147700d0963fSdilpreet 				case sizeof (uint16_t):
147800d0963fSdilpreet 					*(uint16_t *)host_addr =
147900d0963fSdilpreet 					    *(uint16_t *)dev_addr;
148000d0963fSdilpreet 					break;
148100d0963fSdilpreet 				case sizeof (uint32_t):
148200d0963fSdilpreet 					*(uint32_t *)host_addr =
148300d0963fSdilpreet 					    *(uint32_t *)dev_addr;
148400d0963fSdilpreet 					break;
148500d0963fSdilpreet 				case sizeof (uint64_t):
148600d0963fSdilpreet 					*(uint64_t *)host_addr =
148700d0963fSdilpreet 					    *(uint64_t *)dev_addr;
148800d0963fSdilpreet 					break;
148900d0963fSdilpreet 				default:
149000d0963fSdilpreet 					err = DDI_FAILURE;
149100d0963fSdilpreet 					break;
149200d0963fSdilpreet 				}
149300d0963fSdilpreet 			}
149400d0963fSdilpreet 		}
149500d0963fSdilpreet 		host_addr += size;
149600d0963fSdilpreet 		if (flags == DDI_DEV_AUTOINCR)
149700d0963fSdilpreet 			dev_addr += size;
149800d0963fSdilpreet 	}
149900d0963fSdilpreet 	return (err);
150000d0963fSdilpreet }
150100d0963fSdilpreet 
150200d0963fSdilpreet /*ARGSUSED*/
150300d0963fSdilpreet int
pci_common_peekpoke(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)150400d0963fSdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
1505584b574aSToomas Soome     ddi_ctl_enum_t ctlop, void *arg, void *result)
150600d0963fSdilpreet {
150700d0963fSdilpreet 	if (ctlop == DDI_CTLOPS_PEEK)
150800d0963fSdilpreet 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
150900d0963fSdilpreet 	else
151000d0963fSdilpreet 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
151100d0963fSdilpreet }
151200d0963fSdilpreet 
1513649d4cceSanish /*
1514649d4cceSanish  * These are the get and put functions to be shared with drivers. The
1515649d4cceSanish  * mutex locking is done inside the functions referenced, rather than
1516649d4cceSanish  * here, and is thus shared across PCI child drivers and any other
1517649d4cceSanish  * consumers of PCI config space (such as the ACPI subsystem).
1518649d4cceSanish  *
1519649d4cceSanish  * The configuration space addresses come in as pointers.  This is fine on
1520649d4cceSanish  * a 32-bit system, where the VM space and configuration space are the same
1521649d4cceSanish  * size.  It's not such a good idea on a 64-bit system, where memory
1522649d4cceSanish  * addresses are twice as large as configuration space addresses.  At some
1523649d4cceSanish  * point in the call tree we need to take a stand and say "you are 32-bit
1524649d4cceSanish  * from this time forth", and this seems like a nice self-contained place.
1525649d4cceSanish  */
1526649d4cceSanish 
1527649d4cceSanish uint8_t
pci_config_rd8(ddi_acc_impl_t * hdlp,uint8_t * addr)1528649d4cceSanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
1529649d4cceSanish {
1530649d4cceSanish 	pci_acc_cfblk_t *cfp;
1531649d4cceSanish 	uint8_t	rval;
1532649d4cceSanish 	int reg;
1533649d4cceSanish 
1534649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1535649d4cceSanish 
1536649d4cceSanish 	reg = (int)(uintptr_t)addr;
1537649d4cceSanish 
1538649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1539649d4cceSanish 
1540649d4cceSanish 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1541649d4cceSanish 	    reg);
1542649d4cceSanish 
1543649d4cceSanish 	return (rval);
1544649d4cceSanish }
1545649d4cceSanish 
1546649d4cceSanish void
pci_config_rep_rd8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)1547649d4cceSanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1548584b574aSToomas Soome     uint8_t *dev_addr, size_t repcount, uint_t flags)
1549649d4cceSanish {
1550649d4cceSanish 	uint8_t *h, *d;
1551649d4cceSanish 
1552649d4cceSanish 	h = host_addr;
1553649d4cceSanish 	d = dev_addr;
1554649d4cceSanish 
1555649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1556649d4cceSanish 		for (; repcount; repcount--)
1557649d4cceSanish 			*h++ = pci_config_rd8(hdlp, d++);
1558649d4cceSanish 	else
1559649d4cceSanish 		for (; repcount; repcount--)
1560649d4cceSanish 			*h++ = pci_config_rd8(hdlp, d);
1561649d4cceSanish }
1562649d4cceSanish 
1563649d4cceSanish uint16_t
pci_config_rd16(ddi_acc_impl_t * hdlp,uint16_t * addr)1564649d4cceSanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
1565649d4cceSanish {
1566649d4cceSanish 	pci_acc_cfblk_t *cfp;
1567649d4cceSanish 	uint16_t rval;
1568649d4cceSanish 	int reg;
1569649d4cceSanish 
1570649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1571649d4cceSanish 
1572649d4cceSanish 	reg = (int)(uintptr_t)addr;
1573649d4cceSanish 
1574649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1575649d4cceSanish 
1576649d4cceSanish 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
1577649d4cceSanish 	    reg);
1578649d4cceSanish 
1579649d4cceSanish 	return (rval);
1580649d4cceSanish }
1581649d4cceSanish 
1582649d4cceSanish void
pci_config_rep_rd16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)1583649d4cceSanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1584584b574aSToomas Soome     uint16_t *dev_addr, size_t repcount, uint_t flags)
1585649d4cceSanish {
1586649d4cceSanish 	uint16_t *h, *d;
1587649d4cceSanish 
1588649d4cceSanish 	h = host_addr;
1589649d4cceSanish 	d = dev_addr;
1590649d4cceSanish 
1591649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1592649d4cceSanish 		for (; repcount; repcount--)
1593649d4cceSanish 			*h++ = pci_config_rd16(hdlp, d++);
1594649d4cceSanish 	else
1595649d4cceSanish 		for (; repcount; repcount--)
1596649d4cceSanish 			*h++ = pci_config_rd16(hdlp, d);
1597649d4cceSanish }
1598649d4cceSanish 
1599649d4cceSanish uint32_t
pci_config_rd32(ddi_acc_impl_t * hdlp,uint32_t * addr)1600649d4cceSanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
1601649d4cceSanish {
1602649d4cceSanish 	pci_acc_cfblk_t *cfp;
1603649d4cceSanish 	uint32_t rval;
1604649d4cceSanish 	int reg;
1605649d4cceSanish 
1606649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1607649d4cceSanish 
1608649d4cceSanish 	reg = (int)(uintptr_t)addr;
1609649d4cceSanish 
1610649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1611649d4cceSanish 
1612649d4cceSanish 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
1613649d4cceSanish 	    cfp->c_funcnum, reg);
1614649d4cceSanish 
1615649d4cceSanish 	return (rval);
1616649d4cceSanish }
1617649d4cceSanish 
1618649d4cceSanish void
pci_config_rep_rd32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)1619649d4cceSanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1620584b574aSToomas Soome     uint32_t *dev_addr, size_t repcount, uint_t flags)
1621649d4cceSanish {
1622649d4cceSanish 	uint32_t *h, *d;
1623649d4cceSanish 
1624649d4cceSanish 	h = host_addr;
1625649d4cceSanish 	d = dev_addr;
1626649d4cceSanish 
1627649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1628649d4cceSanish 		for (; repcount; repcount--)
1629649d4cceSanish 			*h++ = pci_config_rd32(hdlp, d++);
1630649d4cceSanish 	else
1631649d4cceSanish 		for (; repcount; repcount--)
1632649d4cceSanish 			*h++ = pci_config_rd32(hdlp, d);
1633649d4cceSanish }
1634649d4cceSanish 
1635649d4cceSanish 
1636649d4cceSanish void
pci_config_wr8(ddi_acc_impl_t * hdlp,uint8_t * addr,uint8_t value)1637649d4cceSanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
1638649d4cceSanish {
1639649d4cceSanish 	pci_acc_cfblk_t *cfp;
1640649d4cceSanish 	int reg;
1641649d4cceSanish 
1642649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1643649d4cceSanish 
1644649d4cceSanish 	reg = (int)(uintptr_t)addr;
1645649d4cceSanish 
1646649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1647649d4cceSanish 
1648649d4cceSanish 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
1649649d4cceSanish 	    cfp->c_funcnum, reg, value);
1650649d4cceSanish }
1651649d4cceSanish 
1652649d4cceSanish void
pci_config_rep_wr8(ddi_acc_impl_t * hdlp,uint8_t * host_addr,uint8_t * dev_addr,size_t repcount,uint_t flags)1653649d4cceSanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
1654584b574aSToomas Soome     uint8_t *dev_addr, size_t repcount, uint_t flags)
1655649d4cceSanish {
1656649d4cceSanish 	uint8_t *h, *d;
1657649d4cceSanish 
1658649d4cceSanish 	h = host_addr;
1659649d4cceSanish 	d = dev_addr;
1660649d4cceSanish 
1661649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1662649d4cceSanish 		for (; repcount; repcount--)
1663649d4cceSanish 			pci_config_wr8(hdlp, d++, *h++);
1664649d4cceSanish 	else
1665649d4cceSanish 		for (; repcount; repcount--)
1666649d4cceSanish 			pci_config_wr8(hdlp, d, *h++);
1667649d4cceSanish }
1668649d4cceSanish 
1669649d4cceSanish void
pci_config_wr16(ddi_acc_impl_t * hdlp,uint16_t * addr,uint16_t value)1670649d4cceSanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
1671649d4cceSanish {
1672649d4cceSanish 	pci_acc_cfblk_t *cfp;
1673649d4cceSanish 	int reg;
1674649d4cceSanish 
1675649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1676649d4cceSanish 
1677649d4cceSanish 	reg = (int)(uintptr_t)addr;
1678649d4cceSanish 
1679649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1680649d4cceSanish 
1681649d4cceSanish 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
1682649d4cceSanish 	    cfp->c_funcnum, reg, value);
1683649d4cceSanish }
1684649d4cceSanish 
1685649d4cceSanish void
pci_config_rep_wr16(ddi_acc_impl_t * hdlp,uint16_t * host_addr,uint16_t * dev_addr,size_t repcount,uint_t flags)1686649d4cceSanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
1687584b574aSToomas Soome     uint16_t *dev_addr, size_t repcount, uint_t flags)
1688649d4cceSanish {
1689649d4cceSanish 	uint16_t *h, *d;
1690649d4cceSanish 
1691649d4cceSanish 	h = host_addr;
1692649d4cceSanish 	d = dev_addr;
1693649d4cceSanish 
1694649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1695649d4cceSanish 		for (; repcount; repcount--)
1696649d4cceSanish 			pci_config_wr16(hdlp, d++, *h++);
1697649d4cceSanish 	else
1698649d4cceSanish 		for (; repcount; repcount--)
1699649d4cceSanish 			pci_config_wr16(hdlp, d, *h++);
1700649d4cceSanish }
1701649d4cceSanish 
1702649d4cceSanish void
pci_config_wr32(ddi_acc_impl_t * hdlp,uint32_t * addr,uint32_t value)1703649d4cceSanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
1704649d4cceSanish {
1705649d4cceSanish 	pci_acc_cfblk_t *cfp;
1706649d4cceSanish 	int reg;
1707649d4cceSanish 
1708649d4cceSanish 	ASSERT64(((uintptr_t)addr >> 32) == 0);
1709649d4cceSanish 
1710649d4cceSanish 	reg = (int)(uintptr_t)addr;
1711649d4cceSanish 
1712649d4cceSanish 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
1713649d4cceSanish 
1714649d4cceSanish 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
1715649d4cceSanish 	    cfp->c_funcnum, reg, value);
1716649d4cceSanish }
1717649d4cceSanish 
1718649d4cceSanish void
pci_config_rep_wr32(ddi_acc_impl_t * hdlp,uint32_t * host_addr,uint32_t * dev_addr,size_t repcount,uint_t flags)1719649d4cceSanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
1720584b574aSToomas Soome     uint32_t *dev_addr, size_t repcount, uint_t flags)
1721649d4cceSanish {
1722649d4cceSanish 	uint32_t *h, *d;
1723649d4cceSanish 
1724649d4cceSanish 	h = host_addr;
1725649d4cceSanish 	d = dev_addr;
1726649d4cceSanish 
1727649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR)
1728649d4cceSanish 		for (; repcount; repcount--)
1729649d4cceSanish 			pci_config_wr32(hdlp, d++, *h++);
1730649d4cceSanish 	else
1731649d4cceSanish 		for (; repcount; repcount--)
1732649d4cceSanish 			pci_config_wr32(hdlp, d, *h++);
1733649d4cceSanish }
1734649d4cceSanish 
1735649d4cceSanish uint64_t
pci_config_rd64(ddi_acc_impl_t * hdlp,uint64_t * addr)1736649d4cceSanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
1737649d4cceSanish {
1738649d4cceSanish 	uint32_t lw_val;
1739649d4cceSanish 	uint32_t hi_val;
1740649d4cceSanish 	uint32_t *dp;
1741649d4cceSanish 	uint64_t val;
1742649d4cceSanish 
1743649d4cceSanish 	dp = (uint32_t *)addr;
1744649d4cceSanish 	lw_val = pci_config_rd32(hdlp, dp);
1745649d4cceSanish 	dp++;
1746649d4cceSanish 	hi_val = pci_config_rd32(hdlp, dp);
1747649d4cceSanish 	val = ((uint64_t)hi_val << 32) | lw_val;
1748649d4cceSanish 	return (val);
1749649d4cceSanish }
1750649d4cceSanish 
1751649d4cceSanish void
pci_config_wr64(ddi_acc_impl_t * hdlp,uint64_t * addr,uint64_t value)1752649d4cceSanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
1753649d4cceSanish {
1754649d4cceSanish 	uint32_t lw_val;
1755649d4cceSanish 	uint32_t hi_val;
1756649d4cceSanish 	uint32_t *dp;
1757649d4cceSanish 
1758649d4cceSanish 	dp = (uint32_t *)addr;
1759649d4cceSanish 	lw_val = (uint32_t)(value & 0xffffffff);
1760649d4cceSanish 	hi_val = (uint32_t)(value >> 32);
1761649d4cceSanish 	pci_config_wr32(hdlp, dp, lw_val);
1762649d4cceSanish 	dp++;
1763649d4cceSanish 	pci_config_wr32(hdlp, dp, hi_val);
1764649d4cceSanish }
1765649d4cceSanish 
1766649d4cceSanish void
pci_config_rep_rd64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)1767649d4cceSanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1768584b574aSToomas Soome     uint64_t *dev_addr, size_t repcount, uint_t flags)
1769649d4cceSanish {
1770649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR) {
1771649d4cceSanish 		for (; repcount; repcount--)
1772649d4cceSanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
1773649d4cceSanish 	} else {
1774649d4cceSanish 		for (; repcount; repcount--)
1775649d4cceSanish 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
1776649d4cceSanish 	}
1777649d4cceSanish }
1778649d4cceSanish 
1779649d4cceSanish void
pci_config_rep_wr64(ddi_acc_impl_t * hdlp,uint64_t * host_addr,uint64_t * dev_addr,size_t repcount,uint_t flags)1780649d4cceSanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
1781584b574aSToomas Soome     uint64_t *dev_addr, size_t repcount, uint_t flags)
1782649d4cceSanish {
1783649d4cceSanish 	if (flags == DDI_DEV_AUTOINCR) {
1784649d4cceSanish 		for (; repcount; repcount--)
1785649d4cceSanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
1786649d4cceSanish 	} else {
1787649d4cceSanish 		for (; repcount; repcount--)
1788649d4cceSanish 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
1789649d4cceSanish 	}
1790649d4cceSanish }
1791