1881Sjohnny /* 2881Sjohnny * CDDL HEADER START 3881Sjohnny * 4881Sjohnny * The contents of this file are subject to the terms of the 51542Sjohnny * Common Development and Distribution License (the "License"). 61542Sjohnny * You may not use this file except in compliance with the License. 7881Sjohnny * 8881Sjohnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9881Sjohnny * or http://www.opensolaris.org/os/licensing. 10881Sjohnny * See the License for the specific language governing permissions 11881Sjohnny * and limitations under the License. 12881Sjohnny * 13881Sjohnny * When distributing Covered Code, include this CDDL HEADER in each 14881Sjohnny * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15881Sjohnny * If applicable, add the following below this CDDL HEADER, with the 16881Sjohnny * fields enclosed by brackets "[]" replaced with your own identifying 17881Sjohnny * information: Portions Copyright [yyyy] [name of copyright owner] 18881Sjohnny * 19881Sjohnny * CDDL HEADER END 20881Sjohnny */ 21881Sjohnny 22881Sjohnny /* 23*11465SKerry.Shu@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24881Sjohnny * Use is subject to license terms. 25881Sjohnny */ 26881Sjohnny 27881Sjohnny /* 28881Sjohnny * File that has code which is common between pci(7d) and npe(7d) 29881Sjohnny * It shares the following: 30881Sjohnny * - interrupt code 31881Sjohnny * - pci_tools ioctl code 32881Sjohnny * - name_child code 33881Sjohnny * - set_parent_private_data code 34881Sjohnny */ 35881Sjohnny 36881Sjohnny #include <sys/conf.h> 37881Sjohnny #include <sys/pci.h> 38881Sjohnny #include <sys/sunndi.h> 39916Sschwartz #include <sys/mach_intr.h> 40881Sjohnny #include <sys/pci_intr_lib.h> 41881Sjohnny #include <sys/psm.h> 42881Sjohnny #include <sys/policy.h> 43881Sjohnny #include <sys/sysmacros.h> 44916Sschwartz #include <sys/clock.h> 453446Smrj #include <sys/apic.h> 46881Sjohnny #include <sys/pci_tools.h> 47881Sjohnny #include <io/pci/pci_var.h> 48881Sjohnny #include <io/pci/pci_tools_ext.h> 49881Sjohnny #include <io/pci/pci_common.h> 501083Sanish #include <sys/pci_cfgspace.h> 511083Sanish #include <sys/pci_impl.h> 524160Sjveta #include <sys/pci_cap.h> 53881Sjohnny 54881Sjohnny /* 55881Sjohnny * Function prototypes 56881Sjohnny */ 57881Sjohnny static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *); 58881Sjohnny static int pci_enable_intr(dev_info_t *, dev_info_t *, 59881Sjohnny ddi_intr_handle_impl_t *, uint32_t); 60881Sjohnny static void pci_disable_intr(dev_info_t *, dev_info_t *, 61881Sjohnny ddi_intr_handle_impl_t *, uint32_t); 62881Sjohnny 63881Sjohnny /* Extern decalration for pcplusmp module */ 64881Sjohnny extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 65881Sjohnny psm_intr_op_t, int *); 66881Sjohnny 67881Sjohnny /* 68881Sjohnny * pci_name_child: 69881Sjohnny * 70881Sjohnny * Assign the address portion of the node name 71881Sjohnny */ 72881Sjohnny int 73881Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen) 74881Sjohnny { 75881Sjohnny int dev, func, length; 76881Sjohnny char **unit_addr; 77881Sjohnny uint_t n; 78881Sjohnny pci_regspec_t *pci_rp; 79881Sjohnny 80881Sjohnny if (ndi_dev_is_persistent_node(child) == 0) { 81881Sjohnny /* 82881Sjohnny * For .conf node, use "unit-address" property 83881Sjohnny */ 84881Sjohnny if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 85881Sjohnny DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 86881Sjohnny DDI_PROP_SUCCESS) { 87881Sjohnny cmn_err(CE_WARN, "cannot find unit-address in %s.conf", 88881Sjohnny ddi_get_name(child)); 89881Sjohnny return (DDI_FAILURE); 90881Sjohnny } 91881Sjohnny if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 92881Sjohnny cmn_err(CE_WARN, "unit-address property in %s.conf" 93881Sjohnny " not well-formed", ddi_get_name(child)); 94881Sjohnny ddi_prop_free(unit_addr); 95881Sjohnny return (DDI_FAILURE); 96881Sjohnny } 97881Sjohnny (void) snprintf(name, namelen, "%s", *unit_addr); 98881Sjohnny ddi_prop_free(unit_addr); 99881Sjohnny return (DDI_SUCCESS); 100881Sjohnny } 101881Sjohnny 102881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 103881Sjohnny "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) { 104881Sjohnny cmn_err(CE_WARN, "cannot find reg property in %s", 105881Sjohnny ddi_get_name(child)); 106881Sjohnny return (DDI_FAILURE); 107881Sjohnny } 108881Sjohnny 109881Sjohnny /* copy the device identifications */ 110881Sjohnny dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 111881Sjohnny func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 112881Sjohnny 113881Sjohnny /* 114881Sjohnny * free the memory allocated by ddi_prop_lookup_int_array 115881Sjohnny */ 116881Sjohnny ddi_prop_free(pci_rp); 117881Sjohnny 118881Sjohnny if (func != 0) { 119881Sjohnny (void) snprintf(name, namelen, "%x,%x", dev, func); 120881Sjohnny } else { 121881Sjohnny (void) snprintf(name, namelen, "%x", dev); 122881Sjohnny } 123881Sjohnny 124881Sjohnny return (DDI_SUCCESS); 125881Sjohnny } 126881Sjohnny 127881Sjohnny /* 128881Sjohnny * Interrupt related code: 129881Sjohnny * 130881Sjohnny * The following busop is common to npe and pci drivers 131881Sjohnny * bus_introp 132881Sjohnny */ 133881Sjohnny 134881Sjohnny /* 135881Sjohnny * Create the ddi_parent_private_data for a pseudo child. 136881Sjohnny */ 137881Sjohnny void 138881Sjohnny pci_common_set_parent_private_data(dev_info_t *dip) 139881Sjohnny { 140881Sjohnny struct ddi_parent_private_data *pdptr; 141881Sjohnny 142881Sjohnny pdptr = (struct ddi_parent_private_data *)kmem_zalloc( 143881Sjohnny (sizeof (struct ddi_parent_private_data) + 1444397Sschwartz sizeof (struct intrspec)), KM_SLEEP); 145881Sjohnny pdptr->par_intr = (struct intrspec *)(pdptr + 1); 146881Sjohnny pdptr->par_nintr = 1; 147881Sjohnny ddi_set_parent_data(dip, pdptr); 148881Sjohnny } 149881Sjohnny 150881Sjohnny /* 151881Sjohnny * pci_get_priority: 152881Sjohnny * Figure out the priority of the device 153881Sjohnny */ 154881Sjohnny static int 155881Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri) 156881Sjohnny { 157881Sjohnny struct intrspec *ispec; 158881Sjohnny 159881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n", 160881Sjohnny (void *)dip, (void *)hdlp)); 161881Sjohnny 162881Sjohnny if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 163881Sjohnny hdlp->ih_inum)) == NULL) { 164881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 1658535Sevan.yan@sun.com *pri = pci_class_to_pil(dip); 166881Sjohnny pci_common_set_parent_private_data(hdlp->ih_dip); 167881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 168881Sjohnny hdlp->ih_inum); 169881Sjohnny return (DDI_SUCCESS); 170881Sjohnny } 171881Sjohnny return (DDI_FAILURE); 172881Sjohnny } 173881Sjohnny 174881Sjohnny *pri = ispec->intrspec_pri; 175881Sjohnny return (DDI_SUCCESS); 176881Sjohnny } 177881Sjohnny 178881Sjohnny 179881Sjohnny 18010187SKrishna.Elango@Sun.COM static int pcieb_intr_pri_counter = 0; 181881Sjohnny 182881Sjohnny /* 183881Sjohnny * pci_common_intr_ops: bus_intr_op() function for interrupt support 184881Sjohnny */ 185881Sjohnny int 186881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 187881Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 188881Sjohnny { 189881Sjohnny int priority = 0; 190881Sjohnny int psm_status = 0; 191881Sjohnny int pci_status = 0; 192881Sjohnny int pci_rval, psm_rval = PSM_FAILURE; 193881Sjohnny int types = 0; 194881Sjohnny int pciepci = 0; 1951542Sjohnny int i, j, count; 1964160Sjveta int rv; 197881Sjohnny int behavior; 1981997Sanish int cap_ptr; 1994160Sjveta uint16_t msi_cap_base, msix_cap_base, cap_ctrl; 2004160Sjveta char *prop; 201881Sjohnny ddi_intrspec_t isp; 202881Sjohnny struct intrspec *ispec; 203881Sjohnny ddi_intr_handle_impl_t tmp_hdl; 204881Sjohnny ddi_intr_msix_t *msix_p; 2051087Sschwartz ihdl_plat_t *ihdl_plat_datap; 2061542Sjohnny ddi_intr_handle_t *h_array; 2071997Sanish ddi_acc_handle_t handle; 208881Sjohnny 209881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 210881Sjohnny "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 211881Sjohnny (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 212881Sjohnny 213881Sjohnny /* Process the request */ 214881Sjohnny switch (intr_op) { 215881Sjohnny case DDI_INTROP_SUPPORTED_TYPES: 2164160Sjveta /* 2174160Sjveta * First we determine the interrupt types supported by the 2184160Sjveta * device itself, then we filter them through what the OS 2194160Sjveta * and system supports. We determine system-level 2204160Sjveta * interrupt type support for anything other than fixed intrs 2214160Sjveta * through the psm_intr_ops vector 2224160Sjveta */ 2234160Sjveta rv = DDI_FAILURE; 2244160Sjveta 225881Sjohnny /* Fixed supported by default */ 2264160Sjveta types = DDI_INTR_TYPE_FIXED; 2274160Sjveta 2284160Sjveta if (psm_intr_ops == NULL) { 2294160Sjveta *(int *)result = types; 2304160Sjveta return (DDI_SUCCESS); 2314160Sjveta } 2324160Sjveta if (pci_config_setup(rdip, &handle) != DDI_SUCCESS) 2334160Sjveta return (DDI_FAILURE); 234881Sjohnny 2354160Sjveta /* Sanity test cap control values if found */ 2364160Sjveta 2374160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) == 2384160Sjveta DDI_SUCCESS) { 2394160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base, 2404160Sjveta PCI_MSI_CTRL); 2414160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 2424160Sjveta goto SUPPORTED_TYPES_OUT; 2434160Sjveta 2444160Sjveta types |= DDI_INTR_TYPE_MSI; 2454160Sjveta } 2464160Sjveta 2474160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) == 2484160Sjveta DDI_SUCCESS) { 2494160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base, 2504160Sjveta PCI_MSIX_CTRL); 2514160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 2524160Sjveta goto SUPPORTED_TYPES_OUT; 253881Sjohnny 2544160Sjveta types |= DDI_INTR_TYPE_MSIX; 2554160Sjveta } 2564160Sjveta 2574160Sjveta /* 2584160Sjveta * Filter device-level types through system-level support 2594160Sjveta */ 2604160Sjveta tmp_hdl.ih_type = types; 2614160Sjveta if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI, 2624160Sjveta &types) != PSM_SUCCESS) 2634160Sjveta goto SUPPORTED_TYPES_OUT; 2644160Sjveta 2654160Sjveta DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 2664160Sjveta "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, 2674160Sjveta *(int *)result)); 268881Sjohnny 2694160Sjveta /* 2704160Sjveta * Export any MSI/MSI-X cap locations via properties 2714160Sjveta */ 2724160Sjveta if (types & DDI_INTR_TYPE_MSI) { 2734160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 2744160Sjveta "pci-msi-capid-pointer", (int)msi_cap_base) != 2754160Sjveta DDI_PROP_SUCCESS) 2764160Sjveta goto SUPPORTED_TYPES_OUT; 277881Sjohnny } 2784160Sjveta if (types & DDI_INTR_TYPE_MSIX) { 2794160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 2804160Sjveta "pci-msix-capid-pointer", (int)msix_cap_base) != 2814160Sjveta DDI_PROP_SUCCESS) 2824160Sjveta goto SUPPORTED_TYPES_OUT; 2834160Sjveta } 2844160Sjveta 2854160Sjveta rv = DDI_SUCCESS; 2864160Sjveta 2874160Sjveta SUPPORTED_TYPES_OUT: 2884160Sjveta *(int *)result = types; 2894160Sjveta pci_config_teardown(&handle); 2904160Sjveta return (rv); 2914160Sjveta 2922580Sanish case DDI_INTROP_NAVAIL: 293881Sjohnny case DDI_INTROP_NINTRS: 2942580Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 2952580Sanish if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type, 2962580Sanish result) != DDI_SUCCESS) 2972580Sanish return (DDI_FAILURE); 2982580Sanish } else { 2992580Sanish *(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip); 3002580Sanish if (*(int *)result == 0) 3012580Sanish return (DDI_FAILURE); 3022580Sanish } 303881Sjohnny break; 304881Sjohnny case DDI_INTROP_ALLOC: 305881Sjohnny /* 306881Sjohnny * MSI or MSIX (figure out number of vectors available) 307881Sjohnny * FIXED interrupts: just return available interrupts 308881Sjohnny */ 309881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 310881Sjohnny (psm_intr_ops != NULL) && 311881Sjohnny (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) { 312881Sjohnny /* 31310187SKrishna.Elango@Sun.COM * Following check is a special case for 'pcieb'. 314881Sjohnny * This makes sure vectors with the right priority 31510187SKrishna.Elango@Sun.COM * are allocated for pcieb during ALLOC time. 316881Sjohnny */ 31710187SKrishna.Elango@Sun.COM if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) { 318881Sjohnny hdlp->ih_pri = 31910187SKrishna.Elango@Sun.COM (pcieb_intr_pri_counter % 2) ? 4 : 7; 320881Sjohnny pciepci = 1; 321881Sjohnny } else 322881Sjohnny hdlp->ih_pri = priority; 3231717Swesolows behavior = (int)(uintptr_t)hdlp->ih_scratch2; 3241997Sanish 3251997Sanish /* 3261997Sanish * Cache in the config handle and cap_ptr 3271997Sanish */ 3281997Sanish if (i_ddi_get_pci_config_handle(rdip) == NULL) { 3291997Sanish if (pci_config_setup(rdip, &handle) != 3301997Sanish DDI_SUCCESS) 3311997Sanish return (DDI_FAILURE); 3321997Sanish i_ddi_set_pci_config_handle(rdip, handle); 3331997Sanish } 3341997Sanish 3354160Sjveta prop = NULL; 3364160Sjveta cap_ptr = 0; 3374160Sjveta if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 3384160Sjveta prop = "pci-msi-capid-pointer"; 3394160Sjveta else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) 3404160Sjveta prop = "pci-msix-capid-pointer"; 3411997Sanish 3424160Sjveta /* 3434160Sjveta * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES 3444160Sjveta * for MSI(X) before allocation 3454160Sjveta */ 3464160Sjveta if (prop != NULL) { 3471997Sanish cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 3484160Sjveta DDI_PROP_DONTPASS, prop, 0); 3494160Sjveta if (cap_ptr == 0) { 3504160Sjveta DDI_INTR_NEXDBG((CE_CONT, 3514160Sjveta "pci_common_intr_ops: rdip: 0x%p " 3524160Sjveta "attempted MSI(X) alloc without " 3534160Sjveta "cap property\n", (void *)rdip)); 3544160Sjveta return (DDI_FAILURE); 3554160Sjveta } 3561997Sanish } 3574160Sjveta i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); 3581997Sanish 3594160Sjveta /* 3604160Sjveta * Allocate interrupt vectors 3614160Sjveta */ 362881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 363881Sjohnny PSM_INTR_OP_ALLOC_VECTORS, result); 364881Sjohnny 3653112Sanish if (*(int *)result == 0) 3663112Sanish return (DDI_INTR_NOTFOUND); 3673112Sanish 368881Sjohnny /* verify behavior flag and take appropriate action */ 369881Sjohnny if ((behavior == DDI_INTR_ALLOC_STRICT) && 370881Sjohnny (*(int *)result < hdlp->ih_scratch1)) { 371881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 372881Sjohnny "pci_common_intr_ops: behavior %x, " 373881Sjohnny "couldn't get enough intrs\n", behavior)); 374881Sjohnny hdlp->ih_scratch1 = *(int *)result; 375881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 376881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 377881Sjohnny return (DDI_EAGAIN); 378881Sjohnny } 379881Sjohnny 380881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 381881Sjohnny if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 382881Sjohnny msix_p = pci_msix_init(hdlp->ih_dip); 38310647SLipeng.Sang@Sun.COM if (msix_p) { 384881Sjohnny i_ddi_set_msix(hdlp->ih_dip, 385881Sjohnny msix_p); 38610647SLipeng.Sang@Sun.COM } else { 38710647SLipeng.Sang@Sun.COM DDI_INTR_NEXDBG((CE_CONT, 38810647SLipeng.Sang@Sun.COM "pci_common_intr_ops: MSI-X" 38910647SLipeng.Sang@Sun.COM "table initilization failed" 39010647SLipeng.Sang@Sun.COM ", rdip 0x%p inum 0x%x\n", 39110647SLipeng.Sang@Sun.COM (void *)rdip, 39210647SLipeng.Sang@Sun.COM hdlp->ih_inum)); 39310647SLipeng.Sang@Sun.COM 39410647SLipeng.Sang@Sun.COM (void) (*psm_intr_ops)(rdip, 39510647SLipeng.Sang@Sun.COM hdlp, 39610647SLipeng.Sang@Sun.COM PSM_INTR_OP_FREE_VECTORS, 39710647SLipeng.Sang@Sun.COM NULL); 39810647SLipeng.Sang@Sun.COM 39910647SLipeng.Sang@Sun.COM return (DDI_FAILURE); 40010647SLipeng.Sang@Sun.COM } 401881Sjohnny } 402881Sjohnny } 403881Sjohnny 404881Sjohnny if (pciepci) { 405881Sjohnny /* update priority in ispec */ 406881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, 4074397Sschwartz (int)hdlp->ih_inum); 408881Sjohnny ispec = (struct intrspec *)isp; 409881Sjohnny if (ispec) 410881Sjohnny ispec->intrspec_pri = hdlp->ih_pri; 41110187SKrishna.Elango@Sun.COM ++pcieb_intr_pri_counter; 412881Sjohnny } 413881Sjohnny 414881Sjohnny } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 415881Sjohnny /* Figure out if this device supports MASKING */ 416881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 417881Sjohnny if (pci_rval == DDI_SUCCESS && pci_status) 418881Sjohnny hdlp->ih_cap |= pci_status; 419881Sjohnny *(int *)result = 1; /* DDI_INTR_TYPE_FIXED */ 420881Sjohnny } else 421881Sjohnny return (DDI_FAILURE); 422881Sjohnny break; 423881Sjohnny case DDI_INTROP_FREE: 424881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 425881Sjohnny (psm_intr_ops != NULL)) { 4262018Sanish if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 == 4272018Sanish 0) { 4281997Sanish if (handle = i_ddi_get_pci_config_handle( 4291997Sanish rdip)) { 4301997Sanish (void) pci_config_teardown(&handle); 4311997Sanish i_ddi_set_pci_config_handle(rdip, NULL); 4321997Sanish } 4331997Sanish if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip)) 4341997Sanish i_ddi_set_msi_msix_cap_ptr(rdip, 0); 4351997Sanish } 4361997Sanish 437881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 438881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 439881Sjohnny 440881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 441881Sjohnny msix_p = i_ddi_get_msix(hdlp->ih_dip); 442881Sjohnny if (msix_p && 4432018Sanish (i_ddi_intr_get_current_nintrs( 4444397Sschwartz hdlp->ih_dip) - 1) == 0) { 445881Sjohnny pci_msix_fini(msix_p); 446881Sjohnny i_ddi_set_msix(hdlp->ih_dip, NULL); 447881Sjohnny } 448881Sjohnny } 449881Sjohnny } 450881Sjohnny break; 451881Sjohnny case DDI_INTROP_GETPRI: 452881Sjohnny /* Get the priority */ 453881Sjohnny if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS) 454881Sjohnny return (DDI_FAILURE); 455881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 456881Sjohnny "priority = 0x%x\n", priority)); 457881Sjohnny *(int *)result = priority; 458881Sjohnny break; 459881Sjohnny case DDI_INTROP_SETPRI: 460881Sjohnny /* Validate the interrupt priority passed */ 461881Sjohnny if (*(int *)result > LOCK_LEVEL) 462881Sjohnny return (DDI_FAILURE); 463881Sjohnny 464881Sjohnny /* Ensure that PSM is all initialized */ 465881Sjohnny if (psm_intr_ops == NULL) 466881Sjohnny return (DDI_FAILURE); 467881Sjohnny 46810190SSophia.Li@Sun.COM isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 46910190SSophia.Li@Sun.COM ispec = (struct intrspec *)isp; 47010190SSophia.Li@Sun.COM if (ispec == NULL) 47110190SSophia.Li@Sun.COM return (DDI_FAILURE); 47210190SSophia.Li@Sun.COM 47310190SSophia.Li@Sun.COM /* For fixed interrupts */ 47410190SSophia.Li@Sun.COM if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 47510190SSophia.Li@Sun.COM /* if interrupt is shared, return failure */ 47610190SSophia.Li@Sun.COM ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 47710190SSophia.Li@Sun.COM psm_rval = (*psm_intr_ops)(rdip, hdlp, 47810190SSophia.Li@Sun.COM PSM_INTR_OP_GET_SHARED, &psm_status); 47910190SSophia.Li@Sun.COM /* 48010190SSophia.Li@Sun.COM * For fixed interrupts, the irq may not have been 48110190SSophia.Li@Sun.COM * allocated when SET_PRI is called, and the above 48210190SSophia.Li@Sun.COM * GET_SHARED op may return PSM_FAILURE. This is not 48310190SSophia.Li@Sun.COM * a real error and is ignored below. 48410190SSophia.Li@Sun.COM */ 48510190SSophia.Li@Sun.COM if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) { 48610190SSophia.Li@Sun.COM DDI_INTR_NEXDBG((CE_CONT, 48710190SSophia.Li@Sun.COM "pci_common_intr_ops: " 48810190SSophia.Li@Sun.COM "dip 0x%p cannot setpri, psm_rval=%d," 48910190SSophia.Li@Sun.COM "psm_status=%d\n", (void *)rdip, psm_rval, 49010190SSophia.Li@Sun.COM psm_status)); 49110190SSophia.Li@Sun.COM return (DDI_FAILURE); 49210190SSophia.Li@Sun.COM } 49310190SSophia.Li@Sun.COM } 49410190SSophia.Li@Sun.COM 495881Sjohnny /* Change the priority */ 496881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 497881Sjohnny PSM_FAILURE) 498881Sjohnny return (DDI_FAILURE); 499881Sjohnny 500881Sjohnny /* update ispec */ 50110190SSophia.Li@Sun.COM ispec->intrspec_pri = *(int *)result; 502881Sjohnny break; 503881Sjohnny case DDI_INTROP_ADDISR: 504881Sjohnny /* update ispec */ 505881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 506881Sjohnny ispec = (struct intrspec *)isp; 5071087Sschwartz if (ispec) { 508881Sjohnny ispec->intrspec_func = hdlp->ih_cb_func; 5091087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 5101087Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 5111087Sschwartz } 512881Sjohnny break; 513881Sjohnny case DDI_INTROP_REMISR: 514881Sjohnny /* Get the interrupt structure pointer */ 515881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 516881Sjohnny ispec = (struct intrspec *)isp; 5171087Sschwartz if (ispec) { 518881Sjohnny ispec->intrspec_func = (uint_t (*)()) 0; 5191087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 5201087Sschwartz if (ihdl_plat_datap->ip_ksp != NULL) 5211087Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp); 5221087Sschwartz } 523881Sjohnny break; 524881Sjohnny case DDI_INTROP_GETCAP: 525881Sjohnny /* 526881Sjohnny * First check the config space and/or 527881Sjohnny * MSI capability register(s) 528881Sjohnny */ 529881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 530881Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 531881Sjohnny &pci_status); 532881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 533881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 534881Sjohnny 535881Sjohnny /* next check with pcplusmp */ 536881Sjohnny if (psm_intr_ops != NULL) 537881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 538881Sjohnny PSM_INTR_OP_GET_CAP, &psm_status); 539881Sjohnny 540881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 541881Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n", 542881Sjohnny psm_rval, psm_status, pci_rval, pci_status)); 543881Sjohnny 544881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 545881Sjohnny *(int *)result = 0; 546881Sjohnny return (DDI_FAILURE); 547881Sjohnny } 548881Sjohnny 549881Sjohnny if (psm_rval == PSM_SUCCESS) 550881Sjohnny *(int *)result = psm_status; 551881Sjohnny 552881Sjohnny if (pci_rval == DDI_SUCCESS) 553881Sjohnny *(int *)result |= pci_status; 554881Sjohnny 555881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 556881Sjohnny *(int *)result)); 557881Sjohnny break; 558881Sjohnny case DDI_INTROP_SETCAP: 559881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 560881Sjohnny "SETCAP cap=0x%x\n", *(int *)result)); 561881Sjohnny if (psm_intr_ops == NULL) 562881Sjohnny return (DDI_FAILURE); 563881Sjohnny 564881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 565881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 566881Sjohnny " returned failure\n")); 567881Sjohnny return (DDI_FAILURE); 568881Sjohnny } 569881Sjohnny break; 570881Sjohnny case DDI_INTROP_ENABLE: 571881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 572881Sjohnny if (psm_intr_ops == NULL) 573881Sjohnny return (DDI_FAILURE); 574881Sjohnny 575881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 576881Sjohnny DDI_SUCCESS) 577881Sjohnny return (DDI_FAILURE); 578881Sjohnny 579881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 580881Sjohnny "vector=0x%x\n", hdlp->ih_vector)); 581881Sjohnny break; 582881Sjohnny case DDI_INTROP_DISABLE: 583881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 584881Sjohnny if (psm_intr_ops == NULL) 585881Sjohnny return (DDI_FAILURE); 586881Sjohnny 587881Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 588881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 589881Sjohnny "vector = %x\n", hdlp->ih_vector)); 590881Sjohnny break; 591881Sjohnny case DDI_INTROP_BLOCKENABLE: 592881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 593881Sjohnny "BLOCKENABLE\n")); 594881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 595881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 596881Sjohnny return (DDI_FAILURE); 597881Sjohnny } 598881Sjohnny 599881Sjohnny /* Check if psm_intr_ops is NULL? */ 600881Sjohnny if (psm_intr_ops == NULL) 601881Sjohnny return (DDI_FAILURE); 602881Sjohnny 6031542Sjohnny count = hdlp->ih_scratch1; 6041542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 6051542Sjohnny for (i = 0; i < count; i++) { 6061542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 607881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, 6081542Sjohnny hdlp->ih_inum) != DDI_SUCCESS) { 609881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 610881Sjohnny "pci_enable_intr failed for %d\n", i)); 6111542Sjohnny for (j = 0; j < i; j++) { 6124397Sschwartz hdlp = (ddi_intr_handle_impl_t *) 6134397Sschwartz h_array[j]; 6144397Sschwartz pci_disable_intr(pdip, rdip, hdlp, 6151542Sjohnny hdlp->ih_inum); 6161542Sjohnny } 617881Sjohnny return (DDI_FAILURE); 618881Sjohnny } 619881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 6201542Sjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 621881Sjohnny } 622881Sjohnny break; 623881Sjohnny case DDI_INTROP_BLOCKDISABLE: 624881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 625881Sjohnny "BLOCKDISABLE\n")); 626881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 627881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 628881Sjohnny return (DDI_FAILURE); 629881Sjohnny } 630881Sjohnny 631881Sjohnny /* Check if psm_intr_ops is present */ 632881Sjohnny if (psm_intr_ops == NULL) 633881Sjohnny return (DDI_FAILURE); 634881Sjohnny 6351542Sjohnny count = hdlp->ih_scratch1; 6361542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 6371542Sjohnny for (i = 0; i < count; i++) { 6381542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 6391542Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 640881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 6411542Sjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 642881Sjohnny } 643881Sjohnny break; 644881Sjohnny case DDI_INTROP_SETMASK: 645881Sjohnny case DDI_INTROP_CLRMASK: 646881Sjohnny /* 647881Sjohnny * First handle in the config space 648881Sjohnny */ 649881Sjohnny if (intr_op == DDI_INTROP_SETMASK) { 650881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 651881Sjohnny pci_status = pci_msi_set_mask(rdip, 652881Sjohnny hdlp->ih_type, hdlp->ih_inum); 653881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 654881Sjohnny pci_status = pci_intx_set_mask(rdip); 655881Sjohnny } else { 656881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 657881Sjohnny pci_status = pci_msi_clr_mask(rdip, 658881Sjohnny hdlp->ih_type, hdlp->ih_inum); 659881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 660881Sjohnny pci_status = pci_intx_clr_mask(rdip); 661881Sjohnny } 662881Sjohnny 663881Sjohnny /* For MSI/X; no need to check with pcplusmp */ 664881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 665881Sjohnny return (pci_status); 666881Sjohnny 667881Sjohnny /* For fixed interrupts only: handle config space first */ 668881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 669881Sjohnny pci_status == DDI_SUCCESS) 670881Sjohnny break; 671881Sjohnny 672881Sjohnny /* For fixed interrupts only: confer with pcplusmp next */ 673881Sjohnny if (psm_intr_ops != NULL) { 674881Sjohnny /* If interrupt is shared; do nothing */ 675881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 676881Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status); 677881Sjohnny 678881Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1) 679881Sjohnny return (pci_status); 680881Sjohnny 681881Sjohnny /* Now, pcplusmp should try to set/clear the mask */ 682881Sjohnny if (intr_op == DDI_INTROP_SETMASK) 683881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 684881Sjohnny PSM_INTR_OP_SET_MASK, NULL); 685881Sjohnny else 686881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 687881Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL); 688881Sjohnny } 689881Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 690881Sjohnny case DDI_INTROP_GETPENDING: 691881Sjohnny /* 692881Sjohnny * First check the config space and/or 693881Sjohnny * MSI capability register(s) 694881Sjohnny */ 695881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 696881Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 697881Sjohnny hdlp->ih_inum, &pci_status); 698881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 699881Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status); 700881Sjohnny 701881Sjohnny /* On failure; next try with pcplusmp */ 702881Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 703881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 704881Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status); 705881Sjohnny 706881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 707881Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, " 708881Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval, 709881Sjohnny pci_status)); 710881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 711881Sjohnny *(int *)result = 0; 712881Sjohnny return (DDI_FAILURE); 713881Sjohnny } 714881Sjohnny 715881Sjohnny if (psm_rval != PSM_FAILURE) 716881Sjohnny *(int *)result = psm_status; 717881Sjohnny else if (pci_rval != DDI_FAILURE) 718881Sjohnny *(int *)result = pci_status; 719881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 720881Sjohnny *(int *)result)); 721881Sjohnny break; 72210053SEvan.Yan@Sun.COM case DDI_INTROP_GETTARGET: 72310053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n")); 72410053SEvan.Yan@Sun.COM 72510053SEvan.Yan@Sun.COM /* Note hdlp->ih_vector is actually an irq */ 72610053SEvan.Yan@Sun.COM if ((rv = pci_get_cpu_from_vecirq(hdlp->ih_vector, IS_IRQ)) == 72710053SEvan.Yan@Sun.COM -1) 72810053SEvan.Yan@Sun.COM return (DDI_FAILURE); 72910053SEvan.Yan@Sun.COM *(int *)result = rv; 73010053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET " 73110053SEvan.Yan@Sun.COM "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector, rv)); 73210053SEvan.Yan@Sun.COM break; 73310053SEvan.Yan@Sun.COM case DDI_INTROP_SETTARGET: 73410053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n")); 73510053SEvan.Yan@Sun.COM 73610053SEvan.Yan@Sun.COM /* hdlp->ih_vector is actually an irq */ 73710053SEvan.Yan@Sun.COM tmp_hdl.ih_vector = hdlp->ih_vector; 73810053SEvan.Yan@Sun.COM tmp_hdl.ih_flags = PSMGI_INTRBY_IRQ; 73910053SEvan.Yan@Sun.COM tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result; 74010053SEvan.Yan@Sun.COM psm_rval = (*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU, 74110053SEvan.Yan@Sun.COM &psm_status); 74210053SEvan.Yan@Sun.COM 74310053SEvan.Yan@Sun.COM if (psm_rval != PSM_SUCCESS) 74410053SEvan.Yan@Sun.COM return (DDI_FAILURE); 74510053SEvan.Yan@Sun.COM break; 746881Sjohnny default: 747881Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 748881Sjohnny } 749881Sjohnny 750881Sjohnny return (DDI_SUCCESS); 751881Sjohnny } 752881Sjohnny 753916Sschwartz int 754916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 755916Sschwartz int vecirq, boolean_t is_irq) 756916Sschwartz { 757916Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl; 758916Sschwartz 759916Sschwartz if (is_irq) 760916Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 761916Sschwartz 762916Sschwartz /* 763916Sschwartz * For this locally-declared and used handle, ih_private will contain a 764916Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 765916Sschwartz * global interrupt handling. 766916Sschwartz */ 767916Sschwartz get_info_ii_hdl.ih_private = intrinfo_p; 768916Sschwartz get_info_ii_hdl.ih_vector = (ushort_t)vecirq; 769916Sschwartz 770916Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 771916Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 772916Sschwartz return (DDI_FAILURE); 773916Sschwartz 774916Sschwartz return (DDI_SUCCESS); 775916Sschwartz } 776916Sschwartz 777916Sschwartz 778916Sschwartz int 779916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 780916Sschwartz { 781916Sschwartz int rval; 782916Sschwartz 783916Sschwartz apic_get_intr_t intrinfo; 784916Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 785916Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 786916Sschwartz 787916Sschwartz if (rval == DDI_SUCCESS) 788916Sschwartz return (intrinfo.avgi_cpu_id); 789916Sschwartz else 790916Sschwartz return (-1); 791916Sschwartz } 792916Sschwartz 793881Sjohnny 794881Sjohnny static int 795881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 796881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 797881Sjohnny { 798881Sjohnny struct intrspec *ispec; 799916Sschwartz int irq; 800916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 801881Sjohnny 802881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 803881Sjohnny (void *)hdlp, inum)); 804881Sjohnny 805881Sjohnny /* Translate the interrupt if needed */ 806881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 8072288Sanish if (ispec == NULL) 8082288Sanish return (DDI_FAILURE); 80910190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 810881Sjohnny ispec->intrspec_vec = inum; 81110190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri; 81210190SSophia.Li@Sun.COM } 813916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 814881Sjohnny 815881Sjohnny /* translate the interrupt if needed */ 816*11465SKerry.Shu@Sun.COM if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) == 817*11465SKerry.Shu@Sun.COM PSM_FAILURE) 818*11465SKerry.Shu@Sun.COM return (DDI_FAILURE); 819916Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 820916Sschwartz hdlp->ih_pri, irq)); 821881Sjohnny 822881Sjohnny /* Add the interrupt handler */ 823881Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 824916Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 825916Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 826881Sjohnny return (DDI_FAILURE); 827881Sjohnny 828916Sschwartz /* Note this really is an irq. */ 829916Sschwartz hdlp->ih_vector = (ushort_t)irq; 830916Sschwartz 831881Sjohnny return (DDI_SUCCESS); 832881Sjohnny } 833881Sjohnny 834881Sjohnny 835881Sjohnny static void 836881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 837881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 838881Sjohnny { 839916Sschwartz int irq; 840881Sjohnny struct intrspec *ispec; 841916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 842881Sjohnny 843881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 844881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 8452288Sanish if (ispec == NULL) 8462288Sanish return; 84710190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 848881Sjohnny ispec->intrspec_vec = inum; 84910190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri; 85010190SSophia.Li@Sun.COM } 851916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 852881Sjohnny 853881Sjohnny /* translate the interrupt if needed */ 854916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 855881Sjohnny 856881Sjohnny /* Disable the interrupt handler */ 857916Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 858916Sschwartz ihdl_plat_datap->ip_ispecp = NULL; 859881Sjohnny } 860881Sjohnny 861881Sjohnny /* 862881Sjohnny * Miscellaneous library function 863881Sjohnny */ 864881Sjohnny int 865881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 866881Sjohnny { 867881Sjohnny int i; 868881Sjohnny int number; 869881Sjohnny int assigned_addr_len; 870881Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi; 871881Sjohnny pci_regspec_t *assigned_addr; 872881Sjohnny 873881Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 874881Sjohnny (phys_hi & PCI_RELOCAT_B)) 875881Sjohnny return (DDI_SUCCESS); 876881Sjohnny 877881Sjohnny /* 878881Sjohnny * the "reg" property specifies relocatable, get and interpret the 879881Sjohnny * "assigned-addresses" property. 880881Sjohnny */ 881881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 882881Sjohnny "assigned-addresses", (int **)&assigned_addr, 883881Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 884881Sjohnny return (DDI_FAILURE); 885881Sjohnny 886881Sjohnny /* 887881Sjohnny * Scan the "assigned-addresses" for one that matches the specified 888881Sjohnny * "reg" property entry. 889881Sjohnny */ 890881Sjohnny phys_hi &= PCI_CONF_ADDR_MASK; 891881Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 892881Sjohnny for (i = 0; i < number; i++) { 893881Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 894881Sjohnny phys_hi) { 895881Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 896881Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 897881Sjohnny ddi_prop_free(assigned_addr); 898881Sjohnny return (DDI_SUCCESS); 899881Sjohnny } 900881Sjohnny } 901881Sjohnny 902881Sjohnny ddi_prop_free(assigned_addr); 903881Sjohnny return (DDI_FAILURE); 904881Sjohnny } 905881Sjohnny 906881Sjohnny 907881Sjohnny /* 90810923SEvan.Yan@Sun.COM * To handle PCI tool ioctls 909881Sjohnny */ 910881Sjohnny 91110923SEvan.Yan@Sun.COM /*ARGSUSED*/ 912881Sjohnny int 913881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 914881Sjohnny int mode, cred_t *credp, int *rvalp) 915881Sjohnny { 91610923SEvan.Yan@Sun.COM minor_t minor = getminor(dev); 91710923SEvan.Yan@Sun.COM int rv = ENOTTY; 918881Sjohnny 91910923SEvan.Yan@Sun.COM switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 920881Sjohnny case PCI_TOOL_REG_MINOR_NUM: 921881Sjohnny 922881Sjohnny switch (cmd) { 923881Sjohnny case PCITOOL_DEVICE_SET_REG: 924881Sjohnny case PCITOOL_DEVICE_GET_REG: 925881Sjohnny 926881Sjohnny /* Require full privileges. */ 927881Sjohnny if (secpolicy_kmdb(credp)) 928881Sjohnny rv = EPERM; 929881Sjohnny else 930881Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg, 931881Sjohnny cmd, mode); 932881Sjohnny break; 933881Sjohnny 934881Sjohnny case PCITOOL_NEXUS_SET_REG: 935881Sjohnny case PCITOOL_NEXUS_GET_REG: 936881Sjohnny 937881Sjohnny /* Require full privileges. */ 938881Sjohnny if (secpolicy_kmdb(credp)) 939881Sjohnny rv = EPERM; 940881Sjohnny else 941881Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg, 942881Sjohnny cmd, mode); 943881Sjohnny break; 944881Sjohnny } 945881Sjohnny break; 946881Sjohnny 947881Sjohnny case PCI_TOOL_INTR_MINOR_NUM: 948881Sjohnny 949881Sjohnny switch (cmd) { 950881Sjohnny case PCITOOL_DEVICE_SET_INTR: 951881Sjohnny 952881Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 953881Sjohnny if (secpolicy_ponline(credp)) { 954881Sjohnny rv = EPERM; 955881Sjohnny break; 956881Sjohnny } 957881Sjohnny 958881Sjohnny /*FALLTHRU*/ 959881Sjohnny /* These require no special privileges. */ 960881Sjohnny case PCITOOL_DEVICE_GET_INTR: 9614397Sschwartz case PCITOOL_SYSTEM_INTR_INFO: 962881Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 963881Sjohnny break; 964881Sjohnny } 965881Sjohnny break; 966881Sjohnny 967881Sjohnny default: 968881Sjohnny break; 969881Sjohnny } 970881Sjohnny 971881Sjohnny return (rv); 972881Sjohnny } 9731083Sanish 9741083Sanish 9751865Sdilpreet int 9761865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 9771865Sdilpreet { 9781865Sdilpreet size_t size = in_args->size; 9791865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 9801865Sdilpreet uintptr_t host_addr = in_args->host_addr; 9811865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 9821865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 9831865Sdilpreet size_t repcount = in_args->repcount; 9841865Sdilpreet uint_t flags = in_args->flags; 9851865Sdilpreet int err = DDI_SUCCESS; 9861865Sdilpreet 9871865Sdilpreet /* 9881865Sdilpreet * if no handle then this is a poke. We have to return failure here 9891865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 9901865Sdilpreet */ 9911865Sdilpreet if (in_args->handle == NULL) 9921865Sdilpreet return (DDI_FAILURE); 9931865Sdilpreet 9941865Sdilpreet /* 9951865Sdilpreet * rest of this function is actually for cautious puts 9961865Sdilpreet */ 9971865Sdilpreet for (; repcount; repcount--) { 9981865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 9991865Sdilpreet switch (size) { 10001865Sdilpreet case sizeof (uint8_t): 10011865Sdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr, 10021865Sdilpreet *(uint8_t *)host_addr); 10031865Sdilpreet break; 10041865Sdilpreet case sizeof (uint16_t): 10051865Sdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr, 10061865Sdilpreet *(uint16_t *)host_addr); 10071865Sdilpreet break; 10081865Sdilpreet case sizeof (uint32_t): 10091865Sdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr, 10101865Sdilpreet *(uint32_t *)host_addr); 10111865Sdilpreet break; 10121865Sdilpreet case sizeof (uint64_t): 10131865Sdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr, 10141865Sdilpreet *(uint64_t *)host_addr); 10151865Sdilpreet break; 10161865Sdilpreet default: 10171865Sdilpreet err = DDI_FAILURE; 10181865Sdilpreet break; 10191865Sdilpreet } 10201865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 10211865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 10221865Sdilpreet DDI_STRUCTURE_BE_ACC) { 10231865Sdilpreet switch (size) { 10241865Sdilpreet case sizeof (uint8_t): 10251865Sdilpreet i_ddi_io_put8(hp, 10261865Sdilpreet (uint8_t *)dev_addr, 10271865Sdilpreet *(uint8_t *)host_addr); 10281865Sdilpreet break; 10291865Sdilpreet case sizeof (uint16_t): 10301865Sdilpreet i_ddi_io_swap_put16(hp, 10311865Sdilpreet (uint16_t *)dev_addr, 10321865Sdilpreet *(uint16_t *)host_addr); 10331865Sdilpreet break; 10341865Sdilpreet case sizeof (uint32_t): 10351865Sdilpreet i_ddi_io_swap_put32(hp, 10361865Sdilpreet (uint32_t *)dev_addr, 10371865Sdilpreet *(uint32_t *)host_addr); 10381865Sdilpreet break; 10391865Sdilpreet /* 10401865Sdilpreet * note the 64-bit case is a dummy 10411865Sdilpreet * function - so no need to swap 10421865Sdilpreet */ 10431865Sdilpreet case sizeof (uint64_t): 10441865Sdilpreet i_ddi_io_put64(hp, 10451865Sdilpreet (uint64_t *)dev_addr, 10461865Sdilpreet *(uint64_t *)host_addr); 10471865Sdilpreet break; 10481865Sdilpreet default: 10491865Sdilpreet err = DDI_FAILURE; 10501865Sdilpreet break; 10511865Sdilpreet } 10521865Sdilpreet } else { 10531865Sdilpreet switch (size) { 10541865Sdilpreet case sizeof (uint8_t): 10551865Sdilpreet i_ddi_io_put8(hp, 10561865Sdilpreet (uint8_t *)dev_addr, 10571865Sdilpreet *(uint8_t *)host_addr); 10581865Sdilpreet break; 10591865Sdilpreet case sizeof (uint16_t): 10601865Sdilpreet i_ddi_io_put16(hp, 10611865Sdilpreet (uint16_t *)dev_addr, 10621865Sdilpreet *(uint16_t *)host_addr); 10631865Sdilpreet break; 10641865Sdilpreet case sizeof (uint32_t): 10651865Sdilpreet i_ddi_io_put32(hp, 10661865Sdilpreet (uint32_t *)dev_addr, 10671865Sdilpreet *(uint32_t *)host_addr); 10681865Sdilpreet break; 10691865Sdilpreet case sizeof (uint64_t): 10701865Sdilpreet i_ddi_io_put64(hp, 10711865Sdilpreet (uint64_t *)dev_addr, 10721865Sdilpreet *(uint64_t *)host_addr); 10731865Sdilpreet break; 10741865Sdilpreet default: 10751865Sdilpreet err = DDI_FAILURE; 10761865Sdilpreet break; 10771865Sdilpreet } 10781865Sdilpreet } 10791865Sdilpreet } else { 10801865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 10811865Sdilpreet DDI_STRUCTURE_BE_ACC) { 10821865Sdilpreet switch (size) { 10831865Sdilpreet case sizeof (uint8_t): 10841865Sdilpreet *(uint8_t *)dev_addr = 10851865Sdilpreet *(uint8_t *)host_addr; 10861865Sdilpreet break; 10871865Sdilpreet case sizeof (uint16_t): 10881865Sdilpreet *(uint16_t *)dev_addr = 10891865Sdilpreet ddi_swap16(*(uint16_t *)host_addr); 10901865Sdilpreet break; 10911865Sdilpreet case sizeof (uint32_t): 10921865Sdilpreet *(uint32_t *)dev_addr = 10931865Sdilpreet ddi_swap32(*(uint32_t *)host_addr); 10941865Sdilpreet break; 10951865Sdilpreet case sizeof (uint64_t): 10961865Sdilpreet *(uint64_t *)dev_addr = 10971865Sdilpreet ddi_swap64(*(uint64_t *)host_addr); 10981865Sdilpreet break; 10991865Sdilpreet default: 11001865Sdilpreet err = DDI_FAILURE; 11011865Sdilpreet break; 11021865Sdilpreet } 11031865Sdilpreet } else { 11041865Sdilpreet switch (size) { 11051865Sdilpreet case sizeof (uint8_t): 11061865Sdilpreet *(uint8_t *)dev_addr = 11071865Sdilpreet *(uint8_t *)host_addr; 11081865Sdilpreet break; 11091865Sdilpreet case sizeof (uint16_t): 11101865Sdilpreet *(uint16_t *)dev_addr = 11111865Sdilpreet *(uint16_t *)host_addr; 11121865Sdilpreet break; 11131865Sdilpreet case sizeof (uint32_t): 11141865Sdilpreet *(uint32_t *)dev_addr = 11151865Sdilpreet *(uint32_t *)host_addr; 11161865Sdilpreet break; 11171865Sdilpreet case sizeof (uint64_t): 11181865Sdilpreet *(uint64_t *)dev_addr = 11191865Sdilpreet *(uint64_t *)host_addr; 11201865Sdilpreet break; 11211865Sdilpreet default: 11221865Sdilpreet err = DDI_FAILURE; 11231865Sdilpreet break; 11241865Sdilpreet } 11251865Sdilpreet } 11261865Sdilpreet } 11271865Sdilpreet host_addr += size; 11281865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 11291865Sdilpreet dev_addr += size; 11301865Sdilpreet } 11311865Sdilpreet return (err); 11321865Sdilpreet } 11331865Sdilpreet 11341865Sdilpreet 11351865Sdilpreet int 11361865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 11371865Sdilpreet { 11381865Sdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 11391865Sdilpreet 11401865Sdilpreet /* endian-ness check */ 11411865Sdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 11421865Sdilpreet return (DDI_FAILURE); 11431865Sdilpreet 11441865Sdilpreet /* 11451865Sdilpreet * range check 11461865Sdilpreet */ 11471865Sdilpreet if ((offset >= PCI_CONF_HDR_SIZE) || 11481865Sdilpreet (len > PCI_CONF_HDR_SIZE) || 11491865Sdilpreet (offset + len > PCI_CONF_HDR_SIZE)) 11501865Sdilpreet return (DDI_FAILURE); 11511865Sdilpreet 11521865Sdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 11531865Sdilpreet /* 11541865Sdilpreet * always use cautious mechanism for config space gets 11551865Sdilpreet */ 11561865Sdilpreet ap->ahi_get8 = i_ddi_caut_get8; 11571865Sdilpreet ap->ahi_get16 = i_ddi_caut_get16; 11581865Sdilpreet ap->ahi_get32 = i_ddi_caut_get32; 11591865Sdilpreet ap->ahi_get64 = i_ddi_caut_get64; 11601865Sdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 11611865Sdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 11621865Sdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 11631865Sdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 11641865Sdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 11651865Sdilpreet ap->ahi_put8 = i_ddi_caut_put8; 11661865Sdilpreet ap->ahi_put16 = i_ddi_caut_put16; 11671865Sdilpreet ap->ahi_put32 = i_ddi_caut_put32; 11681865Sdilpreet ap->ahi_put64 = i_ddi_caut_put64; 11691865Sdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 11701865Sdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 11711865Sdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 11721865Sdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 11731865Sdilpreet } else { 11741865Sdilpreet ap->ahi_put8 = pci_config_wr8; 11751865Sdilpreet ap->ahi_put16 = pci_config_wr16; 11761865Sdilpreet ap->ahi_put32 = pci_config_wr32; 11771865Sdilpreet ap->ahi_put64 = pci_config_wr64; 11781865Sdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8; 11791865Sdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16; 11801865Sdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32; 11811865Sdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64; 11821865Sdilpreet } 11831865Sdilpreet 11841865Sdilpreet /* Initialize to default check/notify functions */ 11851865Sdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check; 11861865Sdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify; 11871865Sdilpreet ap->ahi_fault = 0; 11881865Sdilpreet impl_acc_err_init(hp); 11891865Sdilpreet return (DDI_SUCCESS); 11901865Sdilpreet } 11911865Sdilpreet 11921865Sdilpreet 11931865Sdilpreet int 11941865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 11951865Sdilpreet { 11961865Sdilpreet size_t size = in_args->size; 11971865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 11981865Sdilpreet uintptr_t host_addr = in_args->host_addr; 11991865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 12001865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 12011865Sdilpreet size_t repcount = in_args->repcount; 12021865Sdilpreet uint_t flags = in_args->flags; 12031865Sdilpreet int err = DDI_SUCCESS; 12041865Sdilpreet 12051865Sdilpreet /* 12061865Sdilpreet * if no handle then this is a peek. We have to return failure here 12071865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 12081865Sdilpreet */ 12091865Sdilpreet if (in_args->handle == NULL) 12101865Sdilpreet return (DDI_FAILURE); 12111865Sdilpreet 12121865Sdilpreet for (; repcount; repcount--) { 12131865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 12141865Sdilpreet switch (size) { 12151865Sdilpreet case sizeof (uint8_t): 12161865Sdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp, 12171865Sdilpreet (uint8_t *)dev_addr); 12181865Sdilpreet break; 12191865Sdilpreet case sizeof (uint16_t): 12201865Sdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp, 12211865Sdilpreet (uint16_t *)dev_addr); 12221865Sdilpreet break; 12231865Sdilpreet case sizeof (uint32_t): 12241865Sdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp, 12251865Sdilpreet (uint32_t *)dev_addr); 12261865Sdilpreet break; 12271865Sdilpreet case sizeof (uint64_t): 12281865Sdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp, 12291865Sdilpreet (uint64_t *)dev_addr); 12301865Sdilpreet break; 12311865Sdilpreet default: 12321865Sdilpreet err = DDI_FAILURE; 12331865Sdilpreet break; 12341865Sdilpreet } 12351865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 12361865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12371865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12381865Sdilpreet switch (size) { 12391865Sdilpreet case sizeof (uint8_t): 12401865Sdilpreet *(uint8_t *)host_addr = 12411865Sdilpreet i_ddi_io_get8(hp, 12421865Sdilpreet (uint8_t *)dev_addr); 12431865Sdilpreet break; 12441865Sdilpreet case sizeof (uint16_t): 12451865Sdilpreet *(uint16_t *)host_addr = 12461865Sdilpreet i_ddi_io_swap_get16(hp, 12471865Sdilpreet (uint16_t *)dev_addr); 12481865Sdilpreet break; 12491865Sdilpreet case sizeof (uint32_t): 12501865Sdilpreet *(uint32_t *)host_addr = 12511865Sdilpreet i_ddi_io_swap_get32(hp, 12521865Sdilpreet (uint32_t *)dev_addr); 12531865Sdilpreet break; 12541865Sdilpreet /* 12551865Sdilpreet * note the 64-bit case is a dummy 12561865Sdilpreet * function - so no need to swap 12571865Sdilpreet */ 12581865Sdilpreet case sizeof (uint64_t): 12591865Sdilpreet *(uint64_t *)host_addr = 12601865Sdilpreet i_ddi_io_get64(hp, 12611865Sdilpreet (uint64_t *)dev_addr); 12621865Sdilpreet break; 12631865Sdilpreet default: 12641865Sdilpreet err = DDI_FAILURE; 12651865Sdilpreet break; 12661865Sdilpreet } 12671865Sdilpreet } else { 12681865Sdilpreet switch (size) { 12691865Sdilpreet case sizeof (uint8_t): 12701865Sdilpreet *(uint8_t *)host_addr = 12711865Sdilpreet i_ddi_io_get8(hp, 12721865Sdilpreet (uint8_t *)dev_addr); 12731865Sdilpreet break; 12741865Sdilpreet case sizeof (uint16_t): 12751865Sdilpreet *(uint16_t *)host_addr = 12761865Sdilpreet i_ddi_io_get16(hp, 12771865Sdilpreet (uint16_t *)dev_addr); 12781865Sdilpreet break; 12791865Sdilpreet case sizeof (uint32_t): 12801865Sdilpreet *(uint32_t *)host_addr = 12811865Sdilpreet i_ddi_io_get32(hp, 12821865Sdilpreet (uint32_t *)dev_addr); 12831865Sdilpreet break; 12841865Sdilpreet case sizeof (uint64_t): 12851865Sdilpreet *(uint64_t *)host_addr = 12861865Sdilpreet i_ddi_io_get64(hp, 12871865Sdilpreet (uint64_t *)dev_addr); 12881865Sdilpreet break; 12891865Sdilpreet default: 12901865Sdilpreet err = DDI_FAILURE; 12911865Sdilpreet break; 12921865Sdilpreet } 12931865Sdilpreet } 12941865Sdilpreet } else { 12951865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12961865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12971865Sdilpreet switch (in_args->size) { 12981865Sdilpreet case sizeof (uint8_t): 12991865Sdilpreet *(uint8_t *)host_addr = 13001865Sdilpreet *(uint8_t *)dev_addr; 13011865Sdilpreet break; 13021865Sdilpreet case sizeof (uint16_t): 13031865Sdilpreet *(uint16_t *)host_addr = 13041865Sdilpreet ddi_swap16(*(uint16_t *)dev_addr); 13051865Sdilpreet break; 13061865Sdilpreet case sizeof (uint32_t): 13071865Sdilpreet *(uint32_t *)host_addr = 13081865Sdilpreet ddi_swap32(*(uint32_t *)dev_addr); 13091865Sdilpreet break; 13101865Sdilpreet case sizeof (uint64_t): 13111865Sdilpreet *(uint64_t *)host_addr = 13121865Sdilpreet ddi_swap64(*(uint64_t *)dev_addr); 13131865Sdilpreet break; 13141865Sdilpreet default: 13151865Sdilpreet err = DDI_FAILURE; 13161865Sdilpreet break; 13171865Sdilpreet } 13181865Sdilpreet } else { 13191865Sdilpreet switch (in_args->size) { 13201865Sdilpreet case sizeof (uint8_t): 13211865Sdilpreet *(uint8_t *)host_addr = 13221865Sdilpreet *(uint8_t *)dev_addr; 13231865Sdilpreet break; 13241865Sdilpreet case sizeof (uint16_t): 13251865Sdilpreet *(uint16_t *)host_addr = 13261865Sdilpreet *(uint16_t *)dev_addr; 13271865Sdilpreet break; 13281865Sdilpreet case sizeof (uint32_t): 13291865Sdilpreet *(uint32_t *)host_addr = 13301865Sdilpreet *(uint32_t *)dev_addr; 13311865Sdilpreet break; 13321865Sdilpreet case sizeof (uint64_t): 13331865Sdilpreet *(uint64_t *)host_addr = 13341865Sdilpreet *(uint64_t *)dev_addr; 13351865Sdilpreet break; 13361865Sdilpreet default: 13371865Sdilpreet err = DDI_FAILURE; 13381865Sdilpreet break; 13391865Sdilpreet } 13401865Sdilpreet } 13411865Sdilpreet } 13421865Sdilpreet host_addr += size; 13431865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 13441865Sdilpreet dev_addr += size; 13451865Sdilpreet } 13461865Sdilpreet return (err); 13471865Sdilpreet } 13481865Sdilpreet 13491865Sdilpreet /*ARGSUSED*/ 13501865Sdilpreet int 13511865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 13521865Sdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result) 13531865Sdilpreet { 13541865Sdilpreet if (ctlop == DDI_CTLOPS_PEEK) 13551865Sdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 13561865Sdilpreet else 13571865Sdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 13581865Sdilpreet } 13591865Sdilpreet 13601083Sanish /* 13611083Sanish * These are the get and put functions to be shared with drivers. The 13621083Sanish * mutex locking is done inside the functions referenced, rather than 13631083Sanish * here, and is thus shared across PCI child drivers and any other 13641083Sanish * consumers of PCI config space (such as the ACPI subsystem). 13651083Sanish * 13661083Sanish * The configuration space addresses come in as pointers. This is fine on 13671083Sanish * a 32-bit system, where the VM space and configuration space are the same 13681083Sanish * size. It's not such a good idea on a 64-bit system, where memory 13691083Sanish * addresses are twice as large as configuration space addresses. At some 13701083Sanish * point in the call tree we need to take a stand and say "you are 32-bit 13711083Sanish * from this time forth", and this seems like a nice self-contained place. 13721083Sanish */ 13731083Sanish 13741083Sanish uint8_t 13751083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 13761083Sanish { 13771083Sanish pci_acc_cfblk_t *cfp; 13781083Sanish uint8_t rval; 13791083Sanish int reg; 13801083Sanish 13811083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13821083Sanish 13831083Sanish reg = (int)(uintptr_t)addr; 13841083Sanish 13851083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13861083Sanish 13871083Sanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 13881083Sanish reg); 13891083Sanish 13901083Sanish return (rval); 13911083Sanish } 13921083Sanish 13931083Sanish void 13941083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 13951083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 13961083Sanish { 13971083Sanish uint8_t *h, *d; 13981083Sanish 13991083Sanish h = host_addr; 14001083Sanish d = dev_addr; 14011083Sanish 14021083Sanish if (flags == DDI_DEV_AUTOINCR) 14031083Sanish for (; repcount; repcount--) 14041083Sanish *h++ = pci_config_rd8(hdlp, d++); 14051083Sanish else 14061083Sanish for (; repcount; repcount--) 14071083Sanish *h++ = pci_config_rd8(hdlp, d); 14081083Sanish } 14091083Sanish 14101083Sanish uint16_t 14111083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 14121083Sanish { 14131083Sanish pci_acc_cfblk_t *cfp; 14141083Sanish uint16_t rval; 14151083Sanish int reg; 14161083Sanish 14171083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14181083Sanish 14191083Sanish reg = (int)(uintptr_t)addr; 14201083Sanish 14211083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14221083Sanish 14231083Sanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 14241083Sanish reg); 14251083Sanish 14261083Sanish return (rval); 14271083Sanish } 14281083Sanish 14291083Sanish void 14301083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 14311083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 14321083Sanish { 14331083Sanish uint16_t *h, *d; 14341083Sanish 14351083Sanish h = host_addr; 14361083Sanish d = dev_addr; 14371083Sanish 14381083Sanish if (flags == DDI_DEV_AUTOINCR) 14391083Sanish for (; repcount; repcount--) 14401083Sanish *h++ = pci_config_rd16(hdlp, d++); 14411083Sanish else 14421083Sanish for (; repcount; repcount--) 14431083Sanish *h++ = pci_config_rd16(hdlp, d); 14441083Sanish } 14451083Sanish 14461083Sanish uint32_t 14471083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 14481083Sanish { 14491083Sanish pci_acc_cfblk_t *cfp; 14501083Sanish uint32_t rval; 14511083Sanish int reg; 14521083Sanish 14531083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14541083Sanish 14551083Sanish reg = (int)(uintptr_t)addr; 14561083Sanish 14571083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14581083Sanish 14591083Sanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 14601083Sanish cfp->c_funcnum, reg); 14611083Sanish 14621083Sanish return (rval); 14631083Sanish } 14641083Sanish 14651083Sanish void 14661083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 14671083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 14681083Sanish { 14691083Sanish uint32_t *h, *d; 14701083Sanish 14711083Sanish h = host_addr; 14721083Sanish d = dev_addr; 14731083Sanish 14741083Sanish if (flags == DDI_DEV_AUTOINCR) 14751083Sanish for (; repcount; repcount--) 14761083Sanish *h++ = pci_config_rd32(hdlp, d++); 14771083Sanish else 14781083Sanish for (; repcount; repcount--) 14791083Sanish *h++ = pci_config_rd32(hdlp, d); 14801083Sanish } 14811083Sanish 14821083Sanish 14831083Sanish void 14841083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 14851083Sanish { 14861083Sanish pci_acc_cfblk_t *cfp; 14871083Sanish int reg; 14881083Sanish 14891083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14901083Sanish 14911083Sanish reg = (int)(uintptr_t)addr; 14921083Sanish 14931083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14941083Sanish 14951083Sanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 14961083Sanish cfp->c_funcnum, reg, value); 14971083Sanish } 14981083Sanish 14991083Sanish void 15001083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 15011083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 15021083Sanish { 15031083Sanish uint8_t *h, *d; 15041083Sanish 15051083Sanish h = host_addr; 15061083Sanish d = dev_addr; 15071083Sanish 15081083Sanish if (flags == DDI_DEV_AUTOINCR) 15091083Sanish for (; repcount; repcount--) 15101083Sanish pci_config_wr8(hdlp, d++, *h++); 15111083Sanish else 15121083Sanish for (; repcount; repcount--) 15131083Sanish pci_config_wr8(hdlp, d, *h++); 15141083Sanish } 15151083Sanish 15161083Sanish void 15171083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 15181083Sanish { 15191083Sanish pci_acc_cfblk_t *cfp; 15201083Sanish int reg; 15211083Sanish 15221083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15231083Sanish 15241083Sanish reg = (int)(uintptr_t)addr; 15251083Sanish 15261083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15271083Sanish 15281083Sanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 15291083Sanish cfp->c_funcnum, reg, value); 15301083Sanish } 15311083Sanish 15321083Sanish void 15331083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 15341083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 15351083Sanish { 15361083Sanish uint16_t *h, *d; 15371083Sanish 15381083Sanish h = host_addr; 15391083Sanish d = dev_addr; 15401083Sanish 15411083Sanish if (flags == DDI_DEV_AUTOINCR) 15421083Sanish for (; repcount; repcount--) 15431083Sanish pci_config_wr16(hdlp, d++, *h++); 15441083Sanish else 15451083Sanish for (; repcount; repcount--) 15461083Sanish pci_config_wr16(hdlp, d, *h++); 15471083Sanish } 15481083Sanish 15491083Sanish void 15501083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 15511083Sanish { 15521083Sanish pci_acc_cfblk_t *cfp; 15531083Sanish int reg; 15541083Sanish 15551083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15561083Sanish 15571083Sanish reg = (int)(uintptr_t)addr; 15581083Sanish 15591083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15601083Sanish 15611083Sanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 15621083Sanish cfp->c_funcnum, reg, value); 15631083Sanish } 15641083Sanish 15651083Sanish void 15661083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 15671083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 15681083Sanish { 15691083Sanish uint32_t *h, *d; 15701083Sanish 15711083Sanish h = host_addr; 15721083Sanish d = dev_addr; 15731083Sanish 15741083Sanish if (flags == DDI_DEV_AUTOINCR) 15751083Sanish for (; repcount; repcount--) 15761083Sanish pci_config_wr32(hdlp, d++, *h++); 15771083Sanish else 15781083Sanish for (; repcount; repcount--) 15791083Sanish pci_config_wr32(hdlp, d, *h++); 15801083Sanish } 15811083Sanish 15821083Sanish uint64_t 15831083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 15841083Sanish { 15851083Sanish uint32_t lw_val; 15861083Sanish uint32_t hi_val; 15871083Sanish uint32_t *dp; 15881083Sanish uint64_t val; 15891083Sanish 15901083Sanish dp = (uint32_t *)addr; 15911083Sanish lw_val = pci_config_rd32(hdlp, dp); 15921083Sanish dp++; 15931083Sanish hi_val = pci_config_rd32(hdlp, dp); 15941083Sanish val = ((uint64_t)hi_val << 32) | lw_val; 15951083Sanish return (val); 15961083Sanish } 15971083Sanish 15981083Sanish void 15991083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 16001083Sanish { 16011083Sanish uint32_t lw_val; 16021083Sanish uint32_t hi_val; 16031083Sanish uint32_t *dp; 16041083Sanish 16051083Sanish dp = (uint32_t *)addr; 16061083Sanish lw_val = (uint32_t)(value & 0xffffffff); 16071083Sanish hi_val = (uint32_t)(value >> 32); 16081083Sanish pci_config_wr32(hdlp, dp, lw_val); 16091083Sanish dp++; 16101083Sanish pci_config_wr32(hdlp, dp, hi_val); 16111083Sanish } 16121083Sanish 16131083Sanish void 16141083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 16151083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 16161083Sanish { 16171083Sanish if (flags == DDI_DEV_AUTOINCR) { 16181083Sanish for (; repcount; repcount--) 16191083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 16201083Sanish } else { 16211083Sanish for (; repcount; repcount--) 16221083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr); 16231083Sanish } 16241083Sanish } 16251083Sanish 16261083Sanish void 16271083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 16281083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 16291083Sanish { 16301083Sanish if (flags == DDI_DEV_AUTOINCR) { 16311083Sanish for (; repcount; repcount--) 16321083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr++); 16331083Sanish } else { 16341083Sanish for (; repcount; repcount--) 16351083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr); 16361083Sanish } 16371083Sanish } 1638