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/hotplug/pci/pcihp.h> 41881Sjohnny #include <sys/pci_intr_lib.h> 42881Sjohnny #include <sys/psm.h> 43881Sjohnny #include <sys/policy.h> 44881Sjohnny #include <sys/sysmacros.h> 45916Sschwartz #include <sys/clock.h> 463446Smrj #include <sys/apic.h> 47881Sjohnny #include <sys/pci_tools.h> 48881Sjohnny #include <io/pci/pci_var.h> 49881Sjohnny #include <io/pci/pci_tools_ext.h> 50881Sjohnny #include <io/pci/pci_common.h> 511083Sanish #include <sys/pci_cfgspace.h> 521083Sanish #include <sys/pci_impl.h> 534160Sjveta #include <sys/pci_cap.h> 54881Sjohnny 55881Sjohnny /* 56881Sjohnny * Function prototypes 57881Sjohnny */ 58881Sjohnny static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *); 59881Sjohnny static int pci_enable_intr(dev_info_t *, dev_info_t *, 60881Sjohnny ddi_intr_handle_impl_t *, uint32_t); 61881Sjohnny static void pci_disable_intr(dev_info_t *, dev_info_t *, 62881Sjohnny ddi_intr_handle_impl_t *, uint32_t); 63881Sjohnny 64881Sjohnny /* Extern decalration for pcplusmp module */ 65881Sjohnny extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 66881Sjohnny psm_intr_op_t, int *); 67881Sjohnny 68881Sjohnny /* 69881Sjohnny * pci_name_child: 70881Sjohnny * 71881Sjohnny * Assign the address portion of the node name 72881Sjohnny */ 73881Sjohnny int 74881Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen) 75881Sjohnny { 76881Sjohnny int dev, func, length; 77881Sjohnny char **unit_addr; 78881Sjohnny uint_t n; 79881Sjohnny pci_regspec_t *pci_rp; 80881Sjohnny 81881Sjohnny if (ndi_dev_is_persistent_node(child) == 0) { 82881Sjohnny /* 83881Sjohnny * For .conf node, use "unit-address" property 84881Sjohnny */ 85881Sjohnny if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 86881Sjohnny DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 87881Sjohnny DDI_PROP_SUCCESS) { 88881Sjohnny cmn_err(CE_WARN, "cannot find unit-address in %s.conf", 89881Sjohnny ddi_get_name(child)); 90881Sjohnny return (DDI_FAILURE); 91881Sjohnny } 92881Sjohnny if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 93881Sjohnny cmn_err(CE_WARN, "unit-address property in %s.conf" 94881Sjohnny " not well-formed", ddi_get_name(child)); 95881Sjohnny ddi_prop_free(unit_addr); 96881Sjohnny return (DDI_FAILURE); 97881Sjohnny } 98881Sjohnny (void) snprintf(name, namelen, "%s", *unit_addr); 99881Sjohnny ddi_prop_free(unit_addr); 100881Sjohnny return (DDI_SUCCESS); 101881Sjohnny } 102881Sjohnny 103881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 104881Sjohnny "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) { 105881Sjohnny cmn_err(CE_WARN, "cannot find reg property in %s", 106881Sjohnny ddi_get_name(child)); 107881Sjohnny return (DDI_FAILURE); 108881Sjohnny } 109881Sjohnny 110881Sjohnny /* copy the device identifications */ 111881Sjohnny dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 112881Sjohnny func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 113881Sjohnny 114881Sjohnny /* 115881Sjohnny * free the memory allocated by ddi_prop_lookup_int_array 116881Sjohnny */ 117881Sjohnny ddi_prop_free(pci_rp); 118881Sjohnny 119881Sjohnny if (func != 0) { 120881Sjohnny (void) snprintf(name, namelen, "%x,%x", dev, func); 121881Sjohnny } else { 122881Sjohnny (void) snprintf(name, namelen, "%x", dev); 123881Sjohnny } 124881Sjohnny 125881Sjohnny return (DDI_SUCCESS); 126881Sjohnny } 127881Sjohnny 128881Sjohnny /* 129881Sjohnny * Interrupt related code: 130881Sjohnny * 131881Sjohnny * The following busop is common to npe and pci drivers 132881Sjohnny * bus_introp 133881Sjohnny */ 134881Sjohnny 135881Sjohnny /* 136881Sjohnny * Create the ddi_parent_private_data for a pseudo child. 137881Sjohnny */ 138881Sjohnny void 139881Sjohnny pci_common_set_parent_private_data(dev_info_t *dip) 140881Sjohnny { 141881Sjohnny struct ddi_parent_private_data *pdptr; 142881Sjohnny 143881Sjohnny pdptr = (struct ddi_parent_private_data *)kmem_zalloc( 144881Sjohnny (sizeof (struct ddi_parent_private_data) + 1454397Sschwartz sizeof (struct intrspec)), KM_SLEEP); 146881Sjohnny pdptr->par_intr = (struct intrspec *)(pdptr + 1); 147881Sjohnny pdptr->par_nintr = 1; 148881Sjohnny ddi_set_parent_data(dip, pdptr); 149881Sjohnny } 150881Sjohnny 151881Sjohnny /* 152881Sjohnny * pci_get_priority: 153881Sjohnny * Figure out the priority of the device 154881Sjohnny */ 155881Sjohnny static int 156881Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri) 157881Sjohnny { 158881Sjohnny struct intrspec *ispec; 159881Sjohnny 160881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n", 161881Sjohnny (void *)dip, (void *)hdlp)); 162881Sjohnny 163881Sjohnny if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 164881Sjohnny hdlp->ih_inum)) == NULL) { 165881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 1668535Sevan.yan@sun.com *pri = pci_class_to_pil(dip); 167881Sjohnny pci_common_set_parent_private_data(hdlp->ih_dip); 168881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 169881Sjohnny hdlp->ih_inum); 170881Sjohnny return (DDI_SUCCESS); 171881Sjohnny } 172881Sjohnny return (DDI_FAILURE); 173881Sjohnny } 174881Sjohnny 175881Sjohnny *pri = ispec->intrspec_pri; 176881Sjohnny return (DDI_SUCCESS); 177881Sjohnny } 178881Sjohnny 179881Sjohnny 180881Sjohnny 18110187SKrishna.Elango@Sun.COM static int pcieb_intr_pri_counter = 0; 182881Sjohnny 183881Sjohnny /* 184881Sjohnny * pci_common_intr_ops: bus_intr_op() function for interrupt support 185881Sjohnny */ 186881Sjohnny int 187881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 188881Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 189881Sjohnny { 190881Sjohnny int priority = 0; 191881Sjohnny int psm_status = 0; 192881Sjohnny int pci_status = 0; 193881Sjohnny int pci_rval, psm_rval = PSM_FAILURE; 194881Sjohnny int types = 0; 195881Sjohnny int pciepci = 0; 1961542Sjohnny int i, j, count; 1974160Sjveta int rv; 198881Sjohnny int behavior; 1991997Sanish int cap_ptr; 2004160Sjveta uint16_t msi_cap_base, msix_cap_base, cap_ctrl; 2014160Sjveta char *prop; 202881Sjohnny ddi_intrspec_t isp; 203881Sjohnny struct intrspec *ispec; 204881Sjohnny ddi_intr_handle_impl_t tmp_hdl; 205881Sjohnny ddi_intr_msix_t *msix_p; 2061087Sschwartz ihdl_plat_t *ihdl_plat_datap; 2071542Sjohnny ddi_intr_handle_t *h_array; 2081997Sanish ddi_acc_handle_t handle; 209881Sjohnny 210881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 211881Sjohnny "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 212881Sjohnny (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 213881Sjohnny 214881Sjohnny /* Process the request */ 215881Sjohnny switch (intr_op) { 216881Sjohnny case DDI_INTROP_SUPPORTED_TYPES: 2174160Sjveta /* 2184160Sjveta * First we determine the interrupt types supported by the 2194160Sjveta * device itself, then we filter them through what the OS 2204160Sjveta * and system supports. We determine system-level 2214160Sjveta * interrupt type support for anything other than fixed intrs 2224160Sjveta * through the psm_intr_ops vector 2234160Sjveta */ 2244160Sjveta rv = DDI_FAILURE; 2254160Sjveta 226881Sjohnny /* Fixed supported by default */ 2274160Sjveta types = DDI_INTR_TYPE_FIXED; 2284160Sjveta 2294160Sjveta if (psm_intr_ops == NULL) { 2304160Sjveta *(int *)result = types; 2314160Sjveta return (DDI_SUCCESS); 2324160Sjveta } 2334160Sjveta if (pci_config_setup(rdip, &handle) != DDI_SUCCESS) 2344160Sjveta return (DDI_FAILURE); 235881Sjohnny 2364160Sjveta /* Sanity test cap control values if found */ 2374160Sjveta 2384160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) == 2394160Sjveta DDI_SUCCESS) { 2404160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base, 2414160Sjveta PCI_MSI_CTRL); 2424160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 2434160Sjveta goto SUPPORTED_TYPES_OUT; 2444160Sjveta 2454160Sjveta types |= DDI_INTR_TYPE_MSI; 2464160Sjveta } 2474160Sjveta 2484160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) == 2494160Sjveta DDI_SUCCESS) { 2504160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base, 2514160Sjveta PCI_MSIX_CTRL); 2524160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 2534160Sjveta goto SUPPORTED_TYPES_OUT; 254881Sjohnny 2554160Sjveta types |= DDI_INTR_TYPE_MSIX; 2564160Sjveta } 2574160Sjveta 2584160Sjveta /* 2594160Sjveta * Filter device-level types through system-level support 2604160Sjveta */ 2614160Sjveta tmp_hdl.ih_type = types; 2624160Sjveta if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI, 2634160Sjveta &types) != PSM_SUCCESS) 2644160Sjveta goto SUPPORTED_TYPES_OUT; 2654160Sjveta 2664160Sjveta DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 2674160Sjveta "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, 2684160Sjveta *(int *)result)); 269881Sjohnny 2704160Sjveta /* 2714160Sjveta * Export any MSI/MSI-X cap locations via properties 2724160Sjveta */ 2734160Sjveta if (types & DDI_INTR_TYPE_MSI) { 2744160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 2754160Sjveta "pci-msi-capid-pointer", (int)msi_cap_base) != 2764160Sjveta DDI_PROP_SUCCESS) 2774160Sjveta goto SUPPORTED_TYPES_OUT; 278881Sjohnny } 2794160Sjveta if (types & DDI_INTR_TYPE_MSIX) { 2804160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 2814160Sjveta "pci-msix-capid-pointer", (int)msix_cap_base) != 2824160Sjveta DDI_PROP_SUCCESS) 2834160Sjveta goto SUPPORTED_TYPES_OUT; 2844160Sjveta } 2854160Sjveta 2864160Sjveta rv = DDI_SUCCESS; 2874160Sjveta 2884160Sjveta SUPPORTED_TYPES_OUT: 2894160Sjveta *(int *)result = types; 2904160Sjveta pci_config_teardown(&handle); 2914160Sjveta return (rv); 2924160Sjveta 2932580Sanish case DDI_INTROP_NAVAIL: 294881Sjohnny case DDI_INTROP_NINTRS: 2952580Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 2962580Sanish if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type, 2972580Sanish result) != DDI_SUCCESS) 2982580Sanish return (DDI_FAILURE); 2992580Sanish } else { 3002580Sanish *(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip); 3012580Sanish if (*(int *)result == 0) 3022580Sanish return (DDI_FAILURE); 3032580Sanish } 304881Sjohnny break; 305881Sjohnny case DDI_INTROP_ALLOC: 306881Sjohnny /* 307881Sjohnny * MSI or MSIX (figure out number of vectors available) 308881Sjohnny * FIXED interrupts: just return available interrupts 309881Sjohnny */ 310881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 311881Sjohnny (psm_intr_ops != NULL) && 312881Sjohnny (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) { 313881Sjohnny /* 31410187SKrishna.Elango@Sun.COM * Following check is a special case for 'pcieb'. 315881Sjohnny * This makes sure vectors with the right priority 31610187SKrishna.Elango@Sun.COM * are allocated for pcieb during ALLOC time. 317881Sjohnny */ 31810187SKrishna.Elango@Sun.COM if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) { 319881Sjohnny hdlp->ih_pri = 32010187SKrishna.Elango@Sun.COM (pcieb_intr_pri_counter % 2) ? 4 : 7; 321881Sjohnny pciepci = 1; 322881Sjohnny } else 323881Sjohnny hdlp->ih_pri = priority; 3241717Swesolows behavior = (int)(uintptr_t)hdlp->ih_scratch2; 3251997Sanish 3261997Sanish /* 3271997Sanish * Cache in the config handle and cap_ptr 3281997Sanish */ 3291997Sanish if (i_ddi_get_pci_config_handle(rdip) == NULL) { 3301997Sanish if (pci_config_setup(rdip, &handle) != 3311997Sanish DDI_SUCCESS) 3321997Sanish return (DDI_FAILURE); 3331997Sanish i_ddi_set_pci_config_handle(rdip, handle); 3341997Sanish } 3351997Sanish 3364160Sjveta prop = NULL; 3374160Sjveta cap_ptr = 0; 3384160Sjveta if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 3394160Sjveta prop = "pci-msi-capid-pointer"; 3404160Sjveta else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) 3414160Sjveta prop = "pci-msix-capid-pointer"; 3421997Sanish 3434160Sjveta /* 3444160Sjveta * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES 3454160Sjveta * for MSI(X) before allocation 3464160Sjveta */ 3474160Sjveta if (prop != NULL) { 3481997Sanish cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 3494160Sjveta DDI_PROP_DONTPASS, prop, 0); 3504160Sjveta if (cap_ptr == 0) { 3514160Sjveta DDI_INTR_NEXDBG((CE_CONT, 3524160Sjveta "pci_common_intr_ops: rdip: 0x%p " 3534160Sjveta "attempted MSI(X) alloc without " 3544160Sjveta "cap property\n", (void *)rdip)); 3554160Sjveta return (DDI_FAILURE); 3564160Sjveta } 3571997Sanish } 3584160Sjveta i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); 3591997Sanish 3604160Sjveta /* 3614160Sjveta * Allocate interrupt vectors 3624160Sjveta */ 363881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 364881Sjohnny PSM_INTR_OP_ALLOC_VECTORS, result); 365881Sjohnny 3663112Sanish if (*(int *)result == 0) 3673112Sanish return (DDI_INTR_NOTFOUND); 3683112Sanish 369881Sjohnny /* verify behavior flag and take appropriate action */ 370881Sjohnny if ((behavior == DDI_INTR_ALLOC_STRICT) && 371881Sjohnny (*(int *)result < hdlp->ih_scratch1)) { 372881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 373881Sjohnny "pci_common_intr_ops: behavior %x, " 374881Sjohnny "couldn't get enough intrs\n", behavior)); 375881Sjohnny hdlp->ih_scratch1 = *(int *)result; 376881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 377881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 378881Sjohnny return (DDI_EAGAIN); 379881Sjohnny } 380881Sjohnny 381881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 382881Sjohnny if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 383881Sjohnny msix_p = pci_msix_init(hdlp->ih_dip); 384881Sjohnny if (msix_p) 385881Sjohnny i_ddi_set_msix(hdlp->ih_dip, 386881Sjohnny msix_p); 387881Sjohnny } 388881Sjohnny } 389881Sjohnny 390881Sjohnny if (pciepci) { 391881Sjohnny /* update priority in ispec */ 392881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, 3934397Sschwartz (int)hdlp->ih_inum); 394881Sjohnny ispec = (struct intrspec *)isp; 395881Sjohnny if (ispec) 396881Sjohnny ispec->intrspec_pri = hdlp->ih_pri; 39710187SKrishna.Elango@Sun.COM ++pcieb_intr_pri_counter; 398881Sjohnny } 399881Sjohnny 400881Sjohnny } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 401881Sjohnny /* Figure out if this device supports MASKING */ 402881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 403881Sjohnny if (pci_rval == DDI_SUCCESS && pci_status) 404881Sjohnny hdlp->ih_cap |= pci_status; 405881Sjohnny *(int *)result = 1; /* DDI_INTR_TYPE_FIXED */ 406881Sjohnny } else 407881Sjohnny return (DDI_FAILURE); 408881Sjohnny break; 409881Sjohnny case DDI_INTROP_FREE: 410881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 411881Sjohnny (psm_intr_ops != NULL)) { 4122018Sanish if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 == 4132018Sanish 0) { 4141997Sanish if (handle = i_ddi_get_pci_config_handle( 4151997Sanish rdip)) { 4161997Sanish (void) pci_config_teardown(&handle); 4171997Sanish i_ddi_set_pci_config_handle(rdip, NULL); 4181997Sanish } 4191997Sanish if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip)) 4201997Sanish i_ddi_set_msi_msix_cap_ptr(rdip, 0); 4211997Sanish } 4221997Sanish 423881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 424881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 425881Sjohnny 426881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 427881Sjohnny msix_p = i_ddi_get_msix(hdlp->ih_dip); 428881Sjohnny if (msix_p && 4292018Sanish (i_ddi_intr_get_current_nintrs( 4304397Sschwartz hdlp->ih_dip) - 1) == 0) { 431881Sjohnny pci_msix_fini(msix_p); 432881Sjohnny i_ddi_set_msix(hdlp->ih_dip, NULL); 433881Sjohnny } 434881Sjohnny } 435881Sjohnny } 436881Sjohnny break; 437881Sjohnny case DDI_INTROP_GETPRI: 438881Sjohnny /* Get the priority */ 439881Sjohnny if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS) 440881Sjohnny return (DDI_FAILURE); 441881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 442881Sjohnny "priority = 0x%x\n", priority)); 443881Sjohnny *(int *)result = priority; 444881Sjohnny break; 445881Sjohnny case DDI_INTROP_SETPRI: 446881Sjohnny /* Validate the interrupt priority passed */ 447881Sjohnny if (*(int *)result > LOCK_LEVEL) 448881Sjohnny return (DDI_FAILURE); 449881Sjohnny 450881Sjohnny /* Ensure that PSM is all initialized */ 451881Sjohnny if (psm_intr_ops == NULL) 452881Sjohnny return (DDI_FAILURE); 453881Sjohnny 454*10190SSophia.Li@Sun.COM isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 455*10190SSophia.Li@Sun.COM ispec = (struct intrspec *)isp; 456*10190SSophia.Li@Sun.COM if (ispec == NULL) 457*10190SSophia.Li@Sun.COM return (DDI_FAILURE); 458*10190SSophia.Li@Sun.COM 459*10190SSophia.Li@Sun.COM /* For fixed interrupts */ 460*10190SSophia.Li@Sun.COM if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 461*10190SSophia.Li@Sun.COM /* if interrupt is shared, return failure */ 462*10190SSophia.Li@Sun.COM ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 463*10190SSophia.Li@Sun.COM psm_rval = (*psm_intr_ops)(rdip, hdlp, 464*10190SSophia.Li@Sun.COM PSM_INTR_OP_GET_SHARED, &psm_status); 465*10190SSophia.Li@Sun.COM /* 466*10190SSophia.Li@Sun.COM * For fixed interrupts, the irq may not have been 467*10190SSophia.Li@Sun.COM * allocated when SET_PRI is called, and the above 468*10190SSophia.Li@Sun.COM * GET_SHARED op may return PSM_FAILURE. This is not 469*10190SSophia.Li@Sun.COM * a real error and is ignored below. 470*10190SSophia.Li@Sun.COM */ 471*10190SSophia.Li@Sun.COM if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) { 472*10190SSophia.Li@Sun.COM DDI_INTR_NEXDBG((CE_CONT, 473*10190SSophia.Li@Sun.COM "pci_common_intr_ops: " 474*10190SSophia.Li@Sun.COM "dip 0x%p cannot setpri, psm_rval=%d," 475*10190SSophia.Li@Sun.COM "psm_status=%d\n", (void *)rdip, psm_rval, 476*10190SSophia.Li@Sun.COM psm_status)); 477*10190SSophia.Li@Sun.COM return (DDI_FAILURE); 478*10190SSophia.Li@Sun.COM } 479*10190SSophia.Li@Sun.COM } 480*10190SSophia.Li@Sun.COM 481881Sjohnny /* Change the priority */ 482881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 483881Sjohnny PSM_FAILURE) 484881Sjohnny return (DDI_FAILURE); 485881Sjohnny 486881Sjohnny /* update ispec */ 487*10190SSophia.Li@Sun.COM ispec->intrspec_pri = *(int *)result; 488881Sjohnny break; 489881Sjohnny case DDI_INTROP_ADDISR: 490881Sjohnny /* update ispec */ 491881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 492881Sjohnny ispec = (struct intrspec *)isp; 4931087Sschwartz if (ispec) { 494881Sjohnny ispec->intrspec_func = hdlp->ih_cb_func; 4951087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 4961087Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 4971087Sschwartz } 498881Sjohnny break; 499881Sjohnny case DDI_INTROP_REMISR: 500881Sjohnny /* Get the interrupt structure pointer */ 501881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 502881Sjohnny ispec = (struct intrspec *)isp; 5031087Sschwartz if (ispec) { 504881Sjohnny ispec->intrspec_func = (uint_t (*)()) 0; 5051087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 5061087Sschwartz if (ihdl_plat_datap->ip_ksp != NULL) 5071087Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp); 5081087Sschwartz } 509881Sjohnny break; 510881Sjohnny case DDI_INTROP_GETCAP: 511881Sjohnny /* 512881Sjohnny * First check the config space and/or 513881Sjohnny * MSI capability register(s) 514881Sjohnny */ 515881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 516881Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 517881Sjohnny &pci_status); 518881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 519881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 520881Sjohnny 521881Sjohnny /* next check with pcplusmp */ 522881Sjohnny if (psm_intr_ops != NULL) 523881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 524881Sjohnny PSM_INTR_OP_GET_CAP, &psm_status); 525881Sjohnny 526881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 527881Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n", 528881Sjohnny psm_rval, psm_status, pci_rval, pci_status)); 529881Sjohnny 530881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 531881Sjohnny *(int *)result = 0; 532881Sjohnny return (DDI_FAILURE); 533881Sjohnny } 534881Sjohnny 535881Sjohnny if (psm_rval == PSM_SUCCESS) 536881Sjohnny *(int *)result = psm_status; 537881Sjohnny 538881Sjohnny if (pci_rval == DDI_SUCCESS) 539881Sjohnny *(int *)result |= pci_status; 540881Sjohnny 541881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 542881Sjohnny *(int *)result)); 543881Sjohnny break; 544881Sjohnny case DDI_INTROP_SETCAP: 545881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 546881Sjohnny "SETCAP cap=0x%x\n", *(int *)result)); 547881Sjohnny if (psm_intr_ops == NULL) 548881Sjohnny return (DDI_FAILURE); 549881Sjohnny 550881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 551881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 552881Sjohnny " returned failure\n")); 553881Sjohnny return (DDI_FAILURE); 554881Sjohnny } 555881Sjohnny break; 556881Sjohnny case DDI_INTROP_ENABLE: 557881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 558881Sjohnny if (psm_intr_ops == NULL) 559881Sjohnny return (DDI_FAILURE); 560881Sjohnny 561881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 562881Sjohnny DDI_SUCCESS) 563881Sjohnny return (DDI_FAILURE); 564881Sjohnny 565881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 566881Sjohnny "vector=0x%x\n", hdlp->ih_vector)); 567881Sjohnny break; 568881Sjohnny case DDI_INTROP_DISABLE: 569881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 570881Sjohnny if (psm_intr_ops == NULL) 571881Sjohnny return (DDI_FAILURE); 572881Sjohnny 573881Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 574881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 575881Sjohnny "vector = %x\n", hdlp->ih_vector)); 576881Sjohnny break; 577881Sjohnny case DDI_INTROP_BLOCKENABLE: 578881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 579881Sjohnny "BLOCKENABLE\n")); 580881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 581881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 582881Sjohnny return (DDI_FAILURE); 583881Sjohnny } 584881Sjohnny 585881Sjohnny /* Check if psm_intr_ops is NULL? */ 586881Sjohnny if (psm_intr_ops == NULL) 587881Sjohnny return (DDI_FAILURE); 588881Sjohnny 5891542Sjohnny count = hdlp->ih_scratch1; 5901542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 5911542Sjohnny for (i = 0; i < count; i++) { 5921542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 593881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, 5941542Sjohnny hdlp->ih_inum) != DDI_SUCCESS) { 595881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 596881Sjohnny "pci_enable_intr failed for %d\n", i)); 5971542Sjohnny for (j = 0; j < i; j++) { 5984397Sschwartz hdlp = (ddi_intr_handle_impl_t *) 5994397Sschwartz h_array[j]; 6004397Sschwartz pci_disable_intr(pdip, rdip, hdlp, 6011542Sjohnny hdlp->ih_inum); 6021542Sjohnny } 603881Sjohnny return (DDI_FAILURE); 604881Sjohnny } 605881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 6061542Sjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 607881Sjohnny } 608881Sjohnny break; 609881Sjohnny case DDI_INTROP_BLOCKDISABLE: 610881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 611881Sjohnny "BLOCKDISABLE\n")); 612881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 613881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 614881Sjohnny return (DDI_FAILURE); 615881Sjohnny } 616881Sjohnny 617881Sjohnny /* Check if psm_intr_ops is present */ 618881Sjohnny if (psm_intr_ops == NULL) 619881Sjohnny return (DDI_FAILURE); 620881Sjohnny 6211542Sjohnny count = hdlp->ih_scratch1; 6221542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 6231542Sjohnny for (i = 0; i < count; i++) { 6241542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 6251542Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 626881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 6271542Sjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 628881Sjohnny } 629881Sjohnny break; 630881Sjohnny case DDI_INTROP_SETMASK: 631881Sjohnny case DDI_INTROP_CLRMASK: 632881Sjohnny /* 633881Sjohnny * First handle in the config space 634881Sjohnny */ 635881Sjohnny if (intr_op == DDI_INTROP_SETMASK) { 636881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 637881Sjohnny pci_status = pci_msi_set_mask(rdip, 638881Sjohnny hdlp->ih_type, hdlp->ih_inum); 639881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 640881Sjohnny pci_status = pci_intx_set_mask(rdip); 641881Sjohnny } else { 642881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 643881Sjohnny pci_status = pci_msi_clr_mask(rdip, 644881Sjohnny hdlp->ih_type, hdlp->ih_inum); 645881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 646881Sjohnny pci_status = pci_intx_clr_mask(rdip); 647881Sjohnny } 648881Sjohnny 649881Sjohnny /* For MSI/X; no need to check with pcplusmp */ 650881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 651881Sjohnny return (pci_status); 652881Sjohnny 653881Sjohnny /* For fixed interrupts only: handle config space first */ 654881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 655881Sjohnny pci_status == DDI_SUCCESS) 656881Sjohnny break; 657881Sjohnny 658881Sjohnny /* For fixed interrupts only: confer with pcplusmp next */ 659881Sjohnny if (psm_intr_ops != NULL) { 660881Sjohnny /* If interrupt is shared; do nothing */ 661881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 662881Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status); 663881Sjohnny 664881Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1) 665881Sjohnny return (pci_status); 666881Sjohnny 667881Sjohnny /* Now, pcplusmp should try to set/clear the mask */ 668881Sjohnny if (intr_op == DDI_INTROP_SETMASK) 669881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 670881Sjohnny PSM_INTR_OP_SET_MASK, NULL); 671881Sjohnny else 672881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 673881Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL); 674881Sjohnny } 675881Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 676881Sjohnny case DDI_INTROP_GETPENDING: 677881Sjohnny /* 678881Sjohnny * First check the config space and/or 679881Sjohnny * MSI capability register(s) 680881Sjohnny */ 681881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 682881Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 683881Sjohnny hdlp->ih_inum, &pci_status); 684881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 685881Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status); 686881Sjohnny 687881Sjohnny /* On failure; next try with pcplusmp */ 688881Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 689881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 690881Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status); 691881Sjohnny 692881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 693881Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, " 694881Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval, 695881Sjohnny pci_status)); 696881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 697881Sjohnny *(int *)result = 0; 698881Sjohnny return (DDI_FAILURE); 699881Sjohnny } 700881Sjohnny 701881Sjohnny if (psm_rval != PSM_FAILURE) 702881Sjohnny *(int *)result = psm_status; 703881Sjohnny else if (pci_rval != DDI_FAILURE) 704881Sjohnny *(int *)result = pci_status; 705881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 706881Sjohnny *(int *)result)); 707881Sjohnny break; 70810053SEvan.Yan@Sun.COM case DDI_INTROP_GETTARGET: 70910053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n")); 71010053SEvan.Yan@Sun.COM 71110053SEvan.Yan@Sun.COM /* Note hdlp->ih_vector is actually an irq */ 71210053SEvan.Yan@Sun.COM if ((rv = pci_get_cpu_from_vecirq(hdlp->ih_vector, IS_IRQ)) == 71310053SEvan.Yan@Sun.COM -1) 71410053SEvan.Yan@Sun.COM return (DDI_FAILURE); 71510053SEvan.Yan@Sun.COM *(int *)result = rv; 71610053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET " 71710053SEvan.Yan@Sun.COM "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector, rv)); 71810053SEvan.Yan@Sun.COM break; 71910053SEvan.Yan@Sun.COM case DDI_INTROP_SETTARGET: 72010053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n")); 72110053SEvan.Yan@Sun.COM 72210053SEvan.Yan@Sun.COM /* hdlp->ih_vector is actually an irq */ 72310053SEvan.Yan@Sun.COM tmp_hdl.ih_vector = hdlp->ih_vector; 72410053SEvan.Yan@Sun.COM tmp_hdl.ih_flags = PSMGI_INTRBY_IRQ; 72510053SEvan.Yan@Sun.COM tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result; 72610053SEvan.Yan@Sun.COM psm_rval = (*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU, 72710053SEvan.Yan@Sun.COM &psm_status); 72810053SEvan.Yan@Sun.COM 72910053SEvan.Yan@Sun.COM if (psm_rval != PSM_SUCCESS) 73010053SEvan.Yan@Sun.COM return (DDI_FAILURE); 73110053SEvan.Yan@Sun.COM break; 732881Sjohnny default: 733881Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 734881Sjohnny } 735881Sjohnny 736881Sjohnny return (DDI_SUCCESS); 737881Sjohnny } 738881Sjohnny 739916Sschwartz int 740916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 741916Sschwartz int vecirq, boolean_t is_irq) 742916Sschwartz { 743916Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl; 744916Sschwartz 745916Sschwartz if (is_irq) 746916Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 747916Sschwartz 748916Sschwartz /* 749916Sschwartz * For this locally-declared and used handle, ih_private will contain a 750916Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 751916Sschwartz * global interrupt handling. 752916Sschwartz */ 753916Sschwartz get_info_ii_hdl.ih_private = intrinfo_p; 754916Sschwartz get_info_ii_hdl.ih_vector = (ushort_t)vecirq; 755916Sschwartz 756916Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 757916Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 758916Sschwartz return (DDI_FAILURE); 759916Sschwartz 760916Sschwartz return (DDI_SUCCESS); 761916Sschwartz } 762916Sschwartz 763916Sschwartz 764916Sschwartz int 765916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 766916Sschwartz { 767916Sschwartz int rval; 768916Sschwartz 769916Sschwartz apic_get_intr_t intrinfo; 770916Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 771916Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 772916Sschwartz 773916Sschwartz if (rval == DDI_SUCCESS) 774916Sschwartz return (intrinfo.avgi_cpu_id); 775916Sschwartz else 776916Sschwartz return (-1); 777916Sschwartz } 778916Sschwartz 779881Sjohnny 780881Sjohnny static int 781881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 782881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 783881Sjohnny { 784881Sjohnny struct intrspec *ispec; 785916Sschwartz int irq; 786916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 787881Sjohnny 788881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 789881Sjohnny (void *)hdlp, inum)); 790881Sjohnny 791881Sjohnny /* Translate the interrupt if needed */ 792881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 7932288Sanish if (ispec == NULL) 7942288Sanish return (DDI_FAILURE); 795*10190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 796881Sjohnny ispec->intrspec_vec = inum; 797*10190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri; 798*10190SSophia.Li@Sun.COM } 799916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 800881Sjohnny 801881Sjohnny /* translate the interrupt if needed */ 802916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 803916Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 804916Sschwartz hdlp->ih_pri, irq)); 805881Sjohnny 806881Sjohnny /* Add the interrupt handler */ 807881Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 808916Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 809916Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 810881Sjohnny return (DDI_FAILURE); 811881Sjohnny 812916Sschwartz /* Note this really is an irq. */ 813916Sschwartz hdlp->ih_vector = (ushort_t)irq; 814916Sschwartz 815881Sjohnny return (DDI_SUCCESS); 816881Sjohnny } 817881Sjohnny 818881Sjohnny 819881Sjohnny static void 820881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 821881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 822881Sjohnny { 823916Sschwartz int irq; 824881Sjohnny struct intrspec *ispec; 825916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 826881Sjohnny 827881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 828881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 8292288Sanish if (ispec == NULL) 8302288Sanish return; 831*10190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 832881Sjohnny ispec->intrspec_vec = inum; 833*10190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri; 834*10190SSophia.Li@Sun.COM } 835916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 836881Sjohnny 837881Sjohnny /* translate the interrupt if needed */ 838916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 839881Sjohnny 840881Sjohnny /* Disable the interrupt handler */ 841916Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 842916Sschwartz ihdl_plat_datap->ip_ispecp = NULL; 843881Sjohnny } 844881Sjohnny 845881Sjohnny /* 846881Sjohnny * Miscellaneous library function 847881Sjohnny */ 848881Sjohnny int 849881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 850881Sjohnny { 851881Sjohnny int i; 852881Sjohnny int number; 853881Sjohnny int assigned_addr_len; 854881Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi; 855881Sjohnny pci_regspec_t *assigned_addr; 856881Sjohnny 857881Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 858881Sjohnny (phys_hi & PCI_RELOCAT_B)) 859881Sjohnny return (DDI_SUCCESS); 860881Sjohnny 861881Sjohnny /* 862881Sjohnny * the "reg" property specifies relocatable, get and interpret the 863881Sjohnny * "assigned-addresses" property. 864881Sjohnny */ 865881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 866881Sjohnny "assigned-addresses", (int **)&assigned_addr, 867881Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 868881Sjohnny return (DDI_FAILURE); 869881Sjohnny 870881Sjohnny /* 871881Sjohnny * Scan the "assigned-addresses" for one that matches the specified 872881Sjohnny * "reg" property entry. 873881Sjohnny */ 874881Sjohnny phys_hi &= PCI_CONF_ADDR_MASK; 875881Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 876881Sjohnny for (i = 0; i < number; i++) { 877881Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 878881Sjohnny phys_hi) { 879881Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 880881Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 881881Sjohnny ddi_prop_free(assigned_addr); 882881Sjohnny return (DDI_SUCCESS); 883881Sjohnny } 884881Sjohnny } 885881Sjohnny 886881Sjohnny ddi_prop_free(assigned_addr); 887881Sjohnny return (DDI_FAILURE); 888881Sjohnny } 889881Sjohnny 890881Sjohnny 891881Sjohnny /* 892881Sjohnny * For pci_tools 893881Sjohnny */ 894881Sjohnny 895881Sjohnny int 896881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 897881Sjohnny int mode, cred_t *credp, int *rvalp) 898881Sjohnny { 899881Sjohnny int rv = ENOTTY; 900881Sjohnny 901881Sjohnny minor_t minor = getminor(dev); 902881Sjohnny 903881Sjohnny switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 904881Sjohnny case PCI_TOOL_REG_MINOR_NUM: 905881Sjohnny 906881Sjohnny switch (cmd) { 907881Sjohnny case PCITOOL_DEVICE_SET_REG: 908881Sjohnny case PCITOOL_DEVICE_GET_REG: 909881Sjohnny 910881Sjohnny /* Require full privileges. */ 911881Sjohnny if (secpolicy_kmdb(credp)) 912881Sjohnny rv = EPERM; 913881Sjohnny else 914881Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg, 915881Sjohnny cmd, mode); 916881Sjohnny break; 917881Sjohnny 918881Sjohnny case PCITOOL_NEXUS_SET_REG: 919881Sjohnny case PCITOOL_NEXUS_GET_REG: 920881Sjohnny 921881Sjohnny /* Require full privileges. */ 922881Sjohnny if (secpolicy_kmdb(credp)) 923881Sjohnny rv = EPERM; 924881Sjohnny else 925881Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg, 926881Sjohnny cmd, mode); 927881Sjohnny break; 928881Sjohnny } 929881Sjohnny break; 930881Sjohnny 931881Sjohnny case PCI_TOOL_INTR_MINOR_NUM: 932881Sjohnny 933881Sjohnny switch (cmd) { 934881Sjohnny case PCITOOL_DEVICE_SET_INTR: 935881Sjohnny 936881Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 937881Sjohnny if (secpolicy_ponline(credp)) { 938881Sjohnny rv = EPERM; 939881Sjohnny break; 940881Sjohnny } 941881Sjohnny 942881Sjohnny /*FALLTHRU*/ 943881Sjohnny /* These require no special privileges. */ 944881Sjohnny case PCITOOL_DEVICE_GET_INTR: 9454397Sschwartz case PCITOOL_SYSTEM_INTR_INFO: 946881Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 947881Sjohnny break; 948881Sjohnny } 949881Sjohnny break; 950881Sjohnny 951881Sjohnny /* 952881Sjohnny * All non-PCItool ioctls go through here, including: 953881Sjohnny * devctl ioctls with minor number PCIHP_DEVCTL_MINOR and 954881Sjohnny * those for attachment points with where minor number is the 955881Sjohnny * device number. 956881Sjohnny */ 957881Sjohnny default: 958881Sjohnny rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 959881Sjohnny credp, rvalp); 960881Sjohnny break; 961881Sjohnny } 962881Sjohnny 963881Sjohnny return (rv); 964881Sjohnny } 9651083Sanish 9661083Sanish 9671865Sdilpreet int 9681865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 9691865Sdilpreet { 9701865Sdilpreet size_t size = in_args->size; 9711865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 9721865Sdilpreet uintptr_t host_addr = in_args->host_addr; 9731865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 9741865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 9751865Sdilpreet size_t repcount = in_args->repcount; 9761865Sdilpreet uint_t flags = in_args->flags; 9771865Sdilpreet int err = DDI_SUCCESS; 9781865Sdilpreet 9791865Sdilpreet /* 9801865Sdilpreet * if no handle then this is a poke. We have to return failure here 9811865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 9821865Sdilpreet */ 9831865Sdilpreet if (in_args->handle == NULL) 9841865Sdilpreet return (DDI_FAILURE); 9851865Sdilpreet 9861865Sdilpreet /* 9871865Sdilpreet * rest of this function is actually for cautious puts 9881865Sdilpreet */ 9891865Sdilpreet for (; repcount; repcount--) { 9901865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 9911865Sdilpreet switch (size) { 9921865Sdilpreet case sizeof (uint8_t): 9931865Sdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr, 9941865Sdilpreet *(uint8_t *)host_addr); 9951865Sdilpreet break; 9961865Sdilpreet case sizeof (uint16_t): 9971865Sdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr, 9981865Sdilpreet *(uint16_t *)host_addr); 9991865Sdilpreet break; 10001865Sdilpreet case sizeof (uint32_t): 10011865Sdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr, 10021865Sdilpreet *(uint32_t *)host_addr); 10031865Sdilpreet break; 10041865Sdilpreet case sizeof (uint64_t): 10051865Sdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr, 10061865Sdilpreet *(uint64_t *)host_addr); 10071865Sdilpreet break; 10081865Sdilpreet default: 10091865Sdilpreet err = DDI_FAILURE; 10101865Sdilpreet break; 10111865Sdilpreet } 10121865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 10131865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 10141865Sdilpreet DDI_STRUCTURE_BE_ACC) { 10151865Sdilpreet switch (size) { 10161865Sdilpreet case sizeof (uint8_t): 10171865Sdilpreet i_ddi_io_put8(hp, 10181865Sdilpreet (uint8_t *)dev_addr, 10191865Sdilpreet *(uint8_t *)host_addr); 10201865Sdilpreet break; 10211865Sdilpreet case sizeof (uint16_t): 10221865Sdilpreet i_ddi_io_swap_put16(hp, 10231865Sdilpreet (uint16_t *)dev_addr, 10241865Sdilpreet *(uint16_t *)host_addr); 10251865Sdilpreet break; 10261865Sdilpreet case sizeof (uint32_t): 10271865Sdilpreet i_ddi_io_swap_put32(hp, 10281865Sdilpreet (uint32_t *)dev_addr, 10291865Sdilpreet *(uint32_t *)host_addr); 10301865Sdilpreet break; 10311865Sdilpreet /* 10321865Sdilpreet * note the 64-bit case is a dummy 10331865Sdilpreet * function - so no need to swap 10341865Sdilpreet */ 10351865Sdilpreet case sizeof (uint64_t): 10361865Sdilpreet i_ddi_io_put64(hp, 10371865Sdilpreet (uint64_t *)dev_addr, 10381865Sdilpreet *(uint64_t *)host_addr); 10391865Sdilpreet break; 10401865Sdilpreet default: 10411865Sdilpreet err = DDI_FAILURE; 10421865Sdilpreet break; 10431865Sdilpreet } 10441865Sdilpreet } else { 10451865Sdilpreet switch (size) { 10461865Sdilpreet case sizeof (uint8_t): 10471865Sdilpreet i_ddi_io_put8(hp, 10481865Sdilpreet (uint8_t *)dev_addr, 10491865Sdilpreet *(uint8_t *)host_addr); 10501865Sdilpreet break; 10511865Sdilpreet case sizeof (uint16_t): 10521865Sdilpreet i_ddi_io_put16(hp, 10531865Sdilpreet (uint16_t *)dev_addr, 10541865Sdilpreet *(uint16_t *)host_addr); 10551865Sdilpreet break; 10561865Sdilpreet case sizeof (uint32_t): 10571865Sdilpreet i_ddi_io_put32(hp, 10581865Sdilpreet (uint32_t *)dev_addr, 10591865Sdilpreet *(uint32_t *)host_addr); 10601865Sdilpreet break; 10611865Sdilpreet case sizeof (uint64_t): 10621865Sdilpreet i_ddi_io_put64(hp, 10631865Sdilpreet (uint64_t *)dev_addr, 10641865Sdilpreet *(uint64_t *)host_addr); 10651865Sdilpreet break; 10661865Sdilpreet default: 10671865Sdilpreet err = DDI_FAILURE; 10681865Sdilpreet break; 10691865Sdilpreet } 10701865Sdilpreet } 10711865Sdilpreet } else { 10721865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 10731865Sdilpreet DDI_STRUCTURE_BE_ACC) { 10741865Sdilpreet switch (size) { 10751865Sdilpreet case sizeof (uint8_t): 10761865Sdilpreet *(uint8_t *)dev_addr = 10771865Sdilpreet *(uint8_t *)host_addr; 10781865Sdilpreet break; 10791865Sdilpreet case sizeof (uint16_t): 10801865Sdilpreet *(uint16_t *)dev_addr = 10811865Sdilpreet ddi_swap16(*(uint16_t *)host_addr); 10821865Sdilpreet break; 10831865Sdilpreet case sizeof (uint32_t): 10841865Sdilpreet *(uint32_t *)dev_addr = 10851865Sdilpreet ddi_swap32(*(uint32_t *)host_addr); 10861865Sdilpreet break; 10871865Sdilpreet case sizeof (uint64_t): 10881865Sdilpreet *(uint64_t *)dev_addr = 10891865Sdilpreet ddi_swap64(*(uint64_t *)host_addr); 10901865Sdilpreet break; 10911865Sdilpreet default: 10921865Sdilpreet err = DDI_FAILURE; 10931865Sdilpreet break; 10941865Sdilpreet } 10951865Sdilpreet } else { 10961865Sdilpreet switch (size) { 10971865Sdilpreet case sizeof (uint8_t): 10981865Sdilpreet *(uint8_t *)dev_addr = 10991865Sdilpreet *(uint8_t *)host_addr; 11001865Sdilpreet break; 11011865Sdilpreet case sizeof (uint16_t): 11021865Sdilpreet *(uint16_t *)dev_addr = 11031865Sdilpreet *(uint16_t *)host_addr; 11041865Sdilpreet break; 11051865Sdilpreet case sizeof (uint32_t): 11061865Sdilpreet *(uint32_t *)dev_addr = 11071865Sdilpreet *(uint32_t *)host_addr; 11081865Sdilpreet break; 11091865Sdilpreet case sizeof (uint64_t): 11101865Sdilpreet *(uint64_t *)dev_addr = 11111865Sdilpreet *(uint64_t *)host_addr; 11121865Sdilpreet break; 11131865Sdilpreet default: 11141865Sdilpreet err = DDI_FAILURE; 11151865Sdilpreet break; 11161865Sdilpreet } 11171865Sdilpreet } 11181865Sdilpreet } 11191865Sdilpreet host_addr += size; 11201865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 11211865Sdilpreet dev_addr += size; 11221865Sdilpreet } 11231865Sdilpreet return (err); 11241865Sdilpreet } 11251865Sdilpreet 11261865Sdilpreet 11271865Sdilpreet int 11281865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 11291865Sdilpreet { 11301865Sdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 11311865Sdilpreet 11321865Sdilpreet /* endian-ness check */ 11331865Sdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 11341865Sdilpreet return (DDI_FAILURE); 11351865Sdilpreet 11361865Sdilpreet /* 11371865Sdilpreet * range check 11381865Sdilpreet */ 11391865Sdilpreet if ((offset >= PCI_CONF_HDR_SIZE) || 11401865Sdilpreet (len > PCI_CONF_HDR_SIZE) || 11411865Sdilpreet (offset + len > PCI_CONF_HDR_SIZE)) 11421865Sdilpreet return (DDI_FAILURE); 11431865Sdilpreet 11441865Sdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 11451865Sdilpreet /* 11461865Sdilpreet * always use cautious mechanism for config space gets 11471865Sdilpreet */ 11481865Sdilpreet ap->ahi_get8 = i_ddi_caut_get8; 11491865Sdilpreet ap->ahi_get16 = i_ddi_caut_get16; 11501865Sdilpreet ap->ahi_get32 = i_ddi_caut_get32; 11511865Sdilpreet ap->ahi_get64 = i_ddi_caut_get64; 11521865Sdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 11531865Sdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 11541865Sdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 11551865Sdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 11561865Sdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 11571865Sdilpreet ap->ahi_put8 = i_ddi_caut_put8; 11581865Sdilpreet ap->ahi_put16 = i_ddi_caut_put16; 11591865Sdilpreet ap->ahi_put32 = i_ddi_caut_put32; 11601865Sdilpreet ap->ahi_put64 = i_ddi_caut_put64; 11611865Sdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 11621865Sdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 11631865Sdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 11641865Sdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 11651865Sdilpreet } else { 11661865Sdilpreet ap->ahi_put8 = pci_config_wr8; 11671865Sdilpreet ap->ahi_put16 = pci_config_wr16; 11681865Sdilpreet ap->ahi_put32 = pci_config_wr32; 11691865Sdilpreet ap->ahi_put64 = pci_config_wr64; 11701865Sdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8; 11711865Sdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16; 11721865Sdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32; 11731865Sdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64; 11741865Sdilpreet } 11751865Sdilpreet 11761865Sdilpreet /* Initialize to default check/notify functions */ 11771865Sdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check; 11781865Sdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify; 11791865Sdilpreet ap->ahi_fault = 0; 11801865Sdilpreet impl_acc_err_init(hp); 11811865Sdilpreet return (DDI_SUCCESS); 11821865Sdilpreet } 11831865Sdilpreet 11841865Sdilpreet 11851865Sdilpreet int 11861865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 11871865Sdilpreet { 11881865Sdilpreet size_t size = in_args->size; 11891865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 11901865Sdilpreet uintptr_t host_addr = in_args->host_addr; 11911865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 11921865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 11931865Sdilpreet size_t repcount = in_args->repcount; 11941865Sdilpreet uint_t flags = in_args->flags; 11951865Sdilpreet int err = DDI_SUCCESS; 11961865Sdilpreet 11971865Sdilpreet /* 11981865Sdilpreet * if no handle then this is a peek. We have to return failure here 11991865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 12001865Sdilpreet */ 12011865Sdilpreet if (in_args->handle == NULL) 12021865Sdilpreet return (DDI_FAILURE); 12031865Sdilpreet 12041865Sdilpreet for (; repcount; repcount--) { 12051865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 12061865Sdilpreet switch (size) { 12071865Sdilpreet case sizeof (uint8_t): 12081865Sdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp, 12091865Sdilpreet (uint8_t *)dev_addr); 12101865Sdilpreet break; 12111865Sdilpreet case sizeof (uint16_t): 12121865Sdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp, 12131865Sdilpreet (uint16_t *)dev_addr); 12141865Sdilpreet break; 12151865Sdilpreet case sizeof (uint32_t): 12161865Sdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp, 12171865Sdilpreet (uint32_t *)dev_addr); 12181865Sdilpreet break; 12191865Sdilpreet case sizeof (uint64_t): 12201865Sdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp, 12211865Sdilpreet (uint64_t *)dev_addr); 12221865Sdilpreet break; 12231865Sdilpreet default: 12241865Sdilpreet err = DDI_FAILURE; 12251865Sdilpreet break; 12261865Sdilpreet } 12271865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 12281865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12291865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12301865Sdilpreet switch (size) { 12311865Sdilpreet case sizeof (uint8_t): 12321865Sdilpreet *(uint8_t *)host_addr = 12331865Sdilpreet i_ddi_io_get8(hp, 12341865Sdilpreet (uint8_t *)dev_addr); 12351865Sdilpreet break; 12361865Sdilpreet case sizeof (uint16_t): 12371865Sdilpreet *(uint16_t *)host_addr = 12381865Sdilpreet i_ddi_io_swap_get16(hp, 12391865Sdilpreet (uint16_t *)dev_addr); 12401865Sdilpreet break; 12411865Sdilpreet case sizeof (uint32_t): 12421865Sdilpreet *(uint32_t *)host_addr = 12431865Sdilpreet i_ddi_io_swap_get32(hp, 12441865Sdilpreet (uint32_t *)dev_addr); 12451865Sdilpreet break; 12461865Sdilpreet /* 12471865Sdilpreet * note the 64-bit case is a dummy 12481865Sdilpreet * function - so no need to swap 12491865Sdilpreet */ 12501865Sdilpreet case sizeof (uint64_t): 12511865Sdilpreet *(uint64_t *)host_addr = 12521865Sdilpreet i_ddi_io_get64(hp, 12531865Sdilpreet (uint64_t *)dev_addr); 12541865Sdilpreet break; 12551865Sdilpreet default: 12561865Sdilpreet err = DDI_FAILURE; 12571865Sdilpreet break; 12581865Sdilpreet } 12591865Sdilpreet } else { 12601865Sdilpreet switch (size) { 12611865Sdilpreet case sizeof (uint8_t): 12621865Sdilpreet *(uint8_t *)host_addr = 12631865Sdilpreet i_ddi_io_get8(hp, 12641865Sdilpreet (uint8_t *)dev_addr); 12651865Sdilpreet break; 12661865Sdilpreet case sizeof (uint16_t): 12671865Sdilpreet *(uint16_t *)host_addr = 12681865Sdilpreet i_ddi_io_get16(hp, 12691865Sdilpreet (uint16_t *)dev_addr); 12701865Sdilpreet break; 12711865Sdilpreet case sizeof (uint32_t): 12721865Sdilpreet *(uint32_t *)host_addr = 12731865Sdilpreet i_ddi_io_get32(hp, 12741865Sdilpreet (uint32_t *)dev_addr); 12751865Sdilpreet break; 12761865Sdilpreet case sizeof (uint64_t): 12771865Sdilpreet *(uint64_t *)host_addr = 12781865Sdilpreet i_ddi_io_get64(hp, 12791865Sdilpreet (uint64_t *)dev_addr); 12801865Sdilpreet break; 12811865Sdilpreet default: 12821865Sdilpreet err = DDI_FAILURE; 12831865Sdilpreet break; 12841865Sdilpreet } 12851865Sdilpreet } 12861865Sdilpreet } else { 12871865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12881865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12891865Sdilpreet switch (in_args->size) { 12901865Sdilpreet case sizeof (uint8_t): 12911865Sdilpreet *(uint8_t *)host_addr = 12921865Sdilpreet *(uint8_t *)dev_addr; 12931865Sdilpreet break; 12941865Sdilpreet case sizeof (uint16_t): 12951865Sdilpreet *(uint16_t *)host_addr = 12961865Sdilpreet ddi_swap16(*(uint16_t *)dev_addr); 12971865Sdilpreet break; 12981865Sdilpreet case sizeof (uint32_t): 12991865Sdilpreet *(uint32_t *)host_addr = 13001865Sdilpreet ddi_swap32(*(uint32_t *)dev_addr); 13011865Sdilpreet break; 13021865Sdilpreet case sizeof (uint64_t): 13031865Sdilpreet *(uint64_t *)host_addr = 13041865Sdilpreet ddi_swap64(*(uint64_t *)dev_addr); 13051865Sdilpreet break; 13061865Sdilpreet default: 13071865Sdilpreet err = DDI_FAILURE; 13081865Sdilpreet break; 13091865Sdilpreet } 13101865Sdilpreet } else { 13111865Sdilpreet switch (in_args->size) { 13121865Sdilpreet case sizeof (uint8_t): 13131865Sdilpreet *(uint8_t *)host_addr = 13141865Sdilpreet *(uint8_t *)dev_addr; 13151865Sdilpreet break; 13161865Sdilpreet case sizeof (uint16_t): 13171865Sdilpreet *(uint16_t *)host_addr = 13181865Sdilpreet *(uint16_t *)dev_addr; 13191865Sdilpreet break; 13201865Sdilpreet case sizeof (uint32_t): 13211865Sdilpreet *(uint32_t *)host_addr = 13221865Sdilpreet *(uint32_t *)dev_addr; 13231865Sdilpreet break; 13241865Sdilpreet case sizeof (uint64_t): 13251865Sdilpreet *(uint64_t *)host_addr = 13261865Sdilpreet *(uint64_t *)dev_addr; 13271865Sdilpreet break; 13281865Sdilpreet default: 13291865Sdilpreet err = DDI_FAILURE; 13301865Sdilpreet break; 13311865Sdilpreet } 13321865Sdilpreet } 13331865Sdilpreet } 13341865Sdilpreet host_addr += size; 13351865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 13361865Sdilpreet dev_addr += size; 13371865Sdilpreet } 13381865Sdilpreet return (err); 13391865Sdilpreet } 13401865Sdilpreet 13411865Sdilpreet /*ARGSUSED*/ 13421865Sdilpreet int 13431865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 13441865Sdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result) 13451865Sdilpreet { 13461865Sdilpreet if (ctlop == DDI_CTLOPS_PEEK) 13471865Sdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 13481865Sdilpreet else 13491865Sdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 13501865Sdilpreet } 13511865Sdilpreet 13521083Sanish /* 13531083Sanish * These are the get and put functions to be shared with drivers. The 13541083Sanish * mutex locking is done inside the functions referenced, rather than 13551083Sanish * here, and is thus shared across PCI child drivers and any other 13561083Sanish * consumers of PCI config space (such as the ACPI subsystem). 13571083Sanish * 13581083Sanish * The configuration space addresses come in as pointers. This is fine on 13591083Sanish * a 32-bit system, where the VM space and configuration space are the same 13601083Sanish * size. It's not such a good idea on a 64-bit system, where memory 13611083Sanish * addresses are twice as large as configuration space addresses. At some 13621083Sanish * point in the call tree we need to take a stand and say "you are 32-bit 13631083Sanish * from this time forth", and this seems like a nice self-contained place. 13641083Sanish */ 13651083Sanish 13661083Sanish uint8_t 13671083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 13681083Sanish { 13691083Sanish pci_acc_cfblk_t *cfp; 13701083Sanish uint8_t rval; 13711083Sanish int reg; 13721083Sanish 13731083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13741083Sanish 13751083Sanish reg = (int)(uintptr_t)addr; 13761083Sanish 13771083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13781083Sanish 13791083Sanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 13801083Sanish reg); 13811083Sanish 13821083Sanish return (rval); 13831083Sanish } 13841083Sanish 13851083Sanish void 13861083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 13871083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 13881083Sanish { 13891083Sanish uint8_t *h, *d; 13901083Sanish 13911083Sanish h = host_addr; 13921083Sanish d = dev_addr; 13931083Sanish 13941083Sanish if (flags == DDI_DEV_AUTOINCR) 13951083Sanish for (; repcount; repcount--) 13961083Sanish *h++ = pci_config_rd8(hdlp, d++); 13971083Sanish else 13981083Sanish for (; repcount; repcount--) 13991083Sanish *h++ = pci_config_rd8(hdlp, d); 14001083Sanish } 14011083Sanish 14021083Sanish uint16_t 14031083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 14041083Sanish { 14051083Sanish pci_acc_cfblk_t *cfp; 14061083Sanish uint16_t rval; 14071083Sanish int reg; 14081083Sanish 14091083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14101083Sanish 14111083Sanish reg = (int)(uintptr_t)addr; 14121083Sanish 14131083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14141083Sanish 14151083Sanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 14161083Sanish reg); 14171083Sanish 14181083Sanish return (rval); 14191083Sanish } 14201083Sanish 14211083Sanish void 14221083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 14231083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 14241083Sanish { 14251083Sanish uint16_t *h, *d; 14261083Sanish 14271083Sanish h = host_addr; 14281083Sanish d = dev_addr; 14291083Sanish 14301083Sanish if (flags == DDI_DEV_AUTOINCR) 14311083Sanish for (; repcount; repcount--) 14321083Sanish *h++ = pci_config_rd16(hdlp, d++); 14331083Sanish else 14341083Sanish for (; repcount; repcount--) 14351083Sanish *h++ = pci_config_rd16(hdlp, d); 14361083Sanish } 14371083Sanish 14381083Sanish uint32_t 14391083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 14401083Sanish { 14411083Sanish pci_acc_cfblk_t *cfp; 14421083Sanish uint32_t rval; 14431083Sanish int reg; 14441083Sanish 14451083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14461083Sanish 14471083Sanish reg = (int)(uintptr_t)addr; 14481083Sanish 14491083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14501083Sanish 14511083Sanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 14521083Sanish cfp->c_funcnum, reg); 14531083Sanish 14541083Sanish return (rval); 14551083Sanish } 14561083Sanish 14571083Sanish void 14581083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 14591083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 14601083Sanish { 14611083Sanish uint32_t *h, *d; 14621083Sanish 14631083Sanish h = host_addr; 14641083Sanish d = dev_addr; 14651083Sanish 14661083Sanish if (flags == DDI_DEV_AUTOINCR) 14671083Sanish for (; repcount; repcount--) 14681083Sanish *h++ = pci_config_rd32(hdlp, d++); 14691083Sanish else 14701083Sanish for (; repcount; repcount--) 14711083Sanish *h++ = pci_config_rd32(hdlp, d); 14721083Sanish } 14731083Sanish 14741083Sanish 14751083Sanish void 14761083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 14771083Sanish { 14781083Sanish pci_acc_cfblk_t *cfp; 14791083Sanish int reg; 14801083Sanish 14811083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14821083Sanish 14831083Sanish reg = (int)(uintptr_t)addr; 14841083Sanish 14851083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14861083Sanish 14871083Sanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 14881083Sanish cfp->c_funcnum, reg, value); 14891083Sanish } 14901083Sanish 14911083Sanish void 14921083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 14931083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 14941083Sanish { 14951083Sanish uint8_t *h, *d; 14961083Sanish 14971083Sanish h = host_addr; 14981083Sanish d = dev_addr; 14991083Sanish 15001083Sanish if (flags == DDI_DEV_AUTOINCR) 15011083Sanish for (; repcount; repcount--) 15021083Sanish pci_config_wr8(hdlp, d++, *h++); 15031083Sanish else 15041083Sanish for (; repcount; repcount--) 15051083Sanish pci_config_wr8(hdlp, d, *h++); 15061083Sanish } 15071083Sanish 15081083Sanish void 15091083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 15101083Sanish { 15111083Sanish pci_acc_cfblk_t *cfp; 15121083Sanish int reg; 15131083Sanish 15141083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15151083Sanish 15161083Sanish reg = (int)(uintptr_t)addr; 15171083Sanish 15181083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15191083Sanish 15201083Sanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 15211083Sanish cfp->c_funcnum, reg, value); 15221083Sanish } 15231083Sanish 15241083Sanish void 15251083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 15261083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 15271083Sanish { 15281083Sanish uint16_t *h, *d; 15291083Sanish 15301083Sanish h = host_addr; 15311083Sanish d = dev_addr; 15321083Sanish 15331083Sanish if (flags == DDI_DEV_AUTOINCR) 15341083Sanish for (; repcount; repcount--) 15351083Sanish pci_config_wr16(hdlp, d++, *h++); 15361083Sanish else 15371083Sanish for (; repcount; repcount--) 15381083Sanish pci_config_wr16(hdlp, d, *h++); 15391083Sanish } 15401083Sanish 15411083Sanish void 15421083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 15431083Sanish { 15441083Sanish pci_acc_cfblk_t *cfp; 15451083Sanish int reg; 15461083Sanish 15471083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15481083Sanish 15491083Sanish reg = (int)(uintptr_t)addr; 15501083Sanish 15511083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15521083Sanish 15531083Sanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 15541083Sanish cfp->c_funcnum, reg, value); 15551083Sanish } 15561083Sanish 15571083Sanish void 15581083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 15591083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 15601083Sanish { 15611083Sanish uint32_t *h, *d; 15621083Sanish 15631083Sanish h = host_addr; 15641083Sanish d = dev_addr; 15651083Sanish 15661083Sanish if (flags == DDI_DEV_AUTOINCR) 15671083Sanish for (; repcount; repcount--) 15681083Sanish pci_config_wr32(hdlp, d++, *h++); 15691083Sanish else 15701083Sanish for (; repcount; repcount--) 15711083Sanish pci_config_wr32(hdlp, d, *h++); 15721083Sanish } 15731083Sanish 15741083Sanish uint64_t 15751083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 15761083Sanish { 15771083Sanish uint32_t lw_val; 15781083Sanish uint32_t hi_val; 15791083Sanish uint32_t *dp; 15801083Sanish uint64_t val; 15811083Sanish 15821083Sanish dp = (uint32_t *)addr; 15831083Sanish lw_val = pci_config_rd32(hdlp, dp); 15841083Sanish dp++; 15851083Sanish hi_val = pci_config_rd32(hdlp, dp); 15861083Sanish val = ((uint64_t)hi_val << 32) | lw_val; 15871083Sanish return (val); 15881083Sanish } 15891083Sanish 15901083Sanish void 15911083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 15921083Sanish { 15931083Sanish uint32_t lw_val; 15941083Sanish uint32_t hi_val; 15951083Sanish uint32_t *dp; 15961083Sanish 15971083Sanish dp = (uint32_t *)addr; 15981083Sanish lw_val = (uint32_t)(value & 0xffffffff); 15991083Sanish hi_val = (uint32_t)(value >> 32); 16001083Sanish pci_config_wr32(hdlp, dp, lw_val); 16011083Sanish dp++; 16021083Sanish pci_config_wr32(hdlp, dp, hi_val); 16031083Sanish } 16041083Sanish 16051083Sanish void 16061083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 16071083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 16081083Sanish { 16091083Sanish if (flags == DDI_DEV_AUTOINCR) { 16101083Sanish for (; repcount; repcount--) 16111083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 16121083Sanish } else { 16131083Sanish for (; repcount; repcount--) 16141083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr); 16151083Sanish } 16161083Sanish } 16171083Sanish 16181083Sanish void 16191083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 16201083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 16211083Sanish { 16221083Sanish if (flags == DDI_DEV_AUTOINCR) { 16231083Sanish for (; repcount; repcount--) 16241083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr++); 16251083Sanish } else { 16261083Sanish for (; repcount; repcount--) 16271083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr); 16281083Sanish } 16291083Sanish } 1630