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 181881Sjohnny static int pcie_pci_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 /* 314881Sjohnny * Following check is a special case for 'pcie_pci'. 315881Sjohnny * This makes sure vectors with the right priority 316881Sjohnny * are allocated for pcie_pci during ALLOC time. 317881Sjohnny */ 318881Sjohnny if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) { 319881Sjohnny hdlp->ih_pri = 320881Sjohnny (pcie_pci_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; 397881Sjohnny ++pcie_pci_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 454881Sjohnny /* Change the priority */ 455881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 456881Sjohnny PSM_FAILURE) 457881Sjohnny return (DDI_FAILURE); 458881Sjohnny 459881Sjohnny /* update ispec */ 460881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 461881Sjohnny ispec = (struct intrspec *)isp; 462881Sjohnny if (ispec) 463881Sjohnny ispec->intrspec_pri = *(int *)result; 464881Sjohnny break; 465881Sjohnny case DDI_INTROP_ADDISR: 466881Sjohnny /* update ispec */ 467881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 468881Sjohnny ispec = (struct intrspec *)isp; 4691087Sschwartz if (ispec) { 470881Sjohnny ispec->intrspec_func = hdlp->ih_cb_func; 4711087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 4721087Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 4731087Sschwartz } 474881Sjohnny break; 475881Sjohnny case DDI_INTROP_REMISR: 476881Sjohnny /* Get the interrupt structure pointer */ 477881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 478881Sjohnny ispec = (struct intrspec *)isp; 4791087Sschwartz if (ispec) { 480881Sjohnny ispec->intrspec_func = (uint_t (*)()) 0; 4811087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 4821087Sschwartz if (ihdl_plat_datap->ip_ksp != NULL) 4831087Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp); 4841087Sschwartz } 485881Sjohnny break; 486881Sjohnny case DDI_INTROP_GETCAP: 487881Sjohnny /* 488881Sjohnny * First check the config space and/or 489881Sjohnny * MSI capability register(s) 490881Sjohnny */ 491881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 492881Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 493881Sjohnny &pci_status); 494881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 495881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 496881Sjohnny 497881Sjohnny /* next check with pcplusmp */ 498881Sjohnny if (psm_intr_ops != NULL) 499881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 500881Sjohnny PSM_INTR_OP_GET_CAP, &psm_status); 501881Sjohnny 502881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 503881Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n", 504881Sjohnny psm_rval, psm_status, pci_rval, pci_status)); 505881Sjohnny 506881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 507881Sjohnny *(int *)result = 0; 508881Sjohnny return (DDI_FAILURE); 509881Sjohnny } 510881Sjohnny 511881Sjohnny if (psm_rval == PSM_SUCCESS) 512881Sjohnny *(int *)result = psm_status; 513881Sjohnny 514881Sjohnny if (pci_rval == DDI_SUCCESS) 515881Sjohnny *(int *)result |= pci_status; 516881Sjohnny 517881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 518881Sjohnny *(int *)result)); 519881Sjohnny break; 520881Sjohnny case DDI_INTROP_SETCAP: 521881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 522881Sjohnny "SETCAP cap=0x%x\n", *(int *)result)); 523881Sjohnny if (psm_intr_ops == NULL) 524881Sjohnny return (DDI_FAILURE); 525881Sjohnny 526881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 527881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 528881Sjohnny " returned failure\n")); 529881Sjohnny return (DDI_FAILURE); 530881Sjohnny } 531881Sjohnny break; 532881Sjohnny case DDI_INTROP_ENABLE: 533881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 534881Sjohnny if (psm_intr_ops == NULL) 535881Sjohnny return (DDI_FAILURE); 536881Sjohnny 537881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 538881Sjohnny DDI_SUCCESS) 539881Sjohnny return (DDI_FAILURE); 540881Sjohnny 541881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 542881Sjohnny "vector=0x%x\n", hdlp->ih_vector)); 543881Sjohnny break; 544881Sjohnny case DDI_INTROP_DISABLE: 545881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 546881Sjohnny if (psm_intr_ops == NULL) 547881Sjohnny return (DDI_FAILURE); 548881Sjohnny 549881Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 550881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 551881Sjohnny "vector = %x\n", hdlp->ih_vector)); 552881Sjohnny break; 553881Sjohnny case DDI_INTROP_BLOCKENABLE: 554881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 555881Sjohnny "BLOCKENABLE\n")); 556881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 557881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 558881Sjohnny return (DDI_FAILURE); 559881Sjohnny } 560881Sjohnny 561881Sjohnny /* Check if psm_intr_ops is NULL? */ 562881Sjohnny if (psm_intr_ops == NULL) 563881Sjohnny return (DDI_FAILURE); 564881Sjohnny 5651542Sjohnny count = hdlp->ih_scratch1; 5661542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 5671542Sjohnny for (i = 0; i < count; i++) { 5681542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 569881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, 5701542Sjohnny hdlp->ih_inum) != DDI_SUCCESS) { 571881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 572881Sjohnny "pci_enable_intr failed for %d\n", i)); 5731542Sjohnny for (j = 0; j < i; j++) { 5744397Sschwartz hdlp = (ddi_intr_handle_impl_t *) 5754397Sschwartz h_array[j]; 5764397Sschwartz pci_disable_intr(pdip, rdip, hdlp, 5771542Sjohnny hdlp->ih_inum); 5781542Sjohnny } 579881Sjohnny return (DDI_FAILURE); 580881Sjohnny } 581881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 5821542Sjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 583881Sjohnny } 584881Sjohnny break; 585881Sjohnny case DDI_INTROP_BLOCKDISABLE: 586881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 587881Sjohnny "BLOCKDISABLE\n")); 588881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 589881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 590881Sjohnny return (DDI_FAILURE); 591881Sjohnny } 592881Sjohnny 593881Sjohnny /* Check if psm_intr_ops is present */ 594881Sjohnny if (psm_intr_ops == NULL) 595881Sjohnny return (DDI_FAILURE); 596881Sjohnny 5971542Sjohnny count = hdlp->ih_scratch1; 5981542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 5991542Sjohnny for (i = 0; i < count; i++) { 6001542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 6011542Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 602881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 6031542Sjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 604881Sjohnny } 605881Sjohnny break; 606881Sjohnny case DDI_INTROP_SETMASK: 607881Sjohnny case DDI_INTROP_CLRMASK: 608881Sjohnny /* 609881Sjohnny * First handle in the config space 610881Sjohnny */ 611881Sjohnny if (intr_op == DDI_INTROP_SETMASK) { 612881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 613881Sjohnny pci_status = pci_msi_set_mask(rdip, 614881Sjohnny hdlp->ih_type, hdlp->ih_inum); 615881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 616881Sjohnny pci_status = pci_intx_set_mask(rdip); 617881Sjohnny } else { 618881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 619881Sjohnny pci_status = pci_msi_clr_mask(rdip, 620881Sjohnny hdlp->ih_type, hdlp->ih_inum); 621881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 622881Sjohnny pci_status = pci_intx_clr_mask(rdip); 623881Sjohnny } 624881Sjohnny 625881Sjohnny /* For MSI/X; no need to check with pcplusmp */ 626881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 627881Sjohnny return (pci_status); 628881Sjohnny 629881Sjohnny /* For fixed interrupts only: handle config space first */ 630881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 631881Sjohnny pci_status == DDI_SUCCESS) 632881Sjohnny break; 633881Sjohnny 634881Sjohnny /* For fixed interrupts only: confer with pcplusmp next */ 635881Sjohnny if (psm_intr_ops != NULL) { 636881Sjohnny /* If interrupt is shared; do nothing */ 637881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 638881Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status); 639881Sjohnny 640881Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1) 641881Sjohnny return (pci_status); 642881Sjohnny 643881Sjohnny /* Now, pcplusmp should try to set/clear the mask */ 644881Sjohnny if (intr_op == DDI_INTROP_SETMASK) 645881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 646881Sjohnny PSM_INTR_OP_SET_MASK, NULL); 647881Sjohnny else 648881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 649881Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL); 650881Sjohnny } 651881Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 652881Sjohnny case DDI_INTROP_GETPENDING: 653881Sjohnny /* 654881Sjohnny * First check the config space and/or 655881Sjohnny * MSI capability register(s) 656881Sjohnny */ 657881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 658881Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 659881Sjohnny hdlp->ih_inum, &pci_status); 660881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 661881Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status); 662881Sjohnny 663881Sjohnny /* On failure; next try with pcplusmp */ 664881Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 665881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 666881Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status); 667881Sjohnny 668881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 669881Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, " 670881Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval, 671881Sjohnny pci_status)); 672881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 673881Sjohnny *(int *)result = 0; 674881Sjohnny return (DDI_FAILURE); 675881Sjohnny } 676881Sjohnny 677881Sjohnny if (psm_rval != PSM_FAILURE) 678881Sjohnny *(int *)result = psm_status; 679881Sjohnny else if (pci_rval != DDI_FAILURE) 680881Sjohnny *(int *)result = pci_status; 681881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 682881Sjohnny *(int *)result)); 683881Sjohnny break; 684*10053SEvan.Yan@Sun.COM case DDI_INTROP_GETTARGET: 685*10053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n")); 686*10053SEvan.Yan@Sun.COM 687*10053SEvan.Yan@Sun.COM /* Note hdlp->ih_vector is actually an irq */ 688*10053SEvan.Yan@Sun.COM if ((rv = pci_get_cpu_from_vecirq(hdlp->ih_vector, IS_IRQ)) == 689*10053SEvan.Yan@Sun.COM -1) 690*10053SEvan.Yan@Sun.COM return (DDI_FAILURE); 691*10053SEvan.Yan@Sun.COM *(int *)result = rv; 692*10053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET " 693*10053SEvan.Yan@Sun.COM "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector, rv)); 694*10053SEvan.Yan@Sun.COM break; 695*10053SEvan.Yan@Sun.COM case DDI_INTROP_SETTARGET: 696*10053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n")); 697*10053SEvan.Yan@Sun.COM 698*10053SEvan.Yan@Sun.COM /* hdlp->ih_vector is actually an irq */ 699*10053SEvan.Yan@Sun.COM tmp_hdl.ih_vector = hdlp->ih_vector; 700*10053SEvan.Yan@Sun.COM tmp_hdl.ih_flags = PSMGI_INTRBY_IRQ; 701*10053SEvan.Yan@Sun.COM tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result; 702*10053SEvan.Yan@Sun.COM psm_rval = (*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU, 703*10053SEvan.Yan@Sun.COM &psm_status); 704*10053SEvan.Yan@Sun.COM 705*10053SEvan.Yan@Sun.COM if (psm_rval != PSM_SUCCESS) 706*10053SEvan.Yan@Sun.COM return (DDI_FAILURE); 707*10053SEvan.Yan@Sun.COM break; 708881Sjohnny default: 709881Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 710881Sjohnny } 711881Sjohnny 712881Sjohnny return (DDI_SUCCESS); 713881Sjohnny } 714881Sjohnny 715916Sschwartz int 716916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 717916Sschwartz int vecirq, boolean_t is_irq) 718916Sschwartz { 719916Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl; 720916Sschwartz 721916Sschwartz if (is_irq) 722916Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 723916Sschwartz 724916Sschwartz /* 725916Sschwartz * For this locally-declared and used handle, ih_private will contain a 726916Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 727916Sschwartz * global interrupt handling. 728916Sschwartz */ 729916Sschwartz get_info_ii_hdl.ih_private = intrinfo_p; 730916Sschwartz get_info_ii_hdl.ih_vector = (ushort_t)vecirq; 731916Sschwartz 732916Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 733916Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 734916Sschwartz return (DDI_FAILURE); 735916Sschwartz 736916Sschwartz return (DDI_SUCCESS); 737916Sschwartz } 738916Sschwartz 739916Sschwartz 740916Sschwartz int 741916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 742916Sschwartz { 743916Sschwartz int rval; 744916Sschwartz 745916Sschwartz apic_get_intr_t intrinfo; 746916Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 747916Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 748916Sschwartz 749916Sschwartz if (rval == DDI_SUCCESS) 750916Sschwartz return (intrinfo.avgi_cpu_id); 751916Sschwartz else 752916Sschwartz return (-1); 753916Sschwartz } 754916Sschwartz 755881Sjohnny 756881Sjohnny static int 757881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 758881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 759881Sjohnny { 760881Sjohnny struct intrspec *ispec; 761916Sschwartz int irq; 762916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 763881Sjohnny 764881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 765881Sjohnny (void *)hdlp, inum)); 766881Sjohnny 767881Sjohnny /* Translate the interrupt if needed */ 768881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 7692288Sanish if (ispec == NULL) 7702288Sanish return (DDI_FAILURE); 7712288Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 772881Sjohnny ispec->intrspec_vec = inum; 773916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 774881Sjohnny 775881Sjohnny /* translate the interrupt if needed */ 776916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 777916Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 778916Sschwartz hdlp->ih_pri, irq)); 779881Sjohnny 780881Sjohnny /* Add the interrupt handler */ 781881Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 782916Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 783916Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 784881Sjohnny return (DDI_FAILURE); 785881Sjohnny 786916Sschwartz /* Note this really is an irq. */ 787916Sschwartz hdlp->ih_vector = (ushort_t)irq; 788916Sschwartz 789881Sjohnny return (DDI_SUCCESS); 790881Sjohnny } 791881Sjohnny 792881Sjohnny 793881Sjohnny static void 794881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 795881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 796881Sjohnny { 797916Sschwartz int irq; 798881Sjohnny struct intrspec *ispec; 799916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 800881Sjohnny 801881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 802881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 8032288Sanish if (ispec == NULL) 8042288Sanish return; 8052288Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 806881Sjohnny ispec->intrspec_vec = inum; 807916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 808881Sjohnny 809881Sjohnny /* translate the interrupt if needed */ 810916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 811881Sjohnny 812881Sjohnny /* Disable the interrupt handler */ 813916Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 814916Sschwartz ihdl_plat_datap->ip_ispecp = NULL; 815881Sjohnny } 816881Sjohnny 817881Sjohnny /* 818881Sjohnny * Miscellaneous library function 819881Sjohnny */ 820881Sjohnny int 821881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 822881Sjohnny { 823881Sjohnny int i; 824881Sjohnny int number; 825881Sjohnny int assigned_addr_len; 826881Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi; 827881Sjohnny pci_regspec_t *assigned_addr; 828881Sjohnny 829881Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 830881Sjohnny (phys_hi & PCI_RELOCAT_B)) 831881Sjohnny return (DDI_SUCCESS); 832881Sjohnny 833881Sjohnny /* 834881Sjohnny * the "reg" property specifies relocatable, get and interpret the 835881Sjohnny * "assigned-addresses" property. 836881Sjohnny */ 837881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 838881Sjohnny "assigned-addresses", (int **)&assigned_addr, 839881Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 840881Sjohnny return (DDI_FAILURE); 841881Sjohnny 842881Sjohnny /* 843881Sjohnny * Scan the "assigned-addresses" for one that matches the specified 844881Sjohnny * "reg" property entry. 845881Sjohnny */ 846881Sjohnny phys_hi &= PCI_CONF_ADDR_MASK; 847881Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 848881Sjohnny for (i = 0; i < number; i++) { 849881Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 850881Sjohnny phys_hi) { 851881Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 852881Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 853881Sjohnny ddi_prop_free(assigned_addr); 854881Sjohnny return (DDI_SUCCESS); 855881Sjohnny } 856881Sjohnny } 857881Sjohnny 858881Sjohnny ddi_prop_free(assigned_addr); 859881Sjohnny return (DDI_FAILURE); 860881Sjohnny } 861881Sjohnny 862881Sjohnny 863881Sjohnny /* 864881Sjohnny * For pci_tools 865881Sjohnny */ 866881Sjohnny 867881Sjohnny int 868881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 869881Sjohnny int mode, cred_t *credp, int *rvalp) 870881Sjohnny { 871881Sjohnny int rv = ENOTTY; 872881Sjohnny 873881Sjohnny minor_t minor = getminor(dev); 874881Sjohnny 875881Sjohnny switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 876881Sjohnny case PCI_TOOL_REG_MINOR_NUM: 877881Sjohnny 878881Sjohnny switch (cmd) { 879881Sjohnny case PCITOOL_DEVICE_SET_REG: 880881Sjohnny case PCITOOL_DEVICE_GET_REG: 881881Sjohnny 882881Sjohnny /* Require full privileges. */ 883881Sjohnny if (secpolicy_kmdb(credp)) 884881Sjohnny rv = EPERM; 885881Sjohnny else 886881Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg, 887881Sjohnny cmd, mode); 888881Sjohnny break; 889881Sjohnny 890881Sjohnny case PCITOOL_NEXUS_SET_REG: 891881Sjohnny case PCITOOL_NEXUS_GET_REG: 892881Sjohnny 893881Sjohnny /* Require full privileges. */ 894881Sjohnny if (secpolicy_kmdb(credp)) 895881Sjohnny rv = EPERM; 896881Sjohnny else 897881Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg, 898881Sjohnny cmd, mode); 899881Sjohnny break; 900881Sjohnny } 901881Sjohnny break; 902881Sjohnny 903881Sjohnny case PCI_TOOL_INTR_MINOR_NUM: 904881Sjohnny 905881Sjohnny switch (cmd) { 906881Sjohnny case PCITOOL_DEVICE_SET_INTR: 907881Sjohnny 908881Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 909881Sjohnny if (secpolicy_ponline(credp)) { 910881Sjohnny rv = EPERM; 911881Sjohnny break; 912881Sjohnny } 913881Sjohnny 914881Sjohnny /*FALLTHRU*/ 915881Sjohnny /* These require no special privileges. */ 916881Sjohnny case PCITOOL_DEVICE_GET_INTR: 9174397Sschwartz case PCITOOL_SYSTEM_INTR_INFO: 918881Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 919881Sjohnny break; 920881Sjohnny } 921881Sjohnny break; 922881Sjohnny 923881Sjohnny /* 924881Sjohnny * All non-PCItool ioctls go through here, including: 925881Sjohnny * devctl ioctls with minor number PCIHP_DEVCTL_MINOR and 926881Sjohnny * those for attachment points with where minor number is the 927881Sjohnny * device number. 928881Sjohnny */ 929881Sjohnny default: 930881Sjohnny rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 931881Sjohnny credp, rvalp); 932881Sjohnny break; 933881Sjohnny } 934881Sjohnny 935881Sjohnny return (rv); 936881Sjohnny } 9371083Sanish 9381083Sanish 9391865Sdilpreet int 9401865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 9411865Sdilpreet { 9421865Sdilpreet size_t size = in_args->size; 9431865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 9441865Sdilpreet uintptr_t host_addr = in_args->host_addr; 9451865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 9461865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 9471865Sdilpreet size_t repcount = in_args->repcount; 9481865Sdilpreet uint_t flags = in_args->flags; 9491865Sdilpreet int err = DDI_SUCCESS; 9501865Sdilpreet 9511865Sdilpreet /* 9521865Sdilpreet * if no handle then this is a poke. We have to return failure here 9531865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 9541865Sdilpreet */ 9551865Sdilpreet if (in_args->handle == NULL) 9561865Sdilpreet return (DDI_FAILURE); 9571865Sdilpreet 9581865Sdilpreet /* 9591865Sdilpreet * rest of this function is actually for cautious puts 9601865Sdilpreet */ 9611865Sdilpreet for (; repcount; repcount--) { 9621865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 9631865Sdilpreet switch (size) { 9641865Sdilpreet case sizeof (uint8_t): 9651865Sdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr, 9661865Sdilpreet *(uint8_t *)host_addr); 9671865Sdilpreet break; 9681865Sdilpreet case sizeof (uint16_t): 9691865Sdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr, 9701865Sdilpreet *(uint16_t *)host_addr); 9711865Sdilpreet break; 9721865Sdilpreet case sizeof (uint32_t): 9731865Sdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr, 9741865Sdilpreet *(uint32_t *)host_addr); 9751865Sdilpreet break; 9761865Sdilpreet case sizeof (uint64_t): 9771865Sdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr, 9781865Sdilpreet *(uint64_t *)host_addr); 9791865Sdilpreet break; 9801865Sdilpreet default: 9811865Sdilpreet err = DDI_FAILURE; 9821865Sdilpreet break; 9831865Sdilpreet } 9841865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 9851865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 9861865Sdilpreet DDI_STRUCTURE_BE_ACC) { 9871865Sdilpreet switch (size) { 9881865Sdilpreet case sizeof (uint8_t): 9891865Sdilpreet i_ddi_io_put8(hp, 9901865Sdilpreet (uint8_t *)dev_addr, 9911865Sdilpreet *(uint8_t *)host_addr); 9921865Sdilpreet break; 9931865Sdilpreet case sizeof (uint16_t): 9941865Sdilpreet i_ddi_io_swap_put16(hp, 9951865Sdilpreet (uint16_t *)dev_addr, 9961865Sdilpreet *(uint16_t *)host_addr); 9971865Sdilpreet break; 9981865Sdilpreet case sizeof (uint32_t): 9991865Sdilpreet i_ddi_io_swap_put32(hp, 10001865Sdilpreet (uint32_t *)dev_addr, 10011865Sdilpreet *(uint32_t *)host_addr); 10021865Sdilpreet break; 10031865Sdilpreet /* 10041865Sdilpreet * note the 64-bit case is a dummy 10051865Sdilpreet * function - so no need to swap 10061865Sdilpreet */ 10071865Sdilpreet case sizeof (uint64_t): 10081865Sdilpreet i_ddi_io_put64(hp, 10091865Sdilpreet (uint64_t *)dev_addr, 10101865Sdilpreet *(uint64_t *)host_addr); 10111865Sdilpreet break; 10121865Sdilpreet default: 10131865Sdilpreet err = DDI_FAILURE; 10141865Sdilpreet break; 10151865Sdilpreet } 10161865Sdilpreet } else { 10171865Sdilpreet switch (size) { 10181865Sdilpreet case sizeof (uint8_t): 10191865Sdilpreet i_ddi_io_put8(hp, 10201865Sdilpreet (uint8_t *)dev_addr, 10211865Sdilpreet *(uint8_t *)host_addr); 10221865Sdilpreet break; 10231865Sdilpreet case sizeof (uint16_t): 10241865Sdilpreet i_ddi_io_put16(hp, 10251865Sdilpreet (uint16_t *)dev_addr, 10261865Sdilpreet *(uint16_t *)host_addr); 10271865Sdilpreet break; 10281865Sdilpreet case sizeof (uint32_t): 10291865Sdilpreet i_ddi_io_put32(hp, 10301865Sdilpreet (uint32_t *)dev_addr, 10311865Sdilpreet *(uint32_t *)host_addr); 10321865Sdilpreet break; 10331865Sdilpreet case sizeof (uint64_t): 10341865Sdilpreet i_ddi_io_put64(hp, 10351865Sdilpreet (uint64_t *)dev_addr, 10361865Sdilpreet *(uint64_t *)host_addr); 10371865Sdilpreet break; 10381865Sdilpreet default: 10391865Sdilpreet err = DDI_FAILURE; 10401865Sdilpreet break; 10411865Sdilpreet } 10421865Sdilpreet } 10431865Sdilpreet } else { 10441865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 10451865Sdilpreet DDI_STRUCTURE_BE_ACC) { 10461865Sdilpreet switch (size) { 10471865Sdilpreet case sizeof (uint8_t): 10481865Sdilpreet *(uint8_t *)dev_addr = 10491865Sdilpreet *(uint8_t *)host_addr; 10501865Sdilpreet break; 10511865Sdilpreet case sizeof (uint16_t): 10521865Sdilpreet *(uint16_t *)dev_addr = 10531865Sdilpreet ddi_swap16(*(uint16_t *)host_addr); 10541865Sdilpreet break; 10551865Sdilpreet case sizeof (uint32_t): 10561865Sdilpreet *(uint32_t *)dev_addr = 10571865Sdilpreet ddi_swap32(*(uint32_t *)host_addr); 10581865Sdilpreet break; 10591865Sdilpreet case sizeof (uint64_t): 10601865Sdilpreet *(uint64_t *)dev_addr = 10611865Sdilpreet ddi_swap64(*(uint64_t *)host_addr); 10621865Sdilpreet break; 10631865Sdilpreet default: 10641865Sdilpreet err = DDI_FAILURE; 10651865Sdilpreet break; 10661865Sdilpreet } 10671865Sdilpreet } else { 10681865Sdilpreet switch (size) { 10691865Sdilpreet case sizeof (uint8_t): 10701865Sdilpreet *(uint8_t *)dev_addr = 10711865Sdilpreet *(uint8_t *)host_addr; 10721865Sdilpreet break; 10731865Sdilpreet case sizeof (uint16_t): 10741865Sdilpreet *(uint16_t *)dev_addr = 10751865Sdilpreet *(uint16_t *)host_addr; 10761865Sdilpreet break; 10771865Sdilpreet case sizeof (uint32_t): 10781865Sdilpreet *(uint32_t *)dev_addr = 10791865Sdilpreet *(uint32_t *)host_addr; 10801865Sdilpreet break; 10811865Sdilpreet case sizeof (uint64_t): 10821865Sdilpreet *(uint64_t *)dev_addr = 10831865Sdilpreet *(uint64_t *)host_addr; 10841865Sdilpreet break; 10851865Sdilpreet default: 10861865Sdilpreet err = DDI_FAILURE; 10871865Sdilpreet break; 10881865Sdilpreet } 10891865Sdilpreet } 10901865Sdilpreet } 10911865Sdilpreet host_addr += size; 10921865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 10931865Sdilpreet dev_addr += size; 10941865Sdilpreet } 10951865Sdilpreet return (err); 10961865Sdilpreet } 10971865Sdilpreet 10981865Sdilpreet 10991865Sdilpreet int 11001865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 11011865Sdilpreet { 11021865Sdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 11031865Sdilpreet 11041865Sdilpreet /* endian-ness check */ 11051865Sdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 11061865Sdilpreet return (DDI_FAILURE); 11071865Sdilpreet 11081865Sdilpreet /* 11091865Sdilpreet * range check 11101865Sdilpreet */ 11111865Sdilpreet if ((offset >= PCI_CONF_HDR_SIZE) || 11121865Sdilpreet (len > PCI_CONF_HDR_SIZE) || 11131865Sdilpreet (offset + len > PCI_CONF_HDR_SIZE)) 11141865Sdilpreet return (DDI_FAILURE); 11151865Sdilpreet 11161865Sdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 11171865Sdilpreet /* 11181865Sdilpreet * always use cautious mechanism for config space gets 11191865Sdilpreet */ 11201865Sdilpreet ap->ahi_get8 = i_ddi_caut_get8; 11211865Sdilpreet ap->ahi_get16 = i_ddi_caut_get16; 11221865Sdilpreet ap->ahi_get32 = i_ddi_caut_get32; 11231865Sdilpreet ap->ahi_get64 = i_ddi_caut_get64; 11241865Sdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 11251865Sdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 11261865Sdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 11271865Sdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 11281865Sdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 11291865Sdilpreet ap->ahi_put8 = i_ddi_caut_put8; 11301865Sdilpreet ap->ahi_put16 = i_ddi_caut_put16; 11311865Sdilpreet ap->ahi_put32 = i_ddi_caut_put32; 11321865Sdilpreet ap->ahi_put64 = i_ddi_caut_put64; 11331865Sdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 11341865Sdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 11351865Sdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 11361865Sdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 11371865Sdilpreet } else { 11381865Sdilpreet ap->ahi_put8 = pci_config_wr8; 11391865Sdilpreet ap->ahi_put16 = pci_config_wr16; 11401865Sdilpreet ap->ahi_put32 = pci_config_wr32; 11411865Sdilpreet ap->ahi_put64 = pci_config_wr64; 11421865Sdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8; 11431865Sdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16; 11441865Sdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32; 11451865Sdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64; 11461865Sdilpreet } 11471865Sdilpreet 11481865Sdilpreet /* Initialize to default check/notify functions */ 11491865Sdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check; 11501865Sdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify; 11511865Sdilpreet ap->ahi_fault = 0; 11521865Sdilpreet impl_acc_err_init(hp); 11531865Sdilpreet return (DDI_SUCCESS); 11541865Sdilpreet } 11551865Sdilpreet 11561865Sdilpreet 11571865Sdilpreet int 11581865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 11591865Sdilpreet { 11601865Sdilpreet size_t size = in_args->size; 11611865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 11621865Sdilpreet uintptr_t host_addr = in_args->host_addr; 11631865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 11641865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 11651865Sdilpreet size_t repcount = in_args->repcount; 11661865Sdilpreet uint_t flags = in_args->flags; 11671865Sdilpreet int err = DDI_SUCCESS; 11681865Sdilpreet 11691865Sdilpreet /* 11701865Sdilpreet * if no handle then this is a peek. We have to return failure here 11711865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 11721865Sdilpreet */ 11731865Sdilpreet if (in_args->handle == NULL) 11741865Sdilpreet return (DDI_FAILURE); 11751865Sdilpreet 11761865Sdilpreet for (; repcount; repcount--) { 11771865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 11781865Sdilpreet switch (size) { 11791865Sdilpreet case sizeof (uint8_t): 11801865Sdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp, 11811865Sdilpreet (uint8_t *)dev_addr); 11821865Sdilpreet break; 11831865Sdilpreet case sizeof (uint16_t): 11841865Sdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp, 11851865Sdilpreet (uint16_t *)dev_addr); 11861865Sdilpreet break; 11871865Sdilpreet case sizeof (uint32_t): 11881865Sdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp, 11891865Sdilpreet (uint32_t *)dev_addr); 11901865Sdilpreet break; 11911865Sdilpreet case sizeof (uint64_t): 11921865Sdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp, 11931865Sdilpreet (uint64_t *)dev_addr); 11941865Sdilpreet break; 11951865Sdilpreet default: 11961865Sdilpreet err = DDI_FAILURE; 11971865Sdilpreet break; 11981865Sdilpreet } 11991865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 12001865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12011865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12021865Sdilpreet switch (size) { 12031865Sdilpreet case sizeof (uint8_t): 12041865Sdilpreet *(uint8_t *)host_addr = 12051865Sdilpreet i_ddi_io_get8(hp, 12061865Sdilpreet (uint8_t *)dev_addr); 12071865Sdilpreet break; 12081865Sdilpreet case sizeof (uint16_t): 12091865Sdilpreet *(uint16_t *)host_addr = 12101865Sdilpreet i_ddi_io_swap_get16(hp, 12111865Sdilpreet (uint16_t *)dev_addr); 12121865Sdilpreet break; 12131865Sdilpreet case sizeof (uint32_t): 12141865Sdilpreet *(uint32_t *)host_addr = 12151865Sdilpreet i_ddi_io_swap_get32(hp, 12161865Sdilpreet (uint32_t *)dev_addr); 12171865Sdilpreet break; 12181865Sdilpreet /* 12191865Sdilpreet * note the 64-bit case is a dummy 12201865Sdilpreet * function - so no need to swap 12211865Sdilpreet */ 12221865Sdilpreet case sizeof (uint64_t): 12231865Sdilpreet *(uint64_t *)host_addr = 12241865Sdilpreet i_ddi_io_get64(hp, 12251865Sdilpreet (uint64_t *)dev_addr); 12261865Sdilpreet break; 12271865Sdilpreet default: 12281865Sdilpreet err = DDI_FAILURE; 12291865Sdilpreet break; 12301865Sdilpreet } 12311865Sdilpreet } else { 12321865Sdilpreet switch (size) { 12331865Sdilpreet case sizeof (uint8_t): 12341865Sdilpreet *(uint8_t *)host_addr = 12351865Sdilpreet i_ddi_io_get8(hp, 12361865Sdilpreet (uint8_t *)dev_addr); 12371865Sdilpreet break; 12381865Sdilpreet case sizeof (uint16_t): 12391865Sdilpreet *(uint16_t *)host_addr = 12401865Sdilpreet i_ddi_io_get16(hp, 12411865Sdilpreet (uint16_t *)dev_addr); 12421865Sdilpreet break; 12431865Sdilpreet case sizeof (uint32_t): 12441865Sdilpreet *(uint32_t *)host_addr = 12451865Sdilpreet i_ddi_io_get32(hp, 12461865Sdilpreet (uint32_t *)dev_addr); 12471865Sdilpreet break; 12481865Sdilpreet case sizeof (uint64_t): 12491865Sdilpreet *(uint64_t *)host_addr = 12501865Sdilpreet i_ddi_io_get64(hp, 12511865Sdilpreet (uint64_t *)dev_addr); 12521865Sdilpreet break; 12531865Sdilpreet default: 12541865Sdilpreet err = DDI_FAILURE; 12551865Sdilpreet break; 12561865Sdilpreet } 12571865Sdilpreet } 12581865Sdilpreet } else { 12591865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12601865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12611865Sdilpreet switch (in_args->size) { 12621865Sdilpreet case sizeof (uint8_t): 12631865Sdilpreet *(uint8_t *)host_addr = 12641865Sdilpreet *(uint8_t *)dev_addr; 12651865Sdilpreet break; 12661865Sdilpreet case sizeof (uint16_t): 12671865Sdilpreet *(uint16_t *)host_addr = 12681865Sdilpreet ddi_swap16(*(uint16_t *)dev_addr); 12691865Sdilpreet break; 12701865Sdilpreet case sizeof (uint32_t): 12711865Sdilpreet *(uint32_t *)host_addr = 12721865Sdilpreet ddi_swap32(*(uint32_t *)dev_addr); 12731865Sdilpreet break; 12741865Sdilpreet case sizeof (uint64_t): 12751865Sdilpreet *(uint64_t *)host_addr = 12761865Sdilpreet ddi_swap64(*(uint64_t *)dev_addr); 12771865Sdilpreet break; 12781865Sdilpreet default: 12791865Sdilpreet err = DDI_FAILURE; 12801865Sdilpreet break; 12811865Sdilpreet } 12821865Sdilpreet } else { 12831865Sdilpreet switch (in_args->size) { 12841865Sdilpreet case sizeof (uint8_t): 12851865Sdilpreet *(uint8_t *)host_addr = 12861865Sdilpreet *(uint8_t *)dev_addr; 12871865Sdilpreet break; 12881865Sdilpreet case sizeof (uint16_t): 12891865Sdilpreet *(uint16_t *)host_addr = 12901865Sdilpreet *(uint16_t *)dev_addr; 12911865Sdilpreet break; 12921865Sdilpreet case sizeof (uint32_t): 12931865Sdilpreet *(uint32_t *)host_addr = 12941865Sdilpreet *(uint32_t *)dev_addr; 12951865Sdilpreet break; 12961865Sdilpreet case sizeof (uint64_t): 12971865Sdilpreet *(uint64_t *)host_addr = 12981865Sdilpreet *(uint64_t *)dev_addr; 12991865Sdilpreet break; 13001865Sdilpreet default: 13011865Sdilpreet err = DDI_FAILURE; 13021865Sdilpreet break; 13031865Sdilpreet } 13041865Sdilpreet } 13051865Sdilpreet } 13061865Sdilpreet host_addr += size; 13071865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 13081865Sdilpreet dev_addr += size; 13091865Sdilpreet } 13101865Sdilpreet return (err); 13111865Sdilpreet } 13121865Sdilpreet 13131865Sdilpreet /*ARGSUSED*/ 13141865Sdilpreet int 13151865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 13161865Sdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result) 13171865Sdilpreet { 13181865Sdilpreet if (ctlop == DDI_CTLOPS_PEEK) 13191865Sdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 13201865Sdilpreet else 13211865Sdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 13221865Sdilpreet } 13231865Sdilpreet 13241083Sanish /* 13251083Sanish * These are the get and put functions to be shared with drivers. The 13261083Sanish * mutex locking is done inside the functions referenced, rather than 13271083Sanish * here, and is thus shared across PCI child drivers and any other 13281083Sanish * consumers of PCI config space (such as the ACPI subsystem). 13291083Sanish * 13301083Sanish * The configuration space addresses come in as pointers. This is fine on 13311083Sanish * a 32-bit system, where the VM space and configuration space are the same 13321083Sanish * size. It's not such a good idea on a 64-bit system, where memory 13331083Sanish * addresses are twice as large as configuration space addresses. At some 13341083Sanish * point in the call tree we need to take a stand and say "you are 32-bit 13351083Sanish * from this time forth", and this seems like a nice self-contained place. 13361083Sanish */ 13371083Sanish 13381083Sanish uint8_t 13391083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 13401083Sanish { 13411083Sanish pci_acc_cfblk_t *cfp; 13421083Sanish uint8_t rval; 13431083Sanish int reg; 13441083Sanish 13451083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13461083Sanish 13471083Sanish reg = (int)(uintptr_t)addr; 13481083Sanish 13491083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13501083Sanish 13511083Sanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 13521083Sanish reg); 13531083Sanish 13541083Sanish return (rval); 13551083Sanish } 13561083Sanish 13571083Sanish void 13581083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 13591083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 13601083Sanish { 13611083Sanish uint8_t *h, *d; 13621083Sanish 13631083Sanish h = host_addr; 13641083Sanish d = dev_addr; 13651083Sanish 13661083Sanish if (flags == DDI_DEV_AUTOINCR) 13671083Sanish for (; repcount; repcount--) 13681083Sanish *h++ = pci_config_rd8(hdlp, d++); 13691083Sanish else 13701083Sanish for (; repcount; repcount--) 13711083Sanish *h++ = pci_config_rd8(hdlp, d); 13721083Sanish } 13731083Sanish 13741083Sanish uint16_t 13751083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 13761083Sanish { 13771083Sanish pci_acc_cfblk_t *cfp; 13781083Sanish uint16_t rval; 13791083Sanish int reg; 13801083Sanish 13811083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13821083Sanish 13831083Sanish reg = (int)(uintptr_t)addr; 13841083Sanish 13851083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13861083Sanish 13871083Sanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 13881083Sanish reg); 13891083Sanish 13901083Sanish return (rval); 13911083Sanish } 13921083Sanish 13931083Sanish void 13941083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 13951083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 13961083Sanish { 13971083Sanish uint16_t *h, *d; 13981083Sanish 13991083Sanish h = host_addr; 14001083Sanish d = dev_addr; 14011083Sanish 14021083Sanish if (flags == DDI_DEV_AUTOINCR) 14031083Sanish for (; repcount; repcount--) 14041083Sanish *h++ = pci_config_rd16(hdlp, d++); 14051083Sanish else 14061083Sanish for (; repcount; repcount--) 14071083Sanish *h++ = pci_config_rd16(hdlp, d); 14081083Sanish } 14091083Sanish 14101083Sanish uint32_t 14111083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 14121083Sanish { 14131083Sanish pci_acc_cfblk_t *cfp; 14141083Sanish uint32_t rval; 14151083Sanish int reg; 14161083Sanish 14171083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14181083Sanish 14191083Sanish reg = (int)(uintptr_t)addr; 14201083Sanish 14211083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14221083Sanish 14231083Sanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 14241083Sanish cfp->c_funcnum, reg); 14251083Sanish 14261083Sanish return (rval); 14271083Sanish } 14281083Sanish 14291083Sanish void 14301083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 14311083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 14321083Sanish { 14331083Sanish uint32_t *h, *d; 14341083Sanish 14351083Sanish h = host_addr; 14361083Sanish d = dev_addr; 14371083Sanish 14381083Sanish if (flags == DDI_DEV_AUTOINCR) 14391083Sanish for (; repcount; repcount--) 14401083Sanish *h++ = pci_config_rd32(hdlp, d++); 14411083Sanish else 14421083Sanish for (; repcount; repcount--) 14431083Sanish *h++ = pci_config_rd32(hdlp, d); 14441083Sanish } 14451083Sanish 14461083Sanish 14471083Sanish void 14481083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 14491083Sanish { 14501083Sanish pci_acc_cfblk_t *cfp; 14511083Sanish int reg; 14521083Sanish 14531083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14541083Sanish 14551083Sanish reg = (int)(uintptr_t)addr; 14561083Sanish 14571083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14581083Sanish 14591083Sanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 14601083Sanish cfp->c_funcnum, reg, value); 14611083Sanish } 14621083Sanish 14631083Sanish void 14641083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 14651083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 14661083Sanish { 14671083Sanish uint8_t *h, *d; 14681083Sanish 14691083Sanish h = host_addr; 14701083Sanish d = dev_addr; 14711083Sanish 14721083Sanish if (flags == DDI_DEV_AUTOINCR) 14731083Sanish for (; repcount; repcount--) 14741083Sanish pci_config_wr8(hdlp, d++, *h++); 14751083Sanish else 14761083Sanish for (; repcount; repcount--) 14771083Sanish pci_config_wr8(hdlp, d, *h++); 14781083Sanish } 14791083Sanish 14801083Sanish void 14811083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 14821083Sanish { 14831083Sanish pci_acc_cfblk_t *cfp; 14841083Sanish int reg; 14851083Sanish 14861083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14871083Sanish 14881083Sanish reg = (int)(uintptr_t)addr; 14891083Sanish 14901083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14911083Sanish 14921083Sanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 14931083Sanish cfp->c_funcnum, reg, value); 14941083Sanish } 14951083Sanish 14961083Sanish void 14971083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 14981083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 14991083Sanish { 15001083Sanish uint16_t *h, *d; 15011083Sanish 15021083Sanish h = host_addr; 15031083Sanish d = dev_addr; 15041083Sanish 15051083Sanish if (flags == DDI_DEV_AUTOINCR) 15061083Sanish for (; repcount; repcount--) 15071083Sanish pci_config_wr16(hdlp, d++, *h++); 15081083Sanish else 15091083Sanish for (; repcount; repcount--) 15101083Sanish pci_config_wr16(hdlp, d, *h++); 15111083Sanish } 15121083Sanish 15131083Sanish void 15141083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 15151083Sanish { 15161083Sanish pci_acc_cfblk_t *cfp; 15171083Sanish int reg; 15181083Sanish 15191083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15201083Sanish 15211083Sanish reg = (int)(uintptr_t)addr; 15221083Sanish 15231083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15241083Sanish 15251083Sanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 15261083Sanish cfp->c_funcnum, reg, value); 15271083Sanish } 15281083Sanish 15291083Sanish void 15301083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 15311083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 15321083Sanish { 15331083Sanish uint32_t *h, *d; 15341083Sanish 15351083Sanish h = host_addr; 15361083Sanish d = dev_addr; 15371083Sanish 15381083Sanish if (flags == DDI_DEV_AUTOINCR) 15391083Sanish for (; repcount; repcount--) 15401083Sanish pci_config_wr32(hdlp, d++, *h++); 15411083Sanish else 15421083Sanish for (; repcount; repcount--) 15431083Sanish pci_config_wr32(hdlp, d, *h++); 15441083Sanish } 15451083Sanish 15461083Sanish uint64_t 15471083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 15481083Sanish { 15491083Sanish uint32_t lw_val; 15501083Sanish uint32_t hi_val; 15511083Sanish uint32_t *dp; 15521083Sanish uint64_t val; 15531083Sanish 15541083Sanish dp = (uint32_t *)addr; 15551083Sanish lw_val = pci_config_rd32(hdlp, dp); 15561083Sanish dp++; 15571083Sanish hi_val = pci_config_rd32(hdlp, dp); 15581083Sanish val = ((uint64_t)hi_val << 32) | lw_val; 15591083Sanish return (val); 15601083Sanish } 15611083Sanish 15621083Sanish void 15631083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 15641083Sanish { 15651083Sanish uint32_t lw_val; 15661083Sanish uint32_t hi_val; 15671083Sanish uint32_t *dp; 15681083Sanish 15691083Sanish dp = (uint32_t *)addr; 15701083Sanish lw_val = (uint32_t)(value & 0xffffffff); 15711083Sanish hi_val = (uint32_t)(value >> 32); 15721083Sanish pci_config_wr32(hdlp, dp, lw_val); 15731083Sanish dp++; 15741083Sanish pci_config_wr32(hdlp, dp, hi_val); 15751083Sanish } 15761083Sanish 15771083Sanish void 15781083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 15791083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 15801083Sanish { 15811083Sanish if (flags == DDI_DEV_AUTOINCR) { 15821083Sanish for (; repcount; repcount--) 15831083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 15841083Sanish } else { 15851083Sanish for (; repcount; repcount--) 15861083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr); 15871083Sanish } 15881083Sanish } 15891083Sanish 15901083Sanish void 15911083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 15921083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 15931083Sanish { 15941083Sanish if (flags == DDI_DEV_AUTOINCR) { 15951083Sanish for (; repcount; repcount--) 15961083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr++); 15971083Sanish } else { 15981083Sanish for (; repcount; repcount--) 15991083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr); 16001083Sanish } 16011083Sanish } 1602