Home | History | Annotate | Download | only in pci
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  *	File that has code which is common between pci(7d) and npe(7d)
     29  *	It shares the following:
     30  *	- interrupt code
     31  *	- pci_tools ioctl code
     32  *	- name_child code
     33  *	- set_parent_private_data code
     34  */
     35 
     36 #include <sys/conf.h>
     37 #include <sys/pci.h>
     38 #include <sys/sunndi.h>
     39 #include <sys/mach_intr.h>
     40 #include <sys/pci_intr_lib.h>
     41 #include <sys/psm.h>
     42 #include <sys/policy.h>
     43 #include <sys/sysmacros.h>
     44 #include <sys/clock.h>
     45 #include <sys/apic.h>
     46 #include <sys/pci_tools.h>
     47 #include <io/pci/pci_var.h>
     48 #include <io/pci/pci_tools_ext.h>
     49 #include <io/pci/pci_common.h>
     50 #include <sys/pci_cfgspace.h>
     51 #include <sys/pci_impl.h>
     52 #include <sys/pci_cap.h>
     53 
     54 /*
     55  * Function prototypes
     56  */
     57 static int	pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *);
     58 static int	pci_enable_intr(dev_info_t *, dev_info_t *,
     59 		    ddi_intr_handle_impl_t *, uint32_t);
     60 static void	pci_disable_intr(dev_info_t *, dev_info_t *,
     61 		    ddi_intr_handle_impl_t *, uint32_t);
     62 
     63 /* Extern decalration for pcplusmp module */
     64 extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
     65 		    psm_intr_op_t, int *);
     66 
     67 /*
     68  * pci_name_child:
     69  *
     70  *	Assign the address portion of the node name
     71  */
     72 int
     73 pci_common_name_child(dev_info_t *child, char *name, int namelen)
     74 {
     75 	int		dev, func, length;
     76 	char		**unit_addr;
     77 	uint_t		n;
     78 	pci_regspec_t	*pci_rp;
     79 
     80 	if (ndi_dev_is_persistent_node(child) == 0) {
     81 		/*
     82 		 * For .conf node, use "unit-address" property
     83 		 */
     84 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
     85 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
     86 		    DDI_PROP_SUCCESS) {
     87 			cmn_err(CE_WARN, "cannot find unit-address in %s.conf",
     88 			    ddi_get_name(child));
     89 			return (DDI_FAILURE);
     90 		}
     91 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
     92 			cmn_err(CE_WARN, "unit-address property in %s.conf"
     93 			    " not well-formed", ddi_get_name(child));
     94 			ddi_prop_free(unit_addr);
     95 			return (DDI_FAILURE);
     96 		}
     97 		(void) snprintf(name, namelen, "%s", *unit_addr);
     98 		ddi_prop_free(unit_addr);
     99 		return (DDI_SUCCESS);
    100 	}
    101 
    102 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
    103 	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
    104 		cmn_err(CE_WARN, "cannot find reg property in %s",
    105 		    ddi_get_name(child));
    106 		return (DDI_FAILURE);
    107 	}
    108 
    109 	/* copy the device identifications */
    110 	dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
    111 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
    112 
    113 	/*
    114 	 * free the memory allocated by ddi_prop_lookup_int_array
    115 	 */
    116 	ddi_prop_free(pci_rp);
    117 
    118 	if (func != 0) {
    119 		(void) snprintf(name, namelen, "%x,%x", dev, func);
    120 	} else {
    121 		(void) snprintf(name, namelen, "%x", dev);
    122 	}
    123 
    124 	return (DDI_SUCCESS);
    125 }
    126 
    127 /*
    128  * Interrupt related code:
    129  *
    130  * The following busop is common to npe and pci drivers
    131  *	bus_introp
    132  */
    133 
    134 /*
    135  * Create the ddi_parent_private_data for a pseudo child.
    136  */
    137 void
    138 pci_common_set_parent_private_data(dev_info_t *dip)
    139 {
    140 	struct ddi_parent_private_data *pdptr;
    141 
    142 	pdptr = (struct ddi_parent_private_data *)kmem_zalloc(
    143 	    (sizeof (struct ddi_parent_private_data) +
    144 	    sizeof (struct intrspec)), KM_SLEEP);
    145 	pdptr->par_intr = (struct intrspec *)(pdptr + 1);
    146 	pdptr->par_nintr = 1;
    147 	ddi_set_parent_data(dip, pdptr);
    148 }
    149 
    150 /*
    151  * pci_get_priority:
    152  *	Figure out the priority of the device
    153  */
    154 static int
    155 pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri)
    156 {
    157 	struct intrspec *ispec;
    158 
    159 	DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n",
    160 	    (void *)dip, (void *)hdlp));
    161 
    162 	if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
    163 	    hdlp->ih_inum)) == NULL) {
    164 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
    165 			*pri = pci_class_to_pil(dip);
    166 			pci_common_set_parent_private_data(hdlp->ih_dip);
    167 			ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip,
    168 			    hdlp->ih_inum);
    169 			return (DDI_SUCCESS);
    170 		}
    171 		return (DDI_FAILURE);
    172 	}
    173 
    174 	*pri = ispec->intrspec_pri;
    175 	return (DDI_SUCCESS);
    176 }
    177 
    178 
    179 
    180 static int pcieb_intr_pri_counter = 0;
    181 
    182 /*
    183  * pci_common_intr_ops: bus_intr_op() function for interrupt support
    184  */
    185 int
    186 pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    187     ddi_intr_handle_impl_t *hdlp, void *result)
    188 {
    189 	int			priority = 0;
    190 	int			psm_status = 0;
    191 	int			pci_status = 0;
    192 	int			pci_rval, psm_rval = PSM_FAILURE;
    193 	int			types = 0;
    194 	int			pciepci = 0;
    195 	int			i, j, count;
    196 	int			rv;
    197 	int			behavior;
    198 	int			cap_ptr;
    199 	uint16_t		msi_cap_base, msix_cap_base, cap_ctrl;
    200 	char			*prop;
    201 	ddi_intrspec_t		isp;
    202 	struct intrspec		*ispec;
    203 	ddi_intr_handle_impl_t	tmp_hdl;
    204 	ddi_intr_msix_t		*msix_p;
    205 	ihdl_plat_t		*ihdl_plat_datap;
    206 	ddi_intr_handle_t	*h_array;
    207 	ddi_acc_handle_t	handle;
    208 
    209 	DDI_INTR_NEXDBG((CE_CONT,
    210 	    "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
    211 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
    212 
    213 	/* Process the request */
    214 	switch (intr_op) {
    215 	case DDI_INTROP_SUPPORTED_TYPES:
    216 		/*
    217 		 * First we determine the interrupt types supported by the
    218 		 * device itself, then we filter them through what the OS
    219 		 * and system supports.  We determine system-level
    220 		 * interrupt type support for anything other than fixed intrs
    221 		 * through the psm_intr_ops vector
    222 		 */
    223 		rv = DDI_FAILURE;
    224 
    225 		/* Fixed supported by default */
    226 		types = DDI_INTR_TYPE_FIXED;
    227 
    228 		if (psm_intr_ops == NULL) {
    229 			*(int *)result = types;
    230 			return (DDI_SUCCESS);
    231 		}
    232 		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
    233 			return (DDI_FAILURE);
    234 
    235 		/* Sanity test cap control values if found */
    236 
    237 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) ==
    238 		    DDI_SUCCESS) {
    239 			cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base,
    240 			    PCI_MSI_CTRL);
    241 			if (cap_ctrl == PCI_CAP_EINVAL16)
    242 				goto SUPPORTED_TYPES_OUT;
    243 
    244 			types |= DDI_INTR_TYPE_MSI;
    245 		}
    246 
    247 		if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) ==
    248 		    DDI_SUCCESS) {
    249 			cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base,
    250 			    PCI_MSIX_CTRL);
    251 			if (cap_ctrl == PCI_CAP_EINVAL16)
    252 				goto SUPPORTED_TYPES_OUT;
    253 
    254 			types |= DDI_INTR_TYPE_MSIX;
    255 		}
    256 
    257 		/*
    258 		 * Filter device-level types through system-level support
    259 		 */
    260 		tmp_hdl.ih_type = types;
    261 		if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI,
    262 		    &types) != PSM_SUCCESS)
    263 			goto SUPPORTED_TYPES_OUT;
    264 
    265 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
    266 		    "rdip: 0x%p supported types: 0x%x\n", (void *)rdip,
    267 		    *(int *)result));
    268 
    269 		/*
    270 		 * Export any MSI/MSI-X cap locations via properties
    271 		 */
    272 		if (types & DDI_INTR_TYPE_MSI) {
    273 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
    274 			    "pci-msi-capid-pointer", (int)msi_cap_base) !=
    275 			    DDI_PROP_SUCCESS)
    276 				goto SUPPORTED_TYPES_OUT;
    277 		}
    278 		if (types & DDI_INTR_TYPE_MSIX) {
    279 			if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip,
    280 			    "pci-msix-capid-pointer", (int)msix_cap_base) !=
    281 			    DDI_PROP_SUCCESS)
    282 				goto SUPPORTED_TYPES_OUT;
    283 		}
    284 
    285 		rv = DDI_SUCCESS;
    286 
    287 SUPPORTED_TYPES_OUT:
    288 		*(int *)result = types;
    289 		pci_config_teardown(&handle);
    290 		return (rv);
    291 
    292 	case DDI_INTROP_NAVAIL:
    293 	case DDI_INTROP_NINTRS:
    294 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
    295 			if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type,
    296 			    result) != DDI_SUCCESS)
    297 				return (DDI_FAILURE);
    298 		} else {
    299 			*(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip);
    300 			if (*(int *)result == 0)
    301 				return (DDI_FAILURE);
    302 		}
    303 		break;
    304 	case DDI_INTROP_ALLOC:
    305 		/*
    306 		 * MSI or MSIX (figure out number of vectors available)
    307 		 * FIXED interrupts: just return available interrupts
    308 		 */
    309 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
    310 		    (psm_intr_ops != NULL) &&
    311 		    (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) {
    312 			/*
    313 			 * Following check is a special case for 'pcieb'.
    314 			 * This makes sure vectors with the right priority
    315 			 * are allocated for pcieb during ALLOC time.
    316 			 */
    317 			if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) {
    318 				hdlp->ih_pri =
    319 				    (pcieb_intr_pri_counter % 2) ? 4 : 7;
    320 				pciepci = 1;
    321 			} else
    322 				hdlp->ih_pri = priority;
    323 			behavior = (int)(uintptr_t)hdlp->ih_scratch2;
    324 
    325 			/*
    326 			 * Cache in the config handle and cap_ptr
    327 			 */
    328 			if (i_ddi_get_pci_config_handle(rdip) == NULL) {
    329 				if (pci_config_setup(rdip, &handle) !=
    330 				    DDI_SUCCESS)
    331 					return (DDI_FAILURE);
    332 				i_ddi_set_pci_config_handle(rdip, handle);
    333 			}
    334 
    335 			prop = NULL;
    336 			cap_ptr = 0;
    337 			if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
    338 				prop = "pci-msi-capid-pointer";
    339 			else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX)
    340 				prop = "pci-msix-capid-pointer";
    341 
    342 			/*
    343 			 * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES
    344 			 * for MSI(X) before allocation
    345 			 */
    346 			if (prop != NULL) {
    347 				cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip,
    348 				    DDI_PROP_DONTPASS, prop, 0);
    349 				if (cap_ptr == 0) {
    350 					DDI_INTR_NEXDBG((CE_CONT,
    351 					    "pci_common_intr_ops: rdip: 0x%p "
    352 					    "attempted MSI(X) alloc without "
    353 					    "cap property\n", (void *)rdip));
    354 					return (DDI_FAILURE);
    355 				}
    356 			}
    357 			i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr);
    358 
    359 			/*
    360 			 * Allocate interrupt vectors
    361 			 */
    362 			(void) (*psm_intr_ops)(rdip, hdlp,
    363 			    PSM_INTR_OP_ALLOC_VECTORS, result);
    364 
    365 			if (*(int *)result == 0)
    366 				return (DDI_INTR_NOTFOUND);
    367 
    368 			/* verify behavior flag and take appropriate action */
    369 			if ((behavior == DDI_INTR_ALLOC_STRICT) &&
    370 			    (*(int *)result < hdlp->ih_scratch1)) {
    371 				DDI_INTR_NEXDBG((CE_CONT,
    372 				    "pci_common_intr_ops: behavior %x, "
    373 				    "couldn't get enough intrs\n", behavior));
    374 				hdlp->ih_scratch1 = *(int *)result;
    375 				(void) (*psm_intr_ops)(rdip, hdlp,
    376 				    PSM_INTR_OP_FREE_VECTORS, NULL);
    377 				return (DDI_EAGAIN);
    378 			}
    379 
    380 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
    381 				if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) {
    382 					msix_p = pci_msix_init(hdlp->ih_dip);
    383 					if (msix_p) {
    384 						i_ddi_set_msix(hdlp->ih_dip,
    385 						    msix_p);
    386 					} else {
    387 						DDI_INTR_NEXDBG((CE_CONT,
    388 						    "pci_common_intr_ops: MSI-X"
    389 						    "table initilization failed"
    390 						    ", rdip 0x%p inum 0x%x\n",
    391 						    (void *)rdip,
    392 						    hdlp->ih_inum));
    393 
    394 						(void) (*psm_intr_ops)(rdip,
    395 						    hdlp,
    396 						    PSM_INTR_OP_FREE_VECTORS,
    397 						    NULL);
    398 
    399 						return (DDI_FAILURE);
    400 					}
    401 				}
    402 			}
    403 
    404 			if (pciepci) {
    405 				/* update priority in ispec */
    406 				isp = pci_intx_get_ispec(pdip, rdip,
    407 				    (int)hdlp->ih_inum);
    408 				ispec = (struct intrspec *)isp;
    409 				if (ispec)
    410 					ispec->intrspec_pri = hdlp->ih_pri;
    411 				++pcieb_intr_pri_counter;
    412 			}
    413 
    414 		} else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
    415 			/* Figure out if this device supports MASKING */
    416 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
    417 			if (pci_rval == DDI_SUCCESS && pci_status)
    418 				hdlp->ih_cap |= pci_status;
    419 			*(int *)result = 1;	/* DDI_INTR_TYPE_FIXED */
    420 		} else
    421 			return (DDI_FAILURE);
    422 		break;
    423 	case DDI_INTROP_FREE:
    424 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) &&
    425 		    (psm_intr_ops != NULL)) {
    426 			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 ==
    427 			    0) {
    428 				if (handle = i_ddi_get_pci_config_handle(
    429 				    rdip)) {
    430 					(void) pci_config_teardown(&handle);
    431 					i_ddi_set_pci_config_handle(rdip, NULL);
    432 				}
    433 				if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip))
    434 					i_ddi_set_msi_msix_cap_ptr(rdip, 0);
    435 			}
    436 
    437 			(void) (*psm_intr_ops)(rdip, hdlp,
    438 			    PSM_INTR_OP_FREE_VECTORS, NULL);
    439 
    440 			if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) {
    441 				msix_p = i_ddi_get_msix(hdlp->ih_dip);
    442 				if (msix_p &&
    443 				    (i_ddi_intr_get_current_nintrs(
    444 				    hdlp->ih_dip) - 1) == 0) {
    445 					pci_msix_fini(msix_p);
    446 					i_ddi_set_msix(hdlp->ih_dip, NULL);
    447 				}
    448 			}
    449 		}
    450 		break;
    451 	case DDI_INTROP_GETPRI:
    452 		/* Get the priority */
    453 		if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS)
    454 			return (DDI_FAILURE);
    455 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
    456 		    "priority = 0x%x\n", priority));
    457 		*(int *)result = priority;
    458 		break;
    459 	case DDI_INTROP_SETPRI:
    460 		/* Validate the interrupt priority passed */
    461 		if (*(int *)result > LOCK_LEVEL)
    462 			return (DDI_FAILURE);
    463 
    464 		/* Ensure that PSM is all initialized */
    465 		if (psm_intr_ops == NULL)
    466 			return (DDI_FAILURE);
    467 
    468 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
    469 		ispec = (struct intrspec *)isp;
    470 		if (ispec == NULL)
    471 			return (DDI_FAILURE);
    472 
    473 		/* For fixed interrupts */
    474 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
    475 			/* if interrupt is shared, return failure */
    476 			((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
    477 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
    478 			    PSM_INTR_OP_GET_SHARED, &psm_status);
    479 			/*
    480 			 * For fixed interrupts, the irq may not have been
    481 			 * allocated when SET_PRI is called, and the above
    482 			 * GET_SHARED op may return PSM_FAILURE. This is not
    483 			 * a real error and is ignored below.
    484 			 */
    485 			if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) {
    486 				DDI_INTR_NEXDBG((CE_CONT,
    487 				    "pci_common_intr_ops: "
    488 				    "dip 0x%p cannot setpri, psm_rval=%d,"
    489 				    "psm_status=%d\n", (void *)rdip, psm_rval,
    490 				    psm_status));
    491 				return (DDI_FAILURE);
    492 			}
    493 		}
    494 
    495 		/* Change the priority */
    496 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
    497 		    PSM_FAILURE)
    498 			return (DDI_FAILURE);
    499 
    500 		/* update ispec */
    501 		ispec->intrspec_pri = *(int *)result;
    502 		break;
    503 	case DDI_INTROP_ADDISR:
    504 		/* update ispec */
    505 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
    506 		ispec = (struct intrspec *)isp;
    507 		if (ispec) {
    508 			ispec->intrspec_func = hdlp->ih_cb_func;
    509 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
    510 			pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp);
    511 		}
    512 		break;
    513 	case DDI_INTROP_REMISR:
    514 		/* Get the interrupt structure pointer */
    515 		isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum);
    516 		ispec = (struct intrspec *)isp;
    517 		if (ispec) {
    518 			ispec->intrspec_func = (uint_t (*)()) 0;
    519 			ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
    520 			if (ihdl_plat_datap->ip_ksp != NULL)
    521 				pci_kstat_delete(ihdl_plat_datap->ip_ksp);
    522 		}
    523 		break;
    524 	case DDI_INTROP_GETCAP:
    525 		/*
    526 		 * First check the config space and/or
    527 		 * MSI capability register(s)
    528 		 */
    529 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
    530 			pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type,
    531 			    &pci_status);
    532 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
    533 			pci_rval = pci_intx_get_cap(rdip, &pci_status);
    534 
    535 		/* next check with pcplusmp */
    536 		if (psm_intr_ops != NULL)
    537 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
    538 			    PSM_INTR_OP_GET_CAP, &psm_status);
    539 
    540 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, "
    541 		    "psm_status = %x, pci_rval = %x, pci_status = %x\n",
    542 		    psm_rval, psm_status, pci_rval, pci_status));
    543 
    544 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
    545 			*(int *)result = 0;
    546 			return (DDI_FAILURE);
    547 		}
    548 
    549 		if (psm_rval == PSM_SUCCESS)
    550 			*(int *)result = psm_status;
    551 
    552 		if (pci_rval == DDI_SUCCESS)
    553 			*(int *)result |= pci_status;
    554 
    555 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n",
    556 		    *(int *)result));
    557 		break;
    558 	case DDI_INTROP_SETCAP:
    559 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
    560 		    "SETCAP cap=0x%x\n", *(int *)result));
    561 		if (psm_intr_ops == NULL)
    562 			return (DDI_FAILURE);
    563 
    564 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
    565 			DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
    566 			    " returned failure\n"));
    567 			return (DDI_FAILURE);
    568 		}
    569 		break;
    570 	case DDI_INTROP_ENABLE:
    571 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n"));
    572 		if (psm_intr_ops == NULL)
    573 			return (DDI_FAILURE);
    574 
    575 		if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) !=
    576 		    DDI_SUCCESS)
    577 			return (DDI_FAILURE);
    578 
    579 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE "
    580 		    "vector=0x%x\n", hdlp->ih_vector));
    581 		break;
    582 	case DDI_INTROP_DISABLE:
    583 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n"));
    584 		if (psm_intr_ops == NULL)
    585 			return (DDI_FAILURE);
    586 
    587 		pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
    588 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE "
    589 		    "vector = %x\n", hdlp->ih_vector));
    590 		break;
    591 	case DDI_INTROP_BLOCKENABLE:
    592 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
    593 		    "BLOCKENABLE\n"));
    594 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
    595 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n"));
    596 			return (DDI_FAILURE);
    597 		}
    598 
    599 		/* Check if psm_intr_ops is NULL? */
    600 		if (psm_intr_ops == NULL)
    601 			return (DDI_FAILURE);
    602 
    603 		count = hdlp->ih_scratch1;
    604 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
    605 		for (i = 0; i < count; i++) {
    606 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
    607 			if (pci_enable_intr(pdip, rdip, hdlp,
    608 			    hdlp->ih_inum) != DDI_SUCCESS) {
    609 				DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: "
    610 				    "pci_enable_intr failed for %d\n", i));
    611 				for (j = 0; j < i; j++) {
    612 					hdlp = (ddi_intr_handle_impl_t *)
    613 					    h_array[j];
    614 					pci_disable_intr(pdip, rdip, hdlp,
    615 					    hdlp->ih_inum);
    616 				}
    617 				return (DDI_FAILURE);
    618 			}
    619 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
    620 			    "BLOCKENABLE inum %x done\n", hdlp->ih_inum));
    621 		}
    622 		break;
    623 	case DDI_INTROP_BLOCKDISABLE:
    624 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
    625 		    "BLOCKDISABLE\n"));
    626 		if (hdlp->ih_type != DDI_INTR_TYPE_MSI) {
    627 			DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n"));
    628 			return (DDI_FAILURE);
    629 		}
    630 
    631 		/* Check if psm_intr_ops is present */
    632 		if (psm_intr_ops == NULL)
    633 			return (DDI_FAILURE);
    634 
    635 		count = hdlp->ih_scratch1;
    636 		h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2;
    637 		for (i = 0; i < count; i++) {
    638 			hdlp = (ddi_intr_handle_impl_t *)h_array[i];
    639 			pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum);
    640 			DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: "
    641 			    "BLOCKDISABLE inum %x done\n", hdlp->ih_inum));
    642 		}
    643 		break;
    644 	case DDI_INTROP_SETMASK:
    645 	case DDI_INTROP_CLRMASK:
    646 		/*
    647 		 * First handle in the config space
    648 		 */
    649 		if (intr_op == DDI_INTROP_SETMASK) {
    650 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
    651 				pci_status = pci_msi_set_mask(rdip,
    652 				    hdlp->ih_type, hdlp->ih_inum);
    653 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
    654 				pci_status = pci_intx_set_mask(rdip);
    655 		} else {
    656 			if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
    657 				pci_status = pci_msi_clr_mask(rdip,
    658 				    hdlp->ih_type, hdlp->ih_inum);
    659 			else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
    660 				pci_status = pci_intx_clr_mask(rdip);
    661 		}
    662 
    663 		/* For MSI/X; no need to check with pcplusmp */
    664 		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
    665 			return (pci_status);
    666 
    667 		/* For fixed interrupts only: handle config space first */
    668 		if (hdlp->ih_type == DDI_INTR_TYPE_FIXED &&
    669 		    pci_status == DDI_SUCCESS)
    670 			break;
    671 
    672 		/* For fixed interrupts only: confer with pcplusmp next */
    673 		if (psm_intr_ops != NULL) {
    674 			/* If interrupt is shared; do nothing */
    675 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
    676 			    PSM_INTR_OP_GET_SHARED, &psm_status);
    677 
    678 			if (psm_rval == PSM_FAILURE || psm_status == 1)
    679 				return (pci_status);
    680 
    681 			/* Now, pcplusmp should try to set/clear the mask */
    682 			if (intr_op == DDI_INTROP_SETMASK)
    683 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
    684 				    PSM_INTR_OP_SET_MASK, NULL);
    685 			else
    686 				psm_rval = (*psm_intr_ops)(rdip, hdlp,
    687 				    PSM_INTR_OP_CLEAR_MASK, NULL);
    688 		}
    689 		return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS);
    690 	case DDI_INTROP_GETPENDING:
    691 		/*
    692 		 * First check the config space and/or
    693 		 * MSI capability register(s)
    694 		 */
    695 		if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type))
    696 			pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type,
    697 			    hdlp->ih_inum, &pci_status);
    698 		else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED)
    699 			pci_rval = pci_intx_get_pending(rdip, &pci_status);
    700 
    701 		/* On failure; next try with pcplusmp */
    702 		if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL)
    703 			psm_rval = (*psm_intr_ops)(rdip, hdlp,
    704 			    PSM_INTR_OP_GET_PENDING, &psm_status);
    705 
    706 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned "
    707 		    "psm_rval = %x, psm_status = %x, pci_rval = %x, "
    708 		    "pci_status = %x\n", psm_rval, psm_status, pci_rval,
    709 		    pci_status));
    710 		if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) {
    711 			*(int *)result = 0;
    712 			return (DDI_FAILURE);
    713 		}
    714 
    715 		if (psm_rval != PSM_FAILURE)
    716 			*(int *)result = psm_status;
    717 		else if (pci_rval != DDI_FAILURE)
    718 			*(int *)result = pci_status;
    719 		DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n",
    720 		    *(int *)result));
    721 		break;
    722 	case DDI_INTROP_GETTARGET:
    723 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n"));
    724 
    725 		/* Note hdlp->ih_vector is actually an irq */
    726 		if ((rv = pci_get_cpu_from_vecirq(hdlp->ih_vector, IS_IRQ)) ==
    727 		    -1)
    728 			return (DDI_FAILURE);
    729 		*(int *)result = rv;
    730 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET "
    731 		    "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector, rv));
    732 		break;
    733 	case DDI_INTROP_SETTARGET:
    734 		DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n"));
    735 
    736 		/* hdlp->ih_vector is actually an irq */
    737 		tmp_hdl.ih_vector = hdlp->ih_vector;
    738 		tmp_hdl.ih_flags = PSMGI_INTRBY_IRQ;
    739 		tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result;
    740 		psm_rval = (*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU,
    741 		    &psm_status);
    742 
    743 		if (psm_rval != PSM_SUCCESS)
    744 			return (DDI_FAILURE);
    745 		break;
    746 	default:
    747 		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
    748 	}
    749 
    750 	return (DDI_SUCCESS);
    751 }
    752 
    753 int
    754 pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p,
    755     int vecirq, boolean_t is_irq)
    756 {
    757 	ddi_intr_handle_impl_t	get_info_ii_hdl;
    758 
    759 	if (is_irq)
    760 		intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ;
    761 
    762 	/*
    763 	 * For this locally-declared and used handle, ih_private will contain a
    764 	 * pointer to apic_get_intr_t, not an ihdl_plat_t as used for
    765 	 * global interrupt handling.
    766 	 */
    767 	get_info_ii_hdl.ih_private = intrinfo_p;
    768 	get_info_ii_hdl.ih_vector = (ushort_t)vecirq;
    769 
    770 	if ((*psm_intr_ops)(NULL, &get_info_ii_hdl,
    771 	    PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE)
    772 		return (DDI_FAILURE);
    773 
    774 	return (DDI_SUCCESS);
    775 }
    776 
    777 
    778 int
    779 pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq)
    780 {
    781 	int rval;
    782 
    783 	apic_get_intr_t	intrinfo;
    784 	intrinfo.avgi_req_flags = PSMGI_REQ_CPUID;
    785 	rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq);
    786 
    787 	if (rval == DDI_SUCCESS)
    788 		return (intrinfo.avgi_cpu_id);
    789 	else
    790 		return (-1);
    791 }
    792 
    793 
    794 static int
    795 pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip,
    796     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
    797 {
    798 	struct intrspec	*ispec;
    799 	int		irq;
    800 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
    801 
    802 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n",
    803 	    (void *)hdlp, inum));
    804 
    805 	/* Translate the interrupt if needed */
    806 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
    807 	if (ispec == NULL)
    808 		return (DDI_FAILURE);
    809 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
    810 		ispec->intrspec_vec = inum;
    811 		ispec->intrspec_pri = hdlp->ih_pri;
    812 	}
    813 	ihdl_plat_datap->ip_ispecp = ispec;
    814 
    815 	/* translate the interrupt if needed */
    816 	if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) ==
    817 	    PSM_FAILURE)
    818 		return (DDI_FAILURE);
    819 	DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n",
    820 	    hdlp->ih_pri, irq));
    821 
    822 	/* Add the interrupt handler */
    823 	if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
    824 	    DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1,
    825 	    hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip))
    826 		return (DDI_FAILURE);
    827 
    828 	/* Note this really is an irq. */
    829 	hdlp->ih_vector = (ushort_t)irq;
    830 
    831 	return (DDI_SUCCESS);
    832 }
    833 
    834 
    835 static void
    836 pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip,
    837     ddi_intr_handle_impl_t *hdlp, uint32_t inum)
    838 {
    839 	int		irq;
    840 	struct intrspec	*ispec;
    841 	ihdl_plat_t	*ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
    842 
    843 	DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n"));
    844 	ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum);
    845 	if (ispec == NULL)
    846 		return;
    847 	if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) {
    848 		ispec->intrspec_vec = inum;
    849 		ispec->intrspec_pri = hdlp->ih_pri;
    850 	}
    851 	ihdl_plat_datap->ip_ispecp = ispec;
    852 
    853 	/* translate the interrupt if needed */
    854 	(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq);
    855 
    856 	/* Disable the interrupt handler */
    857 	rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq);
    858 	ihdl_plat_datap->ip_ispecp = NULL;
    859 }
    860 
    861 /*
    862  * Miscellaneous library function
    863  */
    864 int
    865 pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp)
    866 {
    867 	int		i;
    868 	int 		number;
    869 	int		assigned_addr_len;
    870 	uint_t		phys_hi = pci_rp->pci_phys_hi;
    871 	pci_regspec_t	*assigned_addr;
    872 
    873 	if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) ||
    874 	    (phys_hi & PCI_RELOCAT_B))
    875 		return (DDI_SUCCESS);
    876 
    877 	/*
    878 	 * the "reg" property specifies relocatable, get and interpret the
    879 	 * "assigned-addresses" property.
    880 	 */
    881 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
    882 	    "assigned-addresses", (int **)&assigned_addr,
    883 	    (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS)
    884 		return (DDI_FAILURE);
    885 
    886 	/*
    887 	 * Scan the "assigned-addresses" for one that matches the specified
    888 	 * "reg" property entry.
    889 	 */
    890 	phys_hi &= PCI_CONF_ADDR_MASK;
    891 	number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int));
    892 	for (i = 0; i < number; i++) {
    893 		if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) ==
    894 		    phys_hi) {
    895 			pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid;
    896 			pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low;
    897 			ddi_prop_free(assigned_addr);
    898 			return (DDI_SUCCESS);
    899 		}
    900 	}
    901 
    902 	ddi_prop_free(assigned_addr);
    903 	return (DDI_FAILURE);
    904 }
    905 
    906 
    907 /*
    908  * To handle PCI tool ioctls
    909  */
    910 
    911 /*ARGSUSED*/
    912 int
    913 pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg,
    914     int mode, cred_t *credp, int *rvalp)
    915 {
    916 	minor_t	minor = getminor(dev);
    917 	int	rv = ENOTTY;
    918 
    919 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
    920 	case PCI_TOOL_REG_MINOR_NUM:
    921 
    922 		switch (cmd) {
    923 		case PCITOOL_DEVICE_SET_REG:
    924 		case PCITOOL_DEVICE_GET_REG:
    925 
    926 			/* Require full privileges. */
    927 			if (secpolicy_kmdb(credp))
    928 				rv = EPERM;
    929 			else
    930 				rv = pcitool_dev_reg_ops(dip, (void *)arg,
    931 				    cmd, mode);
    932 			break;
    933 
    934 		case PCITOOL_NEXUS_SET_REG:
    935 		case PCITOOL_NEXUS_GET_REG:
    936 
    937 			/* Require full privileges. */
    938 			if (secpolicy_kmdb(credp))
    939 				rv = EPERM;
    940 			else
    941 				rv = pcitool_bus_reg_ops(dip, (void *)arg,
    942 				    cmd, mode);
    943 			break;
    944 		}
    945 		break;
    946 
    947 	case PCI_TOOL_INTR_MINOR_NUM:
    948 
    949 		switch (cmd) {
    950 		case PCITOOL_DEVICE_SET_INTR:
    951 
    952 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
    953 			if (secpolicy_ponline(credp)) {
    954 				rv = EPERM;
    955 				break;
    956 			}
    957 
    958 		/*FALLTHRU*/
    959 		/* These require no special privileges. */
    960 		case PCITOOL_DEVICE_GET_INTR:
    961 		case PCITOOL_SYSTEM_INTR_INFO:
    962 			rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode);
    963 			break;
    964 		}
    965 		break;
    966 
    967 	default:
    968 		break;
    969 	}
    970 
    971 	return (rv);
    972 }
    973 
    974 
    975 int
    976 pci_common_ctlops_poke(peekpoke_ctlops_t *in_args)
    977 {
    978 	size_t size = in_args->size;
    979 	uintptr_t dev_addr = in_args->dev_addr;
    980 	uintptr_t host_addr = in_args->host_addr;
    981 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
    982 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
    983 	size_t repcount = in_args->repcount;
    984 	uint_t flags = in_args->flags;
    985 	int err = DDI_SUCCESS;
    986 
    987 	/*
    988 	 * if no handle then this is a poke. We have to return failure here
    989 	 * as we have no way of knowing whether this is a MEM or IO space access
    990 	 */
    991 	if (in_args->handle == NULL)
    992 		return (DDI_FAILURE);
    993 
    994 	/*
    995 	 * rest of this function is actually for cautious puts
    996 	 */
    997 	for (; repcount; repcount--) {
    998 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
    999 			switch (size) {
   1000 			case sizeof (uint8_t):
   1001 				pci_config_wr8(hp, (uint8_t *)dev_addr,
   1002 				    *(uint8_t *)host_addr);
   1003 				break;
   1004 			case sizeof (uint16_t):
   1005 				pci_config_wr16(hp, (uint16_t *)dev_addr,
   1006 				    *(uint16_t *)host_addr);
   1007 				break;
   1008 			case sizeof (uint32_t):
   1009 				pci_config_wr32(hp, (uint32_t *)dev_addr,
   1010 				    *(uint32_t *)host_addr);
   1011 				break;
   1012 			case sizeof (uint64_t):
   1013 				pci_config_wr64(hp, (uint64_t *)dev_addr,
   1014 				    *(uint64_t *)host_addr);
   1015 				break;
   1016 			default:
   1017 				err = DDI_FAILURE;
   1018 				break;
   1019 			}
   1020 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
   1021 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
   1022 			    DDI_STRUCTURE_BE_ACC) {
   1023 				switch (size) {
   1024 				case sizeof (uint8_t):
   1025 					i_ddi_io_put8(hp,
   1026 					    (uint8_t *)dev_addr,
   1027 					    *(uint8_t *)host_addr);
   1028 					break;
   1029 				case sizeof (uint16_t):
   1030 					i_ddi_io_swap_put16(hp,
   1031 					    (uint16_t *)dev_addr,
   1032 					    *(uint16_t *)host_addr);
   1033 					break;
   1034 				case sizeof (uint32_t):
   1035 					i_ddi_io_swap_put32(hp,
   1036 					    (uint32_t *)dev_addr,
   1037 					    *(uint32_t *)host_addr);
   1038 					break;
   1039 				/*
   1040 				 * note the 64-bit case is a dummy
   1041 				 * function - so no need to swap
   1042 				 */
   1043 				case sizeof (uint64_t):
   1044 					i_ddi_io_put64(hp,
   1045 					    (uint64_t *)dev_addr,
   1046 					    *(uint64_t *)host_addr);
   1047 					break;
   1048 				default:
   1049 					err = DDI_FAILURE;
   1050 					break;
   1051 				}
   1052 			} else {
   1053 				switch (size) {
   1054 				case sizeof (uint8_t):
   1055 					i_ddi_io_put8(hp,
   1056 					    (uint8_t *)dev_addr,
   1057 					    *(uint8_t *)host_addr);
   1058 					break;
   1059 				case sizeof (uint16_t):
   1060 					i_ddi_io_put16(hp,
   1061 					    (uint16_t *)dev_addr,
   1062 					    *(uint16_t *)host_addr);
   1063 					break;
   1064 				case sizeof (uint32_t):
   1065 					i_ddi_io_put32(hp,
   1066 					    (uint32_t *)dev_addr,
   1067 					    *(uint32_t *)host_addr);
   1068 					break;
   1069 				case sizeof (uint64_t):
   1070 					i_ddi_io_put64(hp,
   1071 					    (uint64_t *)dev_addr,
   1072 					    *(uint64_t *)host_addr);
   1073 					break;
   1074 				default:
   1075 					err = DDI_FAILURE;
   1076 					break;
   1077 				}
   1078 			}
   1079 		} else {
   1080 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
   1081 			    DDI_STRUCTURE_BE_ACC) {
   1082 				switch (size) {
   1083 				case sizeof (uint8_t):
   1084 					*(uint8_t *)dev_addr =
   1085 					    *(uint8_t *)host_addr;
   1086 					break;
   1087 				case sizeof (uint16_t):
   1088 					*(uint16_t *)dev_addr =
   1089 					    ddi_swap16(*(uint16_t *)host_addr);
   1090 					break;
   1091 				case sizeof (uint32_t):
   1092 					*(uint32_t *)dev_addr =
   1093 					    ddi_swap32(*(uint32_t *)host_addr);
   1094 					break;
   1095 				case sizeof (uint64_t):
   1096 					*(uint64_t *)dev_addr =
   1097 					    ddi_swap64(*(uint64_t *)host_addr);
   1098 					break;
   1099 				default:
   1100 					err = DDI_FAILURE;
   1101 					break;
   1102 				}
   1103 			} else {
   1104 				switch (size) {
   1105 				case sizeof (uint8_t):
   1106 					*(uint8_t *)dev_addr =
   1107 					    *(uint8_t *)host_addr;
   1108 					break;
   1109 				case sizeof (uint16_t):
   1110 					*(uint16_t *)dev_addr =
   1111 					    *(uint16_t *)host_addr;
   1112 					break;
   1113 				case sizeof (uint32_t):
   1114 					*(uint32_t *)dev_addr =
   1115 					    *(uint32_t *)host_addr;
   1116 					break;
   1117 				case sizeof (uint64_t):
   1118 					*(uint64_t *)dev_addr =
   1119 					    *(uint64_t *)host_addr;
   1120 					break;
   1121 				default:
   1122 					err = DDI_FAILURE;
   1123 					break;
   1124 				}
   1125 			}
   1126 		}
   1127 		host_addr += size;
   1128 		if (flags == DDI_DEV_AUTOINCR)
   1129 			dev_addr += size;
   1130 	}
   1131 	return (err);
   1132 }
   1133 
   1134 
   1135 int
   1136 pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len)
   1137 {
   1138 	ddi_acc_impl_t	*ap = (ddi_acc_impl_t *)hp->ah_platform_private;
   1139 
   1140 	/* endian-ness check */
   1141 	if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC)
   1142 		return (DDI_FAILURE);
   1143 
   1144 	/*
   1145 	 * range check
   1146 	 */
   1147 	if ((offset >= PCI_CONF_HDR_SIZE) ||
   1148 	    (len > PCI_CONF_HDR_SIZE) ||
   1149 	    (offset + len > PCI_CONF_HDR_SIZE))
   1150 		return (DDI_FAILURE);
   1151 
   1152 	ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE;
   1153 	/*
   1154 	 * always use cautious mechanism for config space gets
   1155 	 */
   1156 	ap->ahi_get8 = i_ddi_caut_get8;
   1157 	ap->ahi_get16 = i_ddi_caut_get16;
   1158 	ap->ahi_get32 = i_ddi_caut_get32;
   1159 	ap->ahi_get64 = i_ddi_caut_get64;
   1160 	ap->ahi_rep_get8 = i_ddi_caut_rep_get8;
   1161 	ap->ahi_rep_get16 = i_ddi_caut_rep_get16;
   1162 	ap->ahi_rep_get32 = i_ddi_caut_rep_get32;
   1163 	ap->ahi_rep_get64 = i_ddi_caut_rep_get64;
   1164 	if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) {
   1165 		ap->ahi_put8 = i_ddi_caut_put8;
   1166 		ap->ahi_put16 = i_ddi_caut_put16;
   1167 		ap->ahi_put32 = i_ddi_caut_put32;
   1168 		ap->ahi_put64 = i_ddi_caut_put64;
   1169 		ap->ahi_rep_put8 = i_ddi_caut_rep_put8;
   1170 		ap->ahi_rep_put16 = i_ddi_caut_rep_put16;
   1171 		ap->ahi_rep_put32 = i_ddi_caut_rep_put32;
   1172 		ap->ahi_rep_put64 = i_ddi_caut_rep_put64;
   1173 	} else {
   1174 		ap->ahi_put8 = pci_config_wr8;
   1175 		ap->ahi_put16 = pci_config_wr16;
   1176 		ap->ahi_put32 = pci_config_wr32;
   1177 		ap->ahi_put64 = pci_config_wr64;
   1178 		ap->ahi_rep_put8 = pci_config_rep_wr8;
   1179 		ap->ahi_rep_put16 = pci_config_rep_wr16;
   1180 		ap->ahi_rep_put32 = pci_config_rep_wr32;
   1181 		ap->ahi_rep_put64 = pci_config_rep_wr64;
   1182 	}
   1183 
   1184 	/* Initialize to default check/notify functions */
   1185 	ap->ahi_fault_check = i_ddi_acc_fault_check;
   1186 	ap->ahi_fault_notify = i_ddi_acc_fault_notify;
   1187 	ap->ahi_fault = 0;
   1188 	impl_acc_err_init(hp);
   1189 	return (DDI_SUCCESS);
   1190 }
   1191 
   1192 
   1193 int
   1194 pci_common_ctlops_peek(peekpoke_ctlops_t *in_args)
   1195 {
   1196 	size_t size = in_args->size;
   1197 	uintptr_t dev_addr = in_args->dev_addr;
   1198 	uintptr_t host_addr = in_args->host_addr;
   1199 	ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle;
   1200 	ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle;
   1201 	size_t repcount = in_args->repcount;
   1202 	uint_t flags = in_args->flags;
   1203 	int err = DDI_SUCCESS;
   1204 
   1205 	/*
   1206 	 * if no handle then this is a peek. We have to return failure here
   1207 	 * as we have no way of knowing whether this is a MEM or IO space access
   1208 	 */
   1209 	if (in_args->handle == NULL)
   1210 		return (DDI_FAILURE);
   1211 
   1212 	for (; repcount; repcount--) {
   1213 		if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) {
   1214 			switch (size) {
   1215 			case sizeof (uint8_t):
   1216 				*(uint8_t *)host_addr = pci_config_rd8(hp,
   1217 				    (uint8_t *)dev_addr);
   1218 				break;
   1219 			case sizeof (uint16_t):
   1220 				*(uint16_t *)host_addr = pci_config_rd16(hp,
   1221 				    (uint16_t *)dev_addr);
   1222 				break;
   1223 			case sizeof (uint32_t):
   1224 				*(uint32_t *)host_addr = pci_config_rd32(hp,
   1225 				    (uint32_t *)dev_addr);
   1226 				break;
   1227 			case sizeof (uint64_t):
   1228 				*(uint64_t *)host_addr = pci_config_rd64(hp,
   1229 				    (uint64_t *)dev_addr);
   1230 				break;
   1231 			default:
   1232 				err = DDI_FAILURE;
   1233 				break;
   1234 			}
   1235 		} else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) {
   1236 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
   1237 			    DDI_STRUCTURE_BE_ACC) {
   1238 				switch (size) {
   1239 				case sizeof (uint8_t):
   1240 					*(uint8_t *)host_addr =
   1241 					    i_ddi_io_get8(hp,
   1242 					    (uint8_t *)dev_addr);
   1243 					break;
   1244 				case sizeof (uint16_t):
   1245 					*(uint16_t *)host_addr =
   1246 					    i_ddi_io_swap_get16(hp,
   1247 					    (uint16_t *)dev_addr);
   1248 					break;
   1249 				case sizeof (uint32_t):
   1250 					*(uint32_t *)host_addr =
   1251 					    i_ddi_io_swap_get32(hp,
   1252 					    (uint32_t *)dev_addr);
   1253 					break;
   1254 				/*
   1255 				 * note the 64-bit case is a dummy
   1256 				 * function - so no need to swap
   1257 				 */
   1258 				case sizeof (uint64_t):
   1259 					*(uint64_t *)host_addr =
   1260 					    i_ddi_io_get64(hp,
   1261 					    (uint64_t *)dev_addr);
   1262 					break;
   1263 				default:
   1264 					err = DDI_FAILURE;
   1265 					break;
   1266 				}
   1267 			} else {
   1268 				switch (size) {
   1269 				case sizeof (uint8_t):
   1270 					*(uint8_t *)host_addr =
   1271 					    i_ddi_io_get8(hp,
   1272 					    (uint8_t *)dev_addr);
   1273 					break;
   1274 				case sizeof (uint16_t):
   1275 					*(uint16_t *)host_addr =
   1276 					    i_ddi_io_get16(hp,
   1277 					    (uint16_t *)dev_addr);
   1278 					break;
   1279 				case sizeof (uint32_t):
   1280 					*(uint32_t *)host_addr =
   1281 					    i_ddi_io_get32(hp,
   1282 					    (uint32_t *)dev_addr);
   1283 					break;
   1284 				case sizeof (uint64_t):
   1285 					*(uint64_t *)host_addr =
   1286 					    i_ddi_io_get64(hp,
   1287 					    (uint64_t *)dev_addr);
   1288 					break;
   1289 				default:
   1290 					err = DDI_FAILURE;
   1291 					break;
   1292 				}
   1293 			}
   1294 		} else {
   1295 			if (hdlp->ah_acc.devacc_attr_endian_flags ==
   1296 			    DDI_STRUCTURE_BE_ACC) {
   1297 				switch (in_args->size) {
   1298 				case sizeof (uint8_t):
   1299 					*(uint8_t *)host_addr =
   1300 					    *(uint8_t *)dev_addr;
   1301 					break;
   1302 				case sizeof (uint16_t):
   1303 					*(uint16_t *)host_addr =
   1304 					    ddi_swap16(*(uint16_t *)dev_addr);
   1305 					break;
   1306 				case sizeof (uint32_t):
   1307 					*(uint32_t *)host_addr =
   1308 					    ddi_swap32(*(uint32_t *)dev_addr);
   1309 					break;
   1310 				case sizeof (uint64_t):
   1311 					*(uint64_t *)host_addr =
   1312 					    ddi_swap64(*(uint64_t *)dev_addr);
   1313 					break;
   1314 				default:
   1315 					err = DDI_FAILURE;
   1316 					break;
   1317 				}
   1318 			} else {
   1319 				switch (in_args->size) {
   1320 				case sizeof (uint8_t):
   1321 					*(uint8_t *)host_addr =
   1322 					    *(uint8_t *)dev_addr;
   1323 					break;
   1324 				case sizeof (uint16_t):
   1325 					*(uint16_t *)host_addr =
   1326 					    *(uint16_t *)dev_addr;
   1327 					break;
   1328 				case sizeof (uint32_t):
   1329 					*(uint32_t *)host_addr =
   1330 					    *(uint32_t *)dev_addr;
   1331 					break;
   1332 				case sizeof (uint64_t):
   1333 					*(uint64_t *)host_addr =
   1334 					    *(uint64_t *)dev_addr;
   1335 					break;
   1336 				default:
   1337 					err = DDI_FAILURE;
   1338 					break;
   1339 				}
   1340 			}
   1341 		}
   1342 		host_addr += size;
   1343 		if (flags == DDI_DEV_AUTOINCR)
   1344 			dev_addr += size;
   1345 	}
   1346 	return (err);
   1347 }
   1348 
   1349 /*ARGSUSED*/
   1350 int
   1351 pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip,
   1352 	ddi_ctl_enum_t ctlop, void *arg, void *result)
   1353 {
   1354 	if (ctlop == DDI_CTLOPS_PEEK)
   1355 		return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg));
   1356 	else
   1357 		return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg));
   1358 }
   1359 
   1360 /*
   1361  * These are the get and put functions to be shared with drivers. The
   1362  * mutex locking is done inside the functions referenced, rather than
   1363  * here, and is thus shared across PCI child drivers and any other
   1364  * consumers of PCI config space (such as the ACPI subsystem).
   1365  *
   1366  * The configuration space addresses come in as pointers.  This is fine on
   1367  * a 32-bit system, where the VM space and configuration space are the same
   1368  * size.  It's not such a good idea on a 64-bit system, where memory
   1369  * addresses are twice as large as configuration space addresses.  At some
   1370  * point in the call tree we need to take a stand and say "you are 32-bit
   1371  * from this time forth", and this seems like a nice self-contained place.
   1372  */
   1373 
   1374 uint8_t
   1375 pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr)
   1376 {
   1377 	pci_acc_cfblk_t *cfp;
   1378 	uint8_t	rval;
   1379 	int reg;
   1380 
   1381 	ASSERT64(((uintptr_t)addr >> 32) == 0);
   1382 
   1383 	reg = (int)(uintptr_t)addr;
   1384 
   1385 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
   1386 
   1387 	rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
   1388 	    reg);
   1389 
   1390 	return (rval);
   1391 }
   1392 
   1393 void
   1394 pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
   1395 	uint8_t *dev_addr, size_t repcount, uint_t flags)
   1396 {
   1397 	uint8_t *h, *d;
   1398 
   1399 	h = host_addr;
   1400 	d = dev_addr;
   1401 
   1402 	if (flags == DDI_DEV_AUTOINCR)
   1403 		for (; repcount; repcount--)
   1404 			*h++ = pci_config_rd8(hdlp, d++);
   1405 	else
   1406 		for (; repcount; repcount--)
   1407 			*h++ = pci_config_rd8(hdlp, d);
   1408 }
   1409 
   1410 uint16_t
   1411 pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr)
   1412 {
   1413 	pci_acc_cfblk_t *cfp;
   1414 	uint16_t rval;
   1415 	int reg;
   1416 
   1417 	ASSERT64(((uintptr_t)addr >> 32) == 0);
   1418 
   1419 	reg = (int)(uintptr_t)addr;
   1420 
   1421 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
   1422 
   1423 	rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum,
   1424 	    reg);
   1425 
   1426 	return (rval);
   1427 }
   1428 
   1429 void
   1430 pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
   1431 	uint16_t *dev_addr, size_t repcount, uint_t flags)
   1432 {
   1433 	uint16_t *h, *d;
   1434 
   1435 	h = host_addr;
   1436 	d = dev_addr;
   1437 
   1438 	if (flags == DDI_DEV_AUTOINCR)
   1439 		for (; repcount; repcount--)
   1440 			*h++ = pci_config_rd16(hdlp, d++);
   1441 	else
   1442 		for (; repcount; repcount--)
   1443 			*h++ = pci_config_rd16(hdlp, d);
   1444 }
   1445 
   1446 uint32_t
   1447 pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr)
   1448 {
   1449 	pci_acc_cfblk_t *cfp;
   1450 	uint32_t rval;
   1451 	int reg;
   1452 
   1453 	ASSERT64(((uintptr_t)addr >> 32) == 0);
   1454 
   1455 	reg = (int)(uintptr_t)addr;
   1456 
   1457 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
   1458 
   1459 	rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum,
   1460 	    cfp->c_funcnum, reg);
   1461 
   1462 	return (rval);
   1463 }
   1464 
   1465 void
   1466 pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
   1467 	uint32_t *dev_addr, size_t repcount, uint_t flags)
   1468 {
   1469 	uint32_t *h, *d;
   1470 
   1471 	h = host_addr;
   1472 	d = dev_addr;
   1473 
   1474 	if (flags == DDI_DEV_AUTOINCR)
   1475 		for (; repcount; repcount--)
   1476 			*h++ = pci_config_rd32(hdlp, d++);
   1477 	else
   1478 		for (; repcount; repcount--)
   1479 			*h++ = pci_config_rd32(hdlp, d);
   1480 }
   1481 
   1482 
   1483 void
   1484 pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
   1485 {
   1486 	pci_acc_cfblk_t *cfp;
   1487 	int reg;
   1488 
   1489 	ASSERT64(((uintptr_t)addr >> 32) == 0);
   1490 
   1491 	reg = (int)(uintptr_t)addr;
   1492 
   1493 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
   1494 
   1495 	(*pci_putb_func)(cfp->c_busnum, cfp->c_devnum,
   1496 	    cfp->c_funcnum, reg, value);
   1497 }
   1498 
   1499 void
   1500 pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr,
   1501 	uint8_t *dev_addr, size_t repcount, uint_t flags)
   1502 {
   1503 	uint8_t *h, *d;
   1504 
   1505 	h = host_addr;
   1506 	d = dev_addr;
   1507 
   1508 	if (flags == DDI_DEV_AUTOINCR)
   1509 		for (; repcount; repcount--)
   1510 			pci_config_wr8(hdlp, d++, *h++);
   1511 	else
   1512 		for (; repcount; repcount--)
   1513 			pci_config_wr8(hdlp, d, *h++);
   1514 }
   1515 
   1516 void
   1517 pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
   1518 {
   1519 	pci_acc_cfblk_t *cfp;
   1520 	int reg;
   1521 
   1522 	ASSERT64(((uintptr_t)addr >> 32) == 0);
   1523 
   1524 	reg = (int)(uintptr_t)addr;
   1525 
   1526 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
   1527 
   1528 	(*pci_putw_func)(cfp->c_busnum, cfp->c_devnum,
   1529 	    cfp->c_funcnum, reg, value);
   1530 }
   1531 
   1532 void
   1533 pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr,
   1534 	uint16_t *dev_addr, size_t repcount, uint_t flags)
   1535 {
   1536 	uint16_t *h, *d;
   1537 
   1538 	h = host_addr;
   1539 	d = dev_addr;
   1540 
   1541 	if (flags == DDI_DEV_AUTOINCR)
   1542 		for (; repcount; repcount--)
   1543 			pci_config_wr16(hdlp, d++, *h++);
   1544 	else
   1545 		for (; repcount; repcount--)
   1546 			pci_config_wr16(hdlp, d, *h++);
   1547 }
   1548 
   1549 void
   1550 pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value)
   1551 {
   1552 	pci_acc_cfblk_t *cfp;
   1553 	int reg;
   1554 
   1555 	ASSERT64(((uintptr_t)addr >> 32) == 0);
   1556 
   1557 	reg = (int)(uintptr_t)addr;
   1558 
   1559 	cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private;
   1560 
   1561 	(*pci_putl_func)(cfp->c_busnum, cfp->c_devnum,
   1562 	    cfp->c_funcnum, reg, value);
   1563 }
   1564 
   1565 void
   1566 pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr,
   1567 	uint32_t *dev_addr, size_t repcount, uint_t flags)
   1568 {
   1569 	uint32_t *h, *d;
   1570 
   1571 	h = host_addr;
   1572 	d = dev_addr;
   1573 
   1574 	if (flags == DDI_DEV_AUTOINCR)
   1575 		for (; repcount; repcount--)
   1576 			pci_config_wr32(hdlp, d++, *h++);
   1577 	else
   1578 		for (; repcount; repcount--)
   1579 			pci_config_wr32(hdlp, d, *h++);
   1580 }
   1581 
   1582 uint64_t
   1583 pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr)
   1584 {
   1585 	uint32_t lw_val;
   1586 	uint32_t hi_val;
   1587 	uint32_t *dp;
   1588 	uint64_t val;
   1589 
   1590 	dp = (uint32_t *)addr;
   1591 	lw_val = pci_config_rd32(hdlp, dp);
   1592 	dp++;
   1593 	hi_val = pci_config_rd32(hdlp, dp);
   1594 	val = ((uint64_t)hi_val << 32) | lw_val;
   1595 	return (val);
   1596 }
   1597 
   1598 void
   1599 pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value)
   1600 {
   1601 	uint32_t lw_val;
   1602 	uint32_t hi_val;
   1603 	uint32_t *dp;
   1604 
   1605 	dp = (uint32_t *)addr;
   1606 	lw_val = (uint32_t)(value & 0xffffffff);
   1607 	hi_val = (uint32_t)(value >> 32);
   1608 	pci_config_wr32(hdlp, dp, lw_val);
   1609 	dp++;
   1610 	pci_config_wr32(hdlp, dp, hi_val);
   1611 }
   1612 
   1613 void
   1614 pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
   1615 	uint64_t *dev_addr, size_t repcount, uint_t flags)
   1616 {
   1617 	if (flags == DDI_DEV_AUTOINCR) {
   1618 		for (; repcount; repcount--)
   1619 			*host_addr++ = pci_config_rd64(hdlp, dev_addr++);
   1620 	} else {
   1621 		for (; repcount; repcount--)
   1622 			*host_addr++ = pci_config_rd64(hdlp, dev_addr);
   1623 	}
   1624 }
   1625 
   1626 void
   1627 pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr,
   1628 	uint64_t *dev_addr, size_t repcount, uint_t flags)
   1629 {
   1630 	if (flags == DDI_DEV_AUTOINCR) {
   1631 		for (; repcount; repcount--)
   1632 			pci_config_wr64(hdlp, host_addr++, *dev_addr++);
   1633 	} else {
   1634 		for (; repcount; repcount--)
   1635 			pci_config_wr64(hdlp, host_addr++, *dev_addr);
   1636 	}
   1637 }
   1638