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