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 /* 238535Sevan.yan@sun.com * Copyright 2009 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 */ 816916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 817916Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 818916Sschwartz hdlp->ih_pri, irq)); 819881Sjohnny 820881Sjohnny /* Add the interrupt handler */ 821881Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 822916Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 823916Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 824881Sjohnny return (DDI_FAILURE); 825881Sjohnny 826916Sschwartz /* Note this really is an irq. */ 827916Sschwartz hdlp->ih_vector = (ushort_t)irq; 828916Sschwartz 829881Sjohnny return (DDI_SUCCESS); 830881Sjohnny } 831881Sjohnny 832881Sjohnny 833881Sjohnny static void 834881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 835881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 836881Sjohnny { 837916Sschwartz int irq; 838881Sjohnny struct intrspec *ispec; 839916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 840881Sjohnny 841881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 842881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 8432288Sanish if (ispec == NULL) 8442288Sanish return; 84510190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 846881Sjohnny ispec->intrspec_vec = inum; 84710190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri; 84810190SSophia.Li@Sun.COM } 849916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 850881Sjohnny 851881Sjohnny /* translate the interrupt if needed */ 852916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 853881Sjohnny 854881Sjohnny /* Disable the interrupt handler */ 855916Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 856916Sschwartz ihdl_plat_datap->ip_ispecp = NULL; 857881Sjohnny } 858881Sjohnny 859881Sjohnny /* 860881Sjohnny * Miscellaneous library function 861881Sjohnny */ 862881Sjohnny int 863881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 864881Sjohnny { 865881Sjohnny int i; 866881Sjohnny int number; 867881Sjohnny int assigned_addr_len; 868881Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi; 869881Sjohnny pci_regspec_t *assigned_addr; 870881Sjohnny 871881Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 872881Sjohnny (phys_hi & PCI_RELOCAT_B)) 873881Sjohnny return (DDI_SUCCESS); 874881Sjohnny 875881Sjohnny /* 876881Sjohnny * the "reg" property specifies relocatable, get and interpret the 877881Sjohnny * "assigned-addresses" property. 878881Sjohnny */ 879881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 880881Sjohnny "assigned-addresses", (int **)&assigned_addr, 881881Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 882881Sjohnny return (DDI_FAILURE); 883881Sjohnny 884881Sjohnny /* 885881Sjohnny * Scan the "assigned-addresses" for one that matches the specified 886881Sjohnny * "reg" property entry. 887881Sjohnny */ 888881Sjohnny phys_hi &= PCI_CONF_ADDR_MASK; 889881Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 890881Sjohnny for (i = 0; i < number; i++) { 891881Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 892881Sjohnny phys_hi) { 893881Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 894881Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 895881Sjohnny ddi_prop_free(assigned_addr); 896881Sjohnny return (DDI_SUCCESS); 897881Sjohnny } 898881Sjohnny } 899881Sjohnny 900881Sjohnny ddi_prop_free(assigned_addr); 901881Sjohnny return (DDI_FAILURE); 902881Sjohnny } 903881Sjohnny 904881Sjohnny 905881Sjohnny /* 906*10923SEvan.Yan@Sun.COM * To handle PCI tool ioctls 907881Sjohnny */ 908881Sjohnny 909*10923SEvan.Yan@Sun.COM /*ARGSUSED*/ 910881Sjohnny int 911881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 912881Sjohnny int mode, cred_t *credp, int *rvalp) 913881Sjohnny { 914*10923SEvan.Yan@Sun.COM minor_t minor = getminor(dev); 915*10923SEvan.Yan@Sun.COM int rv = ENOTTY; 916881Sjohnny 917*10923SEvan.Yan@Sun.COM switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 918881Sjohnny case PCI_TOOL_REG_MINOR_NUM: 919881Sjohnny 920881Sjohnny switch (cmd) { 921881Sjohnny case PCITOOL_DEVICE_SET_REG: 922881Sjohnny case PCITOOL_DEVICE_GET_REG: 923881Sjohnny 924881Sjohnny /* Require full privileges. */ 925881Sjohnny if (secpolicy_kmdb(credp)) 926881Sjohnny rv = EPERM; 927881Sjohnny else 928881Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg, 929881Sjohnny cmd, mode); 930881Sjohnny break; 931881Sjohnny 932881Sjohnny case PCITOOL_NEXUS_SET_REG: 933881Sjohnny case PCITOOL_NEXUS_GET_REG: 934881Sjohnny 935881Sjohnny /* Require full privileges. */ 936881Sjohnny if (secpolicy_kmdb(credp)) 937881Sjohnny rv = EPERM; 938881Sjohnny else 939881Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg, 940881Sjohnny cmd, mode); 941881Sjohnny break; 942881Sjohnny } 943881Sjohnny break; 944881Sjohnny 945881Sjohnny case PCI_TOOL_INTR_MINOR_NUM: 946881Sjohnny 947881Sjohnny switch (cmd) { 948881Sjohnny case PCITOOL_DEVICE_SET_INTR: 949881Sjohnny 950881Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 951881Sjohnny if (secpolicy_ponline(credp)) { 952881Sjohnny rv = EPERM; 953881Sjohnny break; 954881Sjohnny } 955881Sjohnny 956881Sjohnny /*FALLTHRU*/ 957881Sjohnny /* These require no special privileges. */ 958881Sjohnny case PCITOOL_DEVICE_GET_INTR: 9594397Sschwartz case PCITOOL_SYSTEM_INTR_INFO: 960881Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 961881Sjohnny break; 962881Sjohnny } 963881Sjohnny break; 964881Sjohnny 965881Sjohnny default: 966881Sjohnny break; 967881Sjohnny } 968881Sjohnny 969881Sjohnny return (rv); 970881Sjohnny } 9711083Sanish 9721083Sanish 9731865Sdilpreet int 9741865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 9751865Sdilpreet { 9761865Sdilpreet size_t size = in_args->size; 9771865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 9781865Sdilpreet uintptr_t host_addr = in_args->host_addr; 9791865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 9801865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 9811865Sdilpreet size_t repcount = in_args->repcount; 9821865Sdilpreet uint_t flags = in_args->flags; 9831865Sdilpreet int err = DDI_SUCCESS; 9841865Sdilpreet 9851865Sdilpreet /* 9861865Sdilpreet * if no handle then this is a poke. We have to return failure here 9871865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 9881865Sdilpreet */ 9891865Sdilpreet if (in_args->handle == NULL) 9901865Sdilpreet return (DDI_FAILURE); 9911865Sdilpreet 9921865Sdilpreet /* 9931865Sdilpreet * rest of this function is actually for cautious puts 9941865Sdilpreet */ 9951865Sdilpreet for (; repcount; repcount--) { 9961865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 9971865Sdilpreet switch (size) { 9981865Sdilpreet case sizeof (uint8_t): 9991865Sdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr, 10001865Sdilpreet *(uint8_t *)host_addr); 10011865Sdilpreet break; 10021865Sdilpreet case sizeof (uint16_t): 10031865Sdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr, 10041865Sdilpreet *(uint16_t *)host_addr); 10051865Sdilpreet break; 10061865Sdilpreet case sizeof (uint32_t): 10071865Sdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr, 10081865Sdilpreet *(uint32_t *)host_addr); 10091865Sdilpreet break; 10101865Sdilpreet case sizeof (uint64_t): 10111865Sdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr, 10121865Sdilpreet *(uint64_t *)host_addr); 10131865Sdilpreet break; 10141865Sdilpreet default: 10151865Sdilpreet err = DDI_FAILURE; 10161865Sdilpreet break; 10171865Sdilpreet } 10181865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 10191865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 10201865Sdilpreet DDI_STRUCTURE_BE_ACC) { 10211865Sdilpreet switch (size) { 10221865Sdilpreet case sizeof (uint8_t): 10231865Sdilpreet i_ddi_io_put8(hp, 10241865Sdilpreet (uint8_t *)dev_addr, 10251865Sdilpreet *(uint8_t *)host_addr); 10261865Sdilpreet break; 10271865Sdilpreet case sizeof (uint16_t): 10281865Sdilpreet i_ddi_io_swap_put16(hp, 10291865Sdilpreet (uint16_t *)dev_addr, 10301865Sdilpreet *(uint16_t *)host_addr); 10311865Sdilpreet break; 10321865Sdilpreet case sizeof (uint32_t): 10331865Sdilpreet i_ddi_io_swap_put32(hp, 10341865Sdilpreet (uint32_t *)dev_addr, 10351865Sdilpreet *(uint32_t *)host_addr); 10361865Sdilpreet break; 10371865Sdilpreet /* 10381865Sdilpreet * note the 64-bit case is a dummy 10391865Sdilpreet * function - so no need to swap 10401865Sdilpreet */ 10411865Sdilpreet case sizeof (uint64_t): 10421865Sdilpreet i_ddi_io_put64(hp, 10431865Sdilpreet (uint64_t *)dev_addr, 10441865Sdilpreet *(uint64_t *)host_addr); 10451865Sdilpreet break; 10461865Sdilpreet default: 10471865Sdilpreet err = DDI_FAILURE; 10481865Sdilpreet break; 10491865Sdilpreet } 10501865Sdilpreet } else { 10511865Sdilpreet switch (size) { 10521865Sdilpreet case sizeof (uint8_t): 10531865Sdilpreet i_ddi_io_put8(hp, 10541865Sdilpreet (uint8_t *)dev_addr, 10551865Sdilpreet *(uint8_t *)host_addr); 10561865Sdilpreet break; 10571865Sdilpreet case sizeof (uint16_t): 10581865Sdilpreet i_ddi_io_put16(hp, 10591865Sdilpreet (uint16_t *)dev_addr, 10601865Sdilpreet *(uint16_t *)host_addr); 10611865Sdilpreet break; 10621865Sdilpreet case sizeof (uint32_t): 10631865Sdilpreet i_ddi_io_put32(hp, 10641865Sdilpreet (uint32_t *)dev_addr, 10651865Sdilpreet *(uint32_t *)host_addr); 10661865Sdilpreet break; 10671865Sdilpreet case sizeof (uint64_t): 10681865Sdilpreet i_ddi_io_put64(hp, 10691865Sdilpreet (uint64_t *)dev_addr, 10701865Sdilpreet *(uint64_t *)host_addr); 10711865Sdilpreet break; 10721865Sdilpreet default: 10731865Sdilpreet err = DDI_FAILURE; 10741865Sdilpreet break; 10751865Sdilpreet } 10761865Sdilpreet } 10771865Sdilpreet } else { 10781865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 10791865Sdilpreet DDI_STRUCTURE_BE_ACC) { 10801865Sdilpreet switch (size) { 10811865Sdilpreet case sizeof (uint8_t): 10821865Sdilpreet *(uint8_t *)dev_addr = 10831865Sdilpreet *(uint8_t *)host_addr; 10841865Sdilpreet break; 10851865Sdilpreet case sizeof (uint16_t): 10861865Sdilpreet *(uint16_t *)dev_addr = 10871865Sdilpreet ddi_swap16(*(uint16_t *)host_addr); 10881865Sdilpreet break; 10891865Sdilpreet case sizeof (uint32_t): 10901865Sdilpreet *(uint32_t *)dev_addr = 10911865Sdilpreet ddi_swap32(*(uint32_t *)host_addr); 10921865Sdilpreet break; 10931865Sdilpreet case sizeof (uint64_t): 10941865Sdilpreet *(uint64_t *)dev_addr = 10951865Sdilpreet ddi_swap64(*(uint64_t *)host_addr); 10961865Sdilpreet break; 10971865Sdilpreet default: 10981865Sdilpreet err = DDI_FAILURE; 10991865Sdilpreet break; 11001865Sdilpreet } 11011865Sdilpreet } else { 11021865Sdilpreet switch (size) { 11031865Sdilpreet case sizeof (uint8_t): 11041865Sdilpreet *(uint8_t *)dev_addr = 11051865Sdilpreet *(uint8_t *)host_addr; 11061865Sdilpreet break; 11071865Sdilpreet case sizeof (uint16_t): 11081865Sdilpreet *(uint16_t *)dev_addr = 11091865Sdilpreet *(uint16_t *)host_addr; 11101865Sdilpreet break; 11111865Sdilpreet case sizeof (uint32_t): 11121865Sdilpreet *(uint32_t *)dev_addr = 11131865Sdilpreet *(uint32_t *)host_addr; 11141865Sdilpreet break; 11151865Sdilpreet case sizeof (uint64_t): 11161865Sdilpreet *(uint64_t *)dev_addr = 11171865Sdilpreet *(uint64_t *)host_addr; 11181865Sdilpreet break; 11191865Sdilpreet default: 11201865Sdilpreet err = DDI_FAILURE; 11211865Sdilpreet break; 11221865Sdilpreet } 11231865Sdilpreet } 11241865Sdilpreet } 11251865Sdilpreet host_addr += size; 11261865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 11271865Sdilpreet dev_addr += size; 11281865Sdilpreet } 11291865Sdilpreet return (err); 11301865Sdilpreet } 11311865Sdilpreet 11321865Sdilpreet 11331865Sdilpreet int 11341865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 11351865Sdilpreet { 11361865Sdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 11371865Sdilpreet 11381865Sdilpreet /* endian-ness check */ 11391865Sdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 11401865Sdilpreet return (DDI_FAILURE); 11411865Sdilpreet 11421865Sdilpreet /* 11431865Sdilpreet * range check 11441865Sdilpreet */ 11451865Sdilpreet if ((offset >= PCI_CONF_HDR_SIZE) || 11461865Sdilpreet (len > PCI_CONF_HDR_SIZE) || 11471865Sdilpreet (offset + len > PCI_CONF_HDR_SIZE)) 11481865Sdilpreet return (DDI_FAILURE); 11491865Sdilpreet 11501865Sdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 11511865Sdilpreet /* 11521865Sdilpreet * always use cautious mechanism for config space gets 11531865Sdilpreet */ 11541865Sdilpreet ap->ahi_get8 = i_ddi_caut_get8; 11551865Sdilpreet ap->ahi_get16 = i_ddi_caut_get16; 11561865Sdilpreet ap->ahi_get32 = i_ddi_caut_get32; 11571865Sdilpreet ap->ahi_get64 = i_ddi_caut_get64; 11581865Sdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 11591865Sdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 11601865Sdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 11611865Sdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 11621865Sdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 11631865Sdilpreet ap->ahi_put8 = i_ddi_caut_put8; 11641865Sdilpreet ap->ahi_put16 = i_ddi_caut_put16; 11651865Sdilpreet ap->ahi_put32 = i_ddi_caut_put32; 11661865Sdilpreet ap->ahi_put64 = i_ddi_caut_put64; 11671865Sdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 11681865Sdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 11691865Sdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 11701865Sdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 11711865Sdilpreet } else { 11721865Sdilpreet ap->ahi_put8 = pci_config_wr8; 11731865Sdilpreet ap->ahi_put16 = pci_config_wr16; 11741865Sdilpreet ap->ahi_put32 = pci_config_wr32; 11751865Sdilpreet ap->ahi_put64 = pci_config_wr64; 11761865Sdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8; 11771865Sdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16; 11781865Sdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32; 11791865Sdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64; 11801865Sdilpreet } 11811865Sdilpreet 11821865Sdilpreet /* Initialize to default check/notify functions */ 11831865Sdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check; 11841865Sdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify; 11851865Sdilpreet ap->ahi_fault = 0; 11861865Sdilpreet impl_acc_err_init(hp); 11871865Sdilpreet return (DDI_SUCCESS); 11881865Sdilpreet } 11891865Sdilpreet 11901865Sdilpreet 11911865Sdilpreet int 11921865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 11931865Sdilpreet { 11941865Sdilpreet size_t size = in_args->size; 11951865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 11961865Sdilpreet uintptr_t host_addr = in_args->host_addr; 11971865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 11981865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 11991865Sdilpreet size_t repcount = in_args->repcount; 12001865Sdilpreet uint_t flags = in_args->flags; 12011865Sdilpreet int err = DDI_SUCCESS; 12021865Sdilpreet 12031865Sdilpreet /* 12041865Sdilpreet * if no handle then this is a peek. We have to return failure here 12051865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 12061865Sdilpreet */ 12071865Sdilpreet if (in_args->handle == NULL) 12081865Sdilpreet return (DDI_FAILURE); 12091865Sdilpreet 12101865Sdilpreet for (; repcount; repcount--) { 12111865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 12121865Sdilpreet switch (size) { 12131865Sdilpreet case sizeof (uint8_t): 12141865Sdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp, 12151865Sdilpreet (uint8_t *)dev_addr); 12161865Sdilpreet break; 12171865Sdilpreet case sizeof (uint16_t): 12181865Sdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp, 12191865Sdilpreet (uint16_t *)dev_addr); 12201865Sdilpreet break; 12211865Sdilpreet case sizeof (uint32_t): 12221865Sdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp, 12231865Sdilpreet (uint32_t *)dev_addr); 12241865Sdilpreet break; 12251865Sdilpreet case sizeof (uint64_t): 12261865Sdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp, 12271865Sdilpreet (uint64_t *)dev_addr); 12281865Sdilpreet break; 12291865Sdilpreet default: 12301865Sdilpreet err = DDI_FAILURE; 12311865Sdilpreet break; 12321865Sdilpreet } 12331865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 12341865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12351865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12361865Sdilpreet switch (size) { 12371865Sdilpreet case sizeof (uint8_t): 12381865Sdilpreet *(uint8_t *)host_addr = 12391865Sdilpreet i_ddi_io_get8(hp, 12401865Sdilpreet (uint8_t *)dev_addr); 12411865Sdilpreet break; 12421865Sdilpreet case sizeof (uint16_t): 12431865Sdilpreet *(uint16_t *)host_addr = 12441865Sdilpreet i_ddi_io_swap_get16(hp, 12451865Sdilpreet (uint16_t *)dev_addr); 12461865Sdilpreet break; 12471865Sdilpreet case sizeof (uint32_t): 12481865Sdilpreet *(uint32_t *)host_addr = 12491865Sdilpreet i_ddi_io_swap_get32(hp, 12501865Sdilpreet (uint32_t *)dev_addr); 12511865Sdilpreet break; 12521865Sdilpreet /* 12531865Sdilpreet * note the 64-bit case is a dummy 12541865Sdilpreet * function - so no need to swap 12551865Sdilpreet */ 12561865Sdilpreet case sizeof (uint64_t): 12571865Sdilpreet *(uint64_t *)host_addr = 12581865Sdilpreet i_ddi_io_get64(hp, 12591865Sdilpreet (uint64_t *)dev_addr); 12601865Sdilpreet break; 12611865Sdilpreet default: 12621865Sdilpreet err = DDI_FAILURE; 12631865Sdilpreet break; 12641865Sdilpreet } 12651865Sdilpreet } else { 12661865Sdilpreet switch (size) { 12671865Sdilpreet case sizeof (uint8_t): 12681865Sdilpreet *(uint8_t *)host_addr = 12691865Sdilpreet i_ddi_io_get8(hp, 12701865Sdilpreet (uint8_t *)dev_addr); 12711865Sdilpreet break; 12721865Sdilpreet case sizeof (uint16_t): 12731865Sdilpreet *(uint16_t *)host_addr = 12741865Sdilpreet i_ddi_io_get16(hp, 12751865Sdilpreet (uint16_t *)dev_addr); 12761865Sdilpreet break; 12771865Sdilpreet case sizeof (uint32_t): 12781865Sdilpreet *(uint32_t *)host_addr = 12791865Sdilpreet i_ddi_io_get32(hp, 12801865Sdilpreet (uint32_t *)dev_addr); 12811865Sdilpreet break; 12821865Sdilpreet case sizeof (uint64_t): 12831865Sdilpreet *(uint64_t *)host_addr = 12841865Sdilpreet i_ddi_io_get64(hp, 12851865Sdilpreet (uint64_t *)dev_addr); 12861865Sdilpreet break; 12871865Sdilpreet default: 12881865Sdilpreet err = DDI_FAILURE; 12891865Sdilpreet break; 12901865Sdilpreet } 12911865Sdilpreet } 12921865Sdilpreet } else { 12931865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12941865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12951865Sdilpreet switch (in_args->size) { 12961865Sdilpreet case sizeof (uint8_t): 12971865Sdilpreet *(uint8_t *)host_addr = 12981865Sdilpreet *(uint8_t *)dev_addr; 12991865Sdilpreet break; 13001865Sdilpreet case sizeof (uint16_t): 13011865Sdilpreet *(uint16_t *)host_addr = 13021865Sdilpreet ddi_swap16(*(uint16_t *)dev_addr); 13031865Sdilpreet break; 13041865Sdilpreet case sizeof (uint32_t): 13051865Sdilpreet *(uint32_t *)host_addr = 13061865Sdilpreet ddi_swap32(*(uint32_t *)dev_addr); 13071865Sdilpreet break; 13081865Sdilpreet case sizeof (uint64_t): 13091865Sdilpreet *(uint64_t *)host_addr = 13101865Sdilpreet ddi_swap64(*(uint64_t *)dev_addr); 13111865Sdilpreet break; 13121865Sdilpreet default: 13131865Sdilpreet err = DDI_FAILURE; 13141865Sdilpreet break; 13151865Sdilpreet } 13161865Sdilpreet } else { 13171865Sdilpreet switch (in_args->size) { 13181865Sdilpreet case sizeof (uint8_t): 13191865Sdilpreet *(uint8_t *)host_addr = 13201865Sdilpreet *(uint8_t *)dev_addr; 13211865Sdilpreet break; 13221865Sdilpreet case sizeof (uint16_t): 13231865Sdilpreet *(uint16_t *)host_addr = 13241865Sdilpreet *(uint16_t *)dev_addr; 13251865Sdilpreet break; 13261865Sdilpreet case sizeof (uint32_t): 13271865Sdilpreet *(uint32_t *)host_addr = 13281865Sdilpreet *(uint32_t *)dev_addr; 13291865Sdilpreet break; 13301865Sdilpreet case sizeof (uint64_t): 13311865Sdilpreet *(uint64_t *)host_addr = 13321865Sdilpreet *(uint64_t *)dev_addr; 13331865Sdilpreet break; 13341865Sdilpreet default: 13351865Sdilpreet err = DDI_FAILURE; 13361865Sdilpreet break; 13371865Sdilpreet } 13381865Sdilpreet } 13391865Sdilpreet } 13401865Sdilpreet host_addr += size; 13411865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 13421865Sdilpreet dev_addr += size; 13431865Sdilpreet } 13441865Sdilpreet return (err); 13451865Sdilpreet } 13461865Sdilpreet 13471865Sdilpreet /*ARGSUSED*/ 13481865Sdilpreet int 13491865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 13501865Sdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result) 13511865Sdilpreet { 13521865Sdilpreet if (ctlop == DDI_CTLOPS_PEEK) 13531865Sdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 13541865Sdilpreet else 13551865Sdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 13561865Sdilpreet } 13571865Sdilpreet 13581083Sanish /* 13591083Sanish * These are the get and put functions to be shared with drivers. The 13601083Sanish * mutex locking is done inside the functions referenced, rather than 13611083Sanish * here, and is thus shared across PCI child drivers and any other 13621083Sanish * consumers of PCI config space (such as the ACPI subsystem). 13631083Sanish * 13641083Sanish * The configuration space addresses come in as pointers. This is fine on 13651083Sanish * a 32-bit system, where the VM space and configuration space are the same 13661083Sanish * size. It's not such a good idea on a 64-bit system, where memory 13671083Sanish * addresses are twice as large as configuration space addresses. At some 13681083Sanish * point in the call tree we need to take a stand and say "you are 32-bit 13691083Sanish * from this time forth", and this seems like a nice self-contained place. 13701083Sanish */ 13711083Sanish 13721083Sanish uint8_t 13731083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 13741083Sanish { 13751083Sanish pci_acc_cfblk_t *cfp; 13761083Sanish uint8_t rval; 13771083Sanish int reg; 13781083Sanish 13791083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13801083Sanish 13811083Sanish reg = (int)(uintptr_t)addr; 13821083Sanish 13831083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13841083Sanish 13851083Sanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 13861083Sanish reg); 13871083Sanish 13881083Sanish return (rval); 13891083Sanish } 13901083Sanish 13911083Sanish void 13921083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 13931083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 13941083Sanish { 13951083Sanish uint8_t *h, *d; 13961083Sanish 13971083Sanish h = host_addr; 13981083Sanish d = dev_addr; 13991083Sanish 14001083Sanish if (flags == DDI_DEV_AUTOINCR) 14011083Sanish for (; repcount; repcount--) 14021083Sanish *h++ = pci_config_rd8(hdlp, d++); 14031083Sanish else 14041083Sanish for (; repcount; repcount--) 14051083Sanish *h++ = pci_config_rd8(hdlp, d); 14061083Sanish } 14071083Sanish 14081083Sanish uint16_t 14091083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 14101083Sanish { 14111083Sanish pci_acc_cfblk_t *cfp; 14121083Sanish uint16_t rval; 14131083Sanish int reg; 14141083Sanish 14151083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14161083Sanish 14171083Sanish reg = (int)(uintptr_t)addr; 14181083Sanish 14191083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14201083Sanish 14211083Sanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 14221083Sanish reg); 14231083Sanish 14241083Sanish return (rval); 14251083Sanish } 14261083Sanish 14271083Sanish void 14281083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 14291083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 14301083Sanish { 14311083Sanish uint16_t *h, *d; 14321083Sanish 14331083Sanish h = host_addr; 14341083Sanish d = dev_addr; 14351083Sanish 14361083Sanish if (flags == DDI_DEV_AUTOINCR) 14371083Sanish for (; repcount; repcount--) 14381083Sanish *h++ = pci_config_rd16(hdlp, d++); 14391083Sanish else 14401083Sanish for (; repcount; repcount--) 14411083Sanish *h++ = pci_config_rd16(hdlp, d); 14421083Sanish } 14431083Sanish 14441083Sanish uint32_t 14451083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 14461083Sanish { 14471083Sanish pci_acc_cfblk_t *cfp; 14481083Sanish uint32_t rval; 14491083Sanish int reg; 14501083Sanish 14511083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14521083Sanish 14531083Sanish reg = (int)(uintptr_t)addr; 14541083Sanish 14551083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14561083Sanish 14571083Sanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 14581083Sanish cfp->c_funcnum, reg); 14591083Sanish 14601083Sanish return (rval); 14611083Sanish } 14621083Sanish 14631083Sanish void 14641083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 14651083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 14661083Sanish { 14671083Sanish uint32_t *h, *d; 14681083Sanish 14691083Sanish h = host_addr; 14701083Sanish d = dev_addr; 14711083Sanish 14721083Sanish if (flags == DDI_DEV_AUTOINCR) 14731083Sanish for (; repcount; repcount--) 14741083Sanish *h++ = pci_config_rd32(hdlp, d++); 14751083Sanish else 14761083Sanish for (; repcount; repcount--) 14771083Sanish *h++ = pci_config_rd32(hdlp, d); 14781083Sanish } 14791083Sanish 14801083Sanish 14811083Sanish void 14821083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 14831083Sanish { 14841083Sanish pci_acc_cfblk_t *cfp; 14851083Sanish int reg; 14861083Sanish 14871083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14881083Sanish 14891083Sanish reg = (int)(uintptr_t)addr; 14901083Sanish 14911083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14921083Sanish 14931083Sanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 14941083Sanish cfp->c_funcnum, reg, value); 14951083Sanish } 14961083Sanish 14971083Sanish void 14981083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 14991083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 15001083Sanish { 15011083Sanish uint8_t *h, *d; 15021083Sanish 15031083Sanish h = host_addr; 15041083Sanish d = dev_addr; 15051083Sanish 15061083Sanish if (flags == DDI_DEV_AUTOINCR) 15071083Sanish for (; repcount; repcount--) 15081083Sanish pci_config_wr8(hdlp, d++, *h++); 15091083Sanish else 15101083Sanish for (; repcount; repcount--) 15111083Sanish pci_config_wr8(hdlp, d, *h++); 15121083Sanish } 15131083Sanish 15141083Sanish void 15151083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 15161083Sanish { 15171083Sanish pci_acc_cfblk_t *cfp; 15181083Sanish int reg; 15191083Sanish 15201083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15211083Sanish 15221083Sanish reg = (int)(uintptr_t)addr; 15231083Sanish 15241083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15251083Sanish 15261083Sanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 15271083Sanish cfp->c_funcnum, reg, value); 15281083Sanish } 15291083Sanish 15301083Sanish void 15311083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 15321083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 15331083Sanish { 15341083Sanish uint16_t *h, *d; 15351083Sanish 15361083Sanish h = host_addr; 15371083Sanish d = dev_addr; 15381083Sanish 15391083Sanish if (flags == DDI_DEV_AUTOINCR) 15401083Sanish for (; repcount; repcount--) 15411083Sanish pci_config_wr16(hdlp, d++, *h++); 15421083Sanish else 15431083Sanish for (; repcount; repcount--) 15441083Sanish pci_config_wr16(hdlp, d, *h++); 15451083Sanish } 15461083Sanish 15471083Sanish void 15481083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 15491083Sanish { 15501083Sanish pci_acc_cfblk_t *cfp; 15511083Sanish int reg; 15521083Sanish 15531083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15541083Sanish 15551083Sanish reg = (int)(uintptr_t)addr; 15561083Sanish 15571083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15581083Sanish 15591083Sanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 15601083Sanish cfp->c_funcnum, reg, value); 15611083Sanish } 15621083Sanish 15631083Sanish void 15641083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 15651083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 15661083Sanish { 15671083Sanish uint32_t *h, *d; 15681083Sanish 15691083Sanish h = host_addr; 15701083Sanish d = dev_addr; 15711083Sanish 15721083Sanish if (flags == DDI_DEV_AUTOINCR) 15731083Sanish for (; repcount; repcount--) 15741083Sanish pci_config_wr32(hdlp, d++, *h++); 15751083Sanish else 15761083Sanish for (; repcount; repcount--) 15771083Sanish pci_config_wr32(hdlp, d, *h++); 15781083Sanish } 15791083Sanish 15801083Sanish uint64_t 15811083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 15821083Sanish { 15831083Sanish uint32_t lw_val; 15841083Sanish uint32_t hi_val; 15851083Sanish uint32_t *dp; 15861083Sanish uint64_t val; 15871083Sanish 15881083Sanish dp = (uint32_t *)addr; 15891083Sanish lw_val = pci_config_rd32(hdlp, dp); 15901083Sanish dp++; 15911083Sanish hi_val = pci_config_rd32(hdlp, dp); 15921083Sanish val = ((uint64_t)hi_val << 32) | lw_val; 15931083Sanish return (val); 15941083Sanish } 15951083Sanish 15961083Sanish void 15971083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 15981083Sanish { 15991083Sanish uint32_t lw_val; 16001083Sanish uint32_t hi_val; 16011083Sanish uint32_t *dp; 16021083Sanish 16031083Sanish dp = (uint32_t *)addr; 16041083Sanish lw_val = (uint32_t)(value & 0xffffffff); 16051083Sanish hi_val = (uint32_t)(value >> 32); 16061083Sanish pci_config_wr32(hdlp, dp, lw_val); 16071083Sanish dp++; 16081083Sanish pci_config_wr32(hdlp, dp, hi_val); 16091083Sanish } 16101083Sanish 16111083Sanish void 16121083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 16131083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 16141083Sanish { 16151083Sanish if (flags == DDI_DEV_AUTOINCR) { 16161083Sanish for (; repcount; repcount--) 16171083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 16181083Sanish } else { 16191083Sanish for (; repcount; repcount--) 16201083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr); 16211083Sanish } 16221083Sanish } 16231083Sanish 16241083Sanish void 16251083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 16261083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 16271083Sanish { 16281083Sanish if (flags == DDI_DEV_AUTOINCR) { 16291083Sanish for (; repcount; repcount--) 16301083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr++); 16311083Sanish } else { 16321083Sanish for (; repcount; repcount--) 16331083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr); 16341083Sanish } 16351083Sanish } 1636