1881Sjohnny /* 2881Sjohnny * CDDL HEADER START 3881Sjohnny * 4881Sjohnny * The contents of this file are subject to the terms of the 51542Sjohnny * Common Development and Distribution License (the "License"). 61542Sjohnny * You may not use this file except in compliance with the License. 7881Sjohnny * 8881Sjohnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9881Sjohnny * or http://www.opensolaris.org/os/licensing. 10881Sjohnny * See the License for the specific language governing permissions 11881Sjohnny * and limitations under the License. 12881Sjohnny * 13881Sjohnny * When distributing Covered Code, include this CDDL HEADER in each 14881Sjohnny * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15881Sjohnny * If applicable, add the following below this CDDL HEADER, with the 16881Sjohnny * fields enclosed by brackets "[]" replaced with your own identifying 17881Sjohnny * information: Portions Copyright [yyyy] [name of copyright owner] 18881Sjohnny * 19881Sjohnny * CDDL HEADER END 20881Sjohnny */ 21881Sjohnny 22881Sjohnny /* 23*12683SJimmy.Vetayases@oracle.com * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24881Sjohnny */ 25881Sjohnny 26881Sjohnny /* 27881Sjohnny * File that has code which is common between pci(7d) and npe(7d) 28881Sjohnny * It shares the following: 29881Sjohnny * - interrupt code 30881Sjohnny * - pci_tools ioctl code 31881Sjohnny * - name_child code 32881Sjohnny * - set_parent_private_data code 33881Sjohnny */ 34881Sjohnny 35881Sjohnny #include <sys/conf.h> 36881Sjohnny #include <sys/pci.h> 37881Sjohnny #include <sys/sunndi.h> 38916Sschwartz #include <sys/mach_intr.h> 39881Sjohnny #include <sys/pci_intr_lib.h> 40881Sjohnny #include <sys/psm.h> 41881Sjohnny #include <sys/policy.h> 42881Sjohnny #include <sys/sysmacros.h> 43916Sschwartz #include <sys/clock.h> 443446Smrj #include <sys/apic.h> 45881Sjohnny #include <sys/pci_tools.h> 46881Sjohnny #include <io/pci/pci_var.h> 47881Sjohnny #include <io/pci/pci_tools_ext.h> 48881Sjohnny #include <io/pci/pci_common.h> 491083Sanish #include <sys/pci_cfgspace.h> 501083Sanish #include <sys/pci_impl.h> 514160Sjveta #include <sys/pci_cap.h> 52881Sjohnny 53881Sjohnny /* 54881Sjohnny * Function prototypes 55881Sjohnny */ 56881Sjohnny static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *); 57881Sjohnny static int pci_enable_intr(dev_info_t *, dev_info_t *, 58881Sjohnny ddi_intr_handle_impl_t *, uint32_t); 59881Sjohnny static void pci_disable_intr(dev_info_t *, dev_info_t *, 60881Sjohnny ddi_intr_handle_impl_t *, uint32_t); 61*12683SJimmy.Vetayases@oracle.com static int pci_alloc_intr_fixed(dev_info_t *, dev_info_t *, 62*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *, void *); 63*12683SJimmy.Vetayases@oracle.com static int pci_free_intr_fixed(dev_info_t *, dev_info_t *, 64*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *); 65881Sjohnny 66*12683SJimmy.Vetayases@oracle.com /* Extern declarations for PSM module */ 67881Sjohnny extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 68881Sjohnny psm_intr_op_t, int *); 69*12683SJimmy.Vetayases@oracle.com extern ddi_irm_pool_t *apix_irm_pool_p; 70881Sjohnny 71881Sjohnny /* 72881Sjohnny * pci_name_child: 73881Sjohnny * 74881Sjohnny * Assign the address portion of the node name 75881Sjohnny */ 76881Sjohnny int 77881Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen) 78881Sjohnny { 79881Sjohnny int dev, func, length; 80881Sjohnny char **unit_addr; 81881Sjohnny uint_t n; 82881Sjohnny pci_regspec_t *pci_rp; 83881Sjohnny 84881Sjohnny if (ndi_dev_is_persistent_node(child) == 0) { 85881Sjohnny /* 86881Sjohnny * For .conf node, use "unit-address" property 87881Sjohnny */ 88881Sjohnny if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 89881Sjohnny DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 90881Sjohnny DDI_PROP_SUCCESS) { 91881Sjohnny cmn_err(CE_WARN, "cannot find unit-address in %s.conf", 92881Sjohnny ddi_get_name(child)); 93881Sjohnny return (DDI_FAILURE); 94881Sjohnny } 95881Sjohnny if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 96881Sjohnny cmn_err(CE_WARN, "unit-address property in %s.conf" 97881Sjohnny " not well-formed", ddi_get_name(child)); 98881Sjohnny ddi_prop_free(unit_addr); 99881Sjohnny return (DDI_FAILURE); 100881Sjohnny } 101881Sjohnny (void) snprintf(name, namelen, "%s", *unit_addr); 102881Sjohnny ddi_prop_free(unit_addr); 103881Sjohnny return (DDI_SUCCESS); 104881Sjohnny } 105881Sjohnny 106881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 107881Sjohnny "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) { 108881Sjohnny cmn_err(CE_WARN, "cannot find reg property in %s", 109881Sjohnny ddi_get_name(child)); 110881Sjohnny return (DDI_FAILURE); 111881Sjohnny } 112881Sjohnny 113881Sjohnny /* copy the device identifications */ 114881Sjohnny dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 115881Sjohnny func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 116881Sjohnny 117881Sjohnny /* 118881Sjohnny * free the memory allocated by ddi_prop_lookup_int_array 119881Sjohnny */ 120881Sjohnny ddi_prop_free(pci_rp); 121881Sjohnny 122881Sjohnny if (func != 0) { 123881Sjohnny (void) snprintf(name, namelen, "%x,%x", dev, func); 124881Sjohnny } else { 125881Sjohnny (void) snprintf(name, namelen, "%x", dev); 126881Sjohnny } 127881Sjohnny 128881Sjohnny return (DDI_SUCCESS); 129881Sjohnny } 130881Sjohnny 131881Sjohnny /* 132881Sjohnny * Interrupt related code: 133881Sjohnny * 134881Sjohnny * The following busop is common to npe and pci drivers 135881Sjohnny * bus_introp 136881Sjohnny */ 137881Sjohnny 138881Sjohnny /* 139881Sjohnny * Create the ddi_parent_private_data for a pseudo child. 140881Sjohnny */ 141881Sjohnny void 142881Sjohnny pci_common_set_parent_private_data(dev_info_t *dip) 143881Sjohnny { 144881Sjohnny struct ddi_parent_private_data *pdptr; 145881Sjohnny 146881Sjohnny pdptr = (struct ddi_parent_private_data *)kmem_zalloc( 147881Sjohnny (sizeof (struct ddi_parent_private_data) + 1484397Sschwartz sizeof (struct intrspec)), KM_SLEEP); 149881Sjohnny pdptr->par_intr = (struct intrspec *)(pdptr + 1); 150881Sjohnny pdptr->par_nintr = 1; 151881Sjohnny ddi_set_parent_data(dip, pdptr); 152881Sjohnny } 153881Sjohnny 154881Sjohnny /* 155881Sjohnny * pci_get_priority: 156881Sjohnny * Figure out the priority of the device 157881Sjohnny */ 158881Sjohnny static int 159881Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri) 160881Sjohnny { 161881Sjohnny struct intrspec *ispec; 162881Sjohnny 163881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n", 164881Sjohnny (void *)dip, (void *)hdlp)); 165881Sjohnny 166881Sjohnny if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 167881Sjohnny hdlp->ih_inum)) == NULL) { 168881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 1698535Sevan.yan@sun.com *pri = pci_class_to_pil(dip); 170881Sjohnny pci_common_set_parent_private_data(hdlp->ih_dip); 171881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 172881Sjohnny hdlp->ih_inum); 173881Sjohnny return (DDI_SUCCESS); 174881Sjohnny } 175881Sjohnny return (DDI_FAILURE); 176881Sjohnny } 177881Sjohnny 178881Sjohnny *pri = ispec->intrspec_pri; 179881Sjohnny return (DDI_SUCCESS); 180881Sjohnny } 181881Sjohnny 182881Sjohnny 183881Sjohnny 18410187SKrishna.Elango@Sun.COM static int pcieb_intr_pri_counter = 0; 185881Sjohnny 186881Sjohnny /* 187881Sjohnny * pci_common_intr_ops: bus_intr_op() function for interrupt support 188881Sjohnny */ 189881Sjohnny int 190881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 191881Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 192881Sjohnny { 193881Sjohnny int priority = 0; 194881Sjohnny int psm_status = 0; 195881Sjohnny int pci_status = 0; 196881Sjohnny int pci_rval, psm_rval = PSM_FAILURE; 197881Sjohnny int types = 0; 198881Sjohnny int pciepci = 0; 1991542Sjohnny int i, j, count; 2004160Sjveta int rv; 201881Sjohnny int behavior; 2021997Sanish int cap_ptr; 2034160Sjveta uint16_t msi_cap_base, msix_cap_base, cap_ctrl; 2044160Sjveta char *prop; 205881Sjohnny ddi_intrspec_t isp; 206881Sjohnny struct intrspec *ispec; 207881Sjohnny ddi_intr_handle_impl_t tmp_hdl; 208881Sjohnny ddi_intr_msix_t *msix_p; 2091087Sschwartz ihdl_plat_t *ihdl_plat_datap; 2101542Sjohnny ddi_intr_handle_t *h_array; 2111997Sanish ddi_acc_handle_t handle; 212*12683SJimmy.Vetayases@oracle.com apic_get_intr_t intrinfo; 213881Sjohnny 214881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 215881Sjohnny "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 216881Sjohnny (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 217881Sjohnny 218881Sjohnny /* Process the request */ 219881Sjohnny switch (intr_op) { 220881Sjohnny case DDI_INTROP_SUPPORTED_TYPES: 2214160Sjveta /* 2224160Sjveta * First we determine the interrupt types supported by the 2234160Sjveta * device itself, then we filter them through what the OS 2244160Sjveta * and system supports. We determine system-level 2254160Sjveta * interrupt type support for anything other than fixed intrs 2264160Sjveta * through the psm_intr_ops vector 2274160Sjveta */ 2284160Sjveta rv = DDI_FAILURE; 2294160Sjveta 230881Sjohnny /* Fixed supported by default */ 2314160Sjveta types = DDI_INTR_TYPE_FIXED; 2324160Sjveta 2334160Sjveta if (psm_intr_ops == NULL) { 2344160Sjveta *(int *)result = types; 2354160Sjveta return (DDI_SUCCESS); 2364160Sjveta } 2374160Sjveta if (pci_config_setup(rdip, &handle) != DDI_SUCCESS) 2384160Sjveta return (DDI_FAILURE); 239881Sjohnny 2404160Sjveta /* Sanity test cap control values if found */ 2414160Sjveta 2424160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) == 2434160Sjveta DDI_SUCCESS) { 2444160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base, 2454160Sjveta PCI_MSI_CTRL); 2464160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 2474160Sjveta goto SUPPORTED_TYPES_OUT; 2484160Sjveta 2494160Sjveta types |= DDI_INTR_TYPE_MSI; 2504160Sjveta } 2514160Sjveta 2524160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) == 2534160Sjveta DDI_SUCCESS) { 2544160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base, 2554160Sjveta PCI_MSIX_CTRL); 2564160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 2574160Sjveta goto SUPPORTED_TYPES_OUT; 258881Sjohnny 2594160Sjveta types |= DDI_INTR_TYPE_MSIX; 2604160Sjveta } 2614160Sjveta 2624160Sjveta /* 2634160Sjveta * Filter device-level types through system-level support 2644160Sjveta */ 2654160Sjveta tmp_hdl.ih_type = types; 2664160Sjveta if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI, 2674160Sjveta &types) != PSM_SUCCESS) 2684160Sjveta goto SUPPORTED_TYPES_OUT; 2694160Sjveta 2704160Sjveta DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 2714160Sjveta "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, 272*12683SJimmy.Vetayases@oracle.com types)); 273881Sjohnny 2744160Sjveta /* 2754160Sjveta * Export any MSI/MSI-X cap locations via properties 2764160Sjveta */ 2774160Sjveta if (types & DDI_INTR_TYPE_MSI) { 2784160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 2794160Sjveta "pci-msi-capid-pointer", (int)msi_cap_base) != 2804160Sjveta DDI_PROP_SUCCESS) 2814160Sjveta goto SUPPORTED_TYPES_OUT; 282881Sjohnny } 2834160Sjveta if (types & DDI_INTR_TYPE_MSIX) { 2844160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 2854160Sjveta "pci-msix-capid-pointer", (int)msix_cap_base) != 2864160Sjveta DDI_PROP_SUCCESS) 2874160Sjveta goto SUPPORTED_TYPES_OUT; 2884160Sjveta } 2894160Sjveta 2904160Sjveta rv = DDI_SUCCESS; 2914160Sjveta 2924160Sjveta SUPPORTED_TYPES_OUT: 2934160Sjveta *(int *)result = types; 2944160Sjveta pci_config_teardown(&handle); 2954160Sjveta return (rv); 2964160Sjveta 2972580Sanish case DDI_INTROP_NAVAIL: 298881Sjohnny case DDI_INTROP_NINTRS: 2992580Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 3002580Sanish if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type, 3012580Sanish result) != DDI_SUCCESS) 3022580Sanish return (DDI_FAILURE); 3032580Sanish } else { 3042580Sanish *(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip); 3052580Sanish if (*(int *)result == 0) 3062580Sanish return (DDI_FAILURE); 3072580Sanish } 308881Sjohnny break; 309881Sjohnny case DDI_INTROP_ALLOC: 310*12683SJimmy.Vetayases@oracle.com 311*12683SJimmy.Vetayases@oracle.com /* 312*12683SJimmy.Vetayases@oracle.com * FIXED type 313*12683SJimmy.Vetayases@oracle.com */ 314*12683SJimmy.Vetayases@oracle.com if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 315*12683SJimmy.Vetayases@oracle.com return (pci_alloc_intr_fixed(pdip, rdip, hdlp, result)); 316881Sjohnny /* 317881Sjohnny * MSI or MSIX (figure out number of vectors available) 318881Sjohnny */ 319881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 320881Sjohnny (psm_intr_ops != NULL) && 321881Sjohnny (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) { 322881Sjohnny /* 32310187SKrishna.Elango@Sun.COM * Following check is a special case for 'pcieb'. 324881Sjohnny * This makes sure vectors with the right priority 32510187SKrishna.Elango@Sun.COM * are allocated for pcieb during ALLOC time. 326881Sjohnny */ 32710187SKrishna.Elango@Sun.COM if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) { 328881Sjohnny hdlp->ih_pri = 32910187SKrishna.Elango@Sun.COM (pcieb_intr_pri_counter % 2) ? 4 : 7; 330881Sjohnny pciepci = 1; 331881Sjohnny } else 332881Sjohnny hdlp->ih_pri = priority; 3331717Swesolows behavior = (int)(uintptr_t)hdlp->ih_scratch2; 3341997Sanish 3351997Sanish /* 3361997Sanish * Cache in the config handle and cap_ptr 3371997Sanish */ 3381997Sanish if (i_ddi_get_pci_config_handle(rdip) == NULL) { 3391997Sanish if (pci_config_setup(rdip, &handle) != 3401997Sanish DDI_SUCCESS) 3411997Sanish return (DDI_FAILURE); 3421997Sanish i_ddi_set_pci_config_handle(rdip, handle); 3431997Sanish } 3441997Sanish 3454160Sjveta prop = NULL; 3464160Sjveta cap_ptr = 0; 3474160Sjveta if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 3484160Sjveta prop = "pci-msi-capid-pointer"; 3494160Sjveta else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) 3504160Sjveta prop = "pci-msix-capid-pointer"; 3511997Sanish 3524160Sjveta /* 3534160Sjveta * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES 3544160Sjveta * for MSI(X) before allocation 3554160Sjveta */ 3564160Sjveta if (prop != NULL) { 3571997Sanish cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 3584160Sjveta DDI_PROP_DONTPASS, prop, 0); 3594160Sjveta if (cap_ptr == 0) { 3604160Sjveta DDI_INTR_NEXDBG((CE_CONT, 3614160Sjveta "pci_common_intr_ops: rdip: 0x%p " 3624160Sjveta "attempted MSI(X) alloc without " 3634160Sjveta "cap property\n", (void *)rdip)); 3644160Sjveta return (DDI_FAILURE); 3654160Sjveta } 3661997Sanish } 3674160Sjveta i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); 3681997Sanish 3694160Sjveta /* 3704160Sjveta * Allocate interrupt vectors 3714160Sjveta */ 372881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 373881Sjohnny PSM_INTR_OP_ALLOC_VECTORS, result); 374881Sjohnny 3753112Sanish if (*(int *)result == 0) 3763112Sanish return (DDI_INTR_NOTFOUND); 3773112Sanish 378881Sjohnny /* verify behavior flag and take appropriate action */ 379881Sjohnny if ((behavior == DDI_INTR_ALLOC_STRICT) && 380881Sjohnny (*(int *)result < hdlp->ih_scratch1)) { 381881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 382881Sjohnny "pci_common_intr_ops: behavior %x, " 383881Sjohnny "couldn't get enough intrs\n", behavior)); 384881Sjohnny hdlp->ih_scratch1 = *(int *)result; 385881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 386881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 387881Sjohnny return (DDI_EAGAIN); 388881Sjohnny } 389881Sjohnny 390881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 391881Sjohnny if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 392881Sjohnny msix_p = pci_msix_init(hdlp->ih_dip); 39310647SLipeng.Sang@Sun.COM if (msix_p) { 394881Sjohnny i_ddi_set_msix(hdlp->ih_dip, 395881Sjohnny msix_p); 39610647SLipeng.Sang@Sun.COM } else { 39710647SLipeng.Sang@Sun.COM DDI_INTR_NEXDBG((CE_CONT, 39810647SLipeng.Sang@Sun.COM "pci_common_intr_ops: MSI-X" 39910647SLipeng.Sang@Sun.COM "table initilization failed" 40010647SLipeng.Sang@Sun.COM ", rdip 0x%p inum 0x%x\n", 40110647SLipeng.Sang@Sun.COM (void *)rdip, 40210647SLipeng.Sang@Sun.COM hdlp->ih_inum)); 40310647SLipeng.Sang@Sun.COM 40410647SLipeng.Sang@Sun.COM (void) (*psm_intr_ops)(rdip, 40510647SLipeng.Sang@Sun.COM hdlp, 40610647SLipeng.Sang@Sun.COM PSM_INTR_OP_FREE_VECTORS, 40710647SLipeng.Sang@Sun.COM NULL); 40810647SLipeng.Sang@Sun.COM 40910647SLipeng.Sang@Sun.COM return (DDI_FAILURE); 41010647SLipeng.Sang@Sun.COM } 411881Sjohnny } 412881Sjohnny } 413881Sjohnny 414881Sjohnny if (pciepci) { 415881Sjohnny /* update priority in ispec */ 416881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, 4174397Sschwartz (int)hdlp->ih_inum); 418881Sjohnny ispec = (struct intrspec *)isp; 419881Sjohnny if (ispec) 420881Sjohnny ispec->intrspec_pri = hdlp->ih_pri; 42110187SKrishna.Elango@Sun.COM ++pcieb_intr_pri_counter; 422881Sjohnny } 423881Sjohnny 424881Sjohnny } else 425881Sjohnny return (DDI_FAILURE); 426881Sjohnny break; 427881Sjohnny case DDI_INTROP_FREE: 428881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 429881Sjohnny (psm_intr_ops != NULL)) { 4302018Sanish if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 == 4312018Sanish 0) { 4321997Sanish if (handle = i_ddi_get_pci_config_handle( 4331997Sanish rdip)) { 4341997Sanish (void) pci_config_teardown(&handle); 4351997Sanish i_ddi_set_pci_config_handle(rdip, NULL); 4361997Sanish } 4371997Sanish if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip)) 4381997Sanish i_ddi_set_msi_msix_cap_ptr(rdip, 0); 4391997Sanish } 4401997Sanish 441881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 442881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 443881Sjohnny 444881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 445881Sjohnny msix_p = i_ddi_get_msix(hdlp->ih_dip); 446881Sjohnny if (msix_p && 4472018Sanish (i_ddi_intr_get_current_nintrs( 4484397Sschwartz hdlp->ih_dip) - 1) == 0) { 449881Sjohnny pci_msix_fini(msix_p); 450881Sjohnny i_ddi_set_msix(hdlp->ih_dip, NULL); 451881Sjohnny } 452881Sjohnny } 453*12683SJimmy.Vetayases@oracle.com } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 454*12683SJimmy.Vetayases@oracle.com return (pci_free_intr_fixed(pdip, rdip, hdlp)); 455*12683SJimmy.Vetayases@oracle.com } else 456*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 457881Sjohnny break; 458881Sjohnny case DDI_INTROP_GETPRI: 459881Sjohnny /* Get the priority */ 460881Sjohnny if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS) 461881Sjohnny return (DDI_FAILURE); 462881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 463881Sjohnny "priority = 0x%x\n", priority)); 464881Sjohnny *(int *)result = priority; 465881Sjohnny break; 466881Sjohnny case DDI_INTROP_SETPRI: 467881Sjohnny /* Validate the interrupt priority passed */ 468881Sjohnny if (*(int *)result > LOCK_LEVEL) 469881Sjohnny return (DDI_FAILURE); 470881Sjohnny 471881Sjohnny /* Ensure that PSM is all initialized */ 472881Sjohnny if (psm_intr_ops == NULL) 473881Sjohnny return (DDI_FAILURE); 474881Sjohnny 47510190SSophia.Li@Sun.COM isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 47610190SSophia.Li@Sun.COM ispec = (struct intrspec *)isp; 47710190SSophia.Li@Sun.COM if (ispec == NULL) 47810190SSophia.Li@Sun.COM return (DDI_FAILURE); 47910190SSophia.Li@Sun.COM 48010190SSophia.Li@Sun.COM /* For fixed interrupts */ 48110190SSophia.Li@Sun.COM if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 48210190SSophia.Li@Sun.COM /* if interrupt is shared, return failure */ 48310190SSophia.Li@Sun.COM ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 48410190SSophia.Li@Sun.COM psm_rval = (*psm_intr_ops)(rdip, hdlp, 48510190SSophia.Li@Sun.COM PSM_INTR_OP_GET_SHARED, &psm_status); 48610190SSophia.Li@Sun.COM /* 48710190SSophia.Li@Sun.COM * For fixed interrupts, the irq may not have been 48810190SSophia.Li@Sun.COM * allocated when SET_PRI is called, and the above 48910190SSophia.Li@Sun.COM * GET_SHARED op may return PSM_FAILURE. This is not 49010190SSophia.Li@Sun.COM * a real error and is ignored below. 49110190SSophia.Li@Sun.COM */ 49210190SSophia.Li@Sun.COM if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) { 49310190SSophia.Li@Sun.COM DDI_INTR_NEXDBG((CE_CONT, 49410190SSophia.Li@Sun.COM "pci_common_intr_ops: " 49510190SSophia.Li@Sun.COM "dip 0x%p cannot setpri, psm_rval=%d," 49610190SSophia.Li@Sun.COM "psm_status=%d\n", (void *)rdip, psm_rval, 49710190SSophia.Li@Sun.COM psm_status)); 49810190SSophia.Li@Sun.COM return (DDI_FAILURE); 49910190SSophia.Li@Sun.COM } 50010190SSophia.Li@Sun.COM } 50110190SSophia.Li@Sun.COM 502881Sjohnny /* Change the priority */ 503881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 504881Sjohnny PSM_FAILURE) 505881Sjohnny return (DDI_FAILURE); 506881Sjohnny 507881Sjohnny /* update ispec */ 50810190SSophia.Li@Sun.COM ispec->intrspec_pri = *(int *)result; 509881Sjohnny break; 510881Sjohnny case DDI_INTROP_ADDISR: 511881Sjohnny /* update ispec */ 512881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 513881Sjohnny ispec = (struct intrspec *)isp; 5141087Sschwartz if (ispec) { 515881Sjohnny ispec->intrspec_func = hdlp->ih_cb_func; 5161087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 5171087Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 5181087Sschwartz } 519881Sjohnny break; 520881Sjohnny case DDI_INTROP_REMISR: 521881Sjohnny /* Get the interrupt structure pointer */ 522881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 523881Sjohnny ispec = (struct intrspec *)isp; 5241087Sschwartz if (ispec) { 525881Sjohnny ispec->intrspec_func = (uint_t (*)()) 0; 5261087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 5271087Sschwartz if (ihdl_plat_datap->ip_ksp != NULL) 5281087Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp); 5291087Sschwartz } 530881Sjohnny break; 531881Sjohnny case DDI_INTROP_GETCAP: 532881Sjohnny /* 533881Sjohnny * First check the config space and/or 534881Sjohnny * MSI capability register(s) 535881Sjohnny */ 536881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 537881Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 538881Sjohnny &pci_status); 539881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 540881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 541881Sjohnny 542*12683SJimmy.Vetayases@oracle.com /* next check with PSM module */ 543881Sjohnny if (psm_intr_ops != NULL) 544881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 545881Sjohnny PSM_INTR_OP_GET_CAP, &psm_status); 546881Sjohnny 547881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 548881Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n", 549881Sjohnny psm_rval, psm_status, pci_rval, pci_status)); 550881Sjohnny 551881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 552881Sjohnny *(int *)result = 0; 553881Sjohnny return (DDI_FAILURE); 554881Sjohnny } 555881Sjohnny 556881Sjohnny if (psm_rval == PSM_SUCCESS) 557881Sjohnny *(int *)result = psm_status; 558881Sjohnny 559881Sjohnny if (pci_rval == DDI_SUCCESS) 560881Sjohnny *(int *)result |= pci_status; 561881Sjohnny 562881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 563881Sjohnny *(int *)result)); 564881Sjohnny break; 565881Sjohnny case DDI_INTROP_SETCAP: 566881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 567881Sjohnny "SETCAP cap=0x%x\n", *(int *)result)); 568881Sjohnny if (psm_intr_ops == NULL) 569881Sjohnny return (DDI_FAILURE); 570881Sjohnny 571881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 572881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 573881Sjohnny " returned failure\n")); 574881Sjohnny return (DDI_FAILURE); 575881Sjohnny } 576881Sjohnny break; 577881Sjohnny case DDI_INTROP_ENABLE: 578881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 579881Sjohnny if (psm_intr_ops == NULL) 580881Sjohnny return (DDI_FAILURE); 581881Sjohnny 582881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 583881Sjohnny DDI_SUCCESS) 584881Sjohnny return (DDI_FAILURE); 585881Sjohnny 586881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 587881Sjohnny "vector=0x%x\n", hdlp->ih_vector)); 588881Sjohnny break; 589881Sjohnny case DDI_INTROP_DISABLE: 590881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 591881Sjohnny if (psm_intr_ops == NULL) 592881Sjohnny return (DDI_FAILURE); 593881Sjohnny 594881Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 595881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 596881Sjohnny "vector = %x\n", hdlp->ih_vector)); 597881Sjohnny break; 598881Sjohnny case DDI_INTROP_BLOCKENABLE: 599881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 600881Sjohnny "BLOCKENABLE\n")); 601881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 602881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 603881Sjohnny return (DDI_FAILURE); 604881Sjohnny } 605881Sjohnny 606881Sjohnny /* Check if psm_intr_ops is NULL? */ 607881Sjohnny if (psm_intr_ops == NULL) 608881Sjohnny return (DDI_FAILURE); 609881Sjohnny 6101542Sjohnny count = hdlp->ih_scratch1; 6111542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 6121542Sjohnny for (i = 0; i < count; i++) { 6131542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 614881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, 6151542Sjohnny hdlp->ih_inum) != DDI_SUCCESS) { 616881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 617881Sjohnny "pci_enable_intr failed for %d\n", i)); 6181542Sjohnny for (j = 0; j < i; j++) { 6194397Sschwartz hdlp = (ddi_intr_handle_impl_t *) 6204397Sschwartz h_array[j]; 6214397Sschwartz pci_disable_intr(pdip, rdip, hdlp, 6221542Sjohnny hdlp->ih_inum); 6231542Sjohnny } 624881Sjohnny return (DDI_FAILURE); 625881Sjohnny } 626881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 6271542Sjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 628881Sjohnny } 629881Sjohnny break; 630881Sjohnny case DDI_INTROP_BLOCKDISABLE: 631881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 632881Sjohnny "BLOCKDISABLE\n")); 633881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 634881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 635881Sjohnny return (DDI_FAILURE); 636881Sjohnny } 637881Sjohnny 638881Sjohnny /* Check if psm_intr_ops is present */ 639881Sjohnny if (psm_intr_ops == NULL) 640881Sjohnny return (DDI_FAILURE); 641881Sjohnny 6421542Sjohnny count = hdlp->ih_scratch1; 6431542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 6441542Sjohnny for (i = 0; i < count; i++) { 6451542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 6461542Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 647881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 6481542Sjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 649881Sjohnny } 650881Sjohnny break; 651881Sjohnny case DDI_INTROP_SETMASK: 652881Sjohnny case DDI_INTROP_CLRMASK: 653881Sjohnny /* 654881Sjohnny * First handle in the config space 655881Sjohnny */ 656881Sjohnny if (intr_op == DDI_INTROP_SETMASK) { 657881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 658881Sjohnny pci_status = pci_msi_set_mask(rdip, 659881Sjohnny hdlp->ih_type, hdlp->ih_inum); 660881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 661881Sjohnny pci_status = pci_intx_set_mask(rdip); 662881Sjohnny } else { 663881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 664881Sjohnny pci_status = pci_msi_clr_mask(rdip, 665881Sjohnny hdlp->ih_type, hdlp->ih_inum); 666881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 667881Sjohnny pci_status = pci_intx_clr_mask(rdip); 668881Sjohnny } 669881Sjohnny 670*12683SJimmy.Vetayases@oracle.com /* For MSI/X; no need to check with PSM module */ 671881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 672881Sjohnny return (pci_status); 673881Sjohnny 674881Sjohnny /* For fixed interrupts only: handle config space first */ 675881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 676881Sjohnny pci_status == DDI_SUCCESS) 677881Sjohnny break; 678881Sjohnny 679*12683SJimmy.Vetayases@oracle.com /* For fixed interrupts only: confer with PSM module next */ 680881Sjohnny if (psm_intr_ops != NULL) { 681881Sjohnny /* If interrupt is shared; do nothing */ 682881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 683881Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status); 684881Sjohnny 685881Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1) 686881Sjohnny return (pci_status); 687881Sjohnny 688*12683SJimmy.Vetayases@oracle.com /* Now, PSM module should try to set/clear the mask */ 689881Sjohnny if (intr_op == DDI_INTROP_SETMASK) 690881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 691881Sjohnny PSM_INTR_OP_SET_MASK, NULL); 692881Sjohnny else 693881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 694881Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL); 695881Sjohnny } 696881Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 697881Sjohnny case DDI_INTROP_GETPENDING: 698881Sjohnny /* 699881Sjohnny * First check the config space and/or 700881Sjohnny * MSI capability register(s) 701881Sjohnny */ 702881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 703881Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 704881Sjohnny hdlp->ih_inum, &pci_status); 705881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 706881Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status); 707881Sjohnny 708*12683SJimmy.Vetayases@oracle.com /* On failure; next try with PSM module */ 709881Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 710881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 711881Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status); 712881Sjohnny 713881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 714881Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, " 715881Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval, 716881Sjohnny pci_status)); 717881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 718881Sjohnny *(int *)result = 0; 719881Sjohnny return (DDI_FAILURE); 720881Sjohnny } 721881Sjohnny 722881Sjohnny if (psm_rval != PSM_FAILURE) 723881Sjohnny *(int *)result = psm_status; 724881Sjohnny else if (pci_rval != DDI_FAILURE) 725881Sjohnny *(int *)result = pci_status; 726881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 727881Sjohnny *(int *)result)); 728881Sjohnny break; 72910053SEvan.Yan@Sun.COM case DDI_INTROP_GETTARGET: 73010053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n")); 73110053SEvan.Yan@Sun.COM 732*12683SJimmy.Vetayases@oracle.com bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t)); 733*12683SJimmy.Vetayases@oracle.com tmp_hdl.ih_private = (void *)&intrinfo; 734*12683SJimmy.Vetayases@oracle.com intrinfo.avgi_req_flags = PSMGI_INTRBY_DEFAULT; 735*12683SJimmy.Vetayases@oracle.com intrinfo.avgi_req_flags |= PSMGI_REQ_CPUID; 736*12683SJimmy.Vetayases@oracle.com 737*12683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_GET_INTR, 738*12683SJimmy.Vetayases@oracle.com NULL) == PSM_FAILURE) 73910053SEvan.Yan@Sun.COM return (DDI_FAILURE); 740*12683SJimmy.Vetayases@oracle.com 741*12683SJimmy.Vetayases@oracle.com *(int *)result = intrinfo.avgi_cpu_id; 74210053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET " 743*12683SJimmy.Vetayases@oracle.com "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector, 744*12683SJimmy.Vetayases@oracle.com *(int *)result)); 74510053SEvan.Yan@Sun.COM break; 74610053SEvan.Yan@Sun.COM case DDI_INTROP_SETTARGET: 74710053SEvan.Yan@Sun.COM DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n")); 74810053SEvan.Yan@Sun.COM 749*12683SJimmy.Vetayases@oracle.com bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t)); 75010053SEvan.Yan@Sun.COM tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result; 751*12683SJimmy.Vetayases@oracle.com tmp_hdl.ih_flags = PSMGI_INTRBY_DEFAULT; 752*12683SJimmy.Vetayases@oracle.com 753*12683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU, 754*12683SJimmy.Vetayases@oracle.com &psm_status) == PSM_FAILURE) 755*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 75610053SEvan.Yan@Sun.COM 757*12683SJimmy.Vetayases@oracle.com hdlp->ih_vector = tmp_hdl.ih_vector; 758*12683SJimmy.Vetayases@oracle.com DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET " 759*12683SJimmy.Vetayases@oracle.com "vector = 0x%x\n", hdlp->ih_vector)); 76010053SEvan.Yan@Sun.COM break; 761*12683SJimmy.Vetayases@oracle.com case DDI_INTROP_GETPOOL: 762*12683SJimmy.Vetayases@oracle.com /* 763*12683SJimmy.Vetayases@oracle.com * For MSI/X interrupts use global IRM pool if available. 764*12683SJimmy.Vetayases@oracle.com */ 765*12683SJimmy.Vetayases@oracle.com if (apix_irm_pool_p && DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 766*12683SJimmy.Vetayases@oracle.com *(ddi_irm_pool_t **)result = apix_irm_pool_p; 767*12683SJimmy.Vetayases@oracle.com return (DDI_SUCCESS); 768*12683SJimmy.Vetayases@oracle.com } 769*12683SJimmy.Vetayases@oracle.com return (DDI_ENOTSUP); 770881Sjohnny default: 771881Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 772881Sjohnny } 773881Sjohnny 774881Sjohnny return (DDI_SUCCESS); 775881Sjohnny } 776881Sjohnny 777*12683SJimmy.Vetayases@oracle.com /* 778*12683SJimmy.Vetayases@oracle.com * Allocate a vector for FIXED type interrupt. 779*12683SJimmy.Vetayases@oracle.com */ 780*12683SJimmy.Vetayases@oracle.com int 781*12683SJimmy.Vetayases@oracle.com pci_alloc_intr_fixed(dev_info_t *pdip, dev_info_t *rdip, 782*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp, void *result) 783*12683SJimmy.Vetayases@oracle.com { 784*12683SJimmy.Vetayases@oracle.com struct intrspec *ispec; 785*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t info_hdl; 786*12683SJimmy.Vetayases@oracle.com int ret; 787*12683SJimmy.Vetayases@oracle.com int free_phdl = 0; 788*12683SJimmy.Vetayases@oracle.com int pci_rval; 789*12683SJimmy.Vetayases@oracle.com int pci_status = 0; 790*12683SJimmy.Vetayases@oracle.com apic_get_type_t type_info; 791*12683SJimmy.Vetayases@oracle.com 792*12683SJimmy.Vetayases@oracle.com if (psm_intr_ops == NULL) 793*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 794*12683SJimmy.Vetayases@oracle.com 795*12683SJimmy.Vetayases@oracle.com /* Figure out if this device supports MASKING */ 796*12683SJimmy.Vetayases@oracle.com pci_rval = pci_intx_get_cap(rdip, &pci_status); 797*12683SJimmy.Vetayases@oracle.com if (pci_rval == DDI_SUCCESS && pci_status) 798*12683SJimmy.Vetayases@oracle.com hdlp->ih_cap |= pci_status; 799*12683SJimmy.Vetayases@oracle.com 800*12683SJimmy.Vetayases@oracle.com /* 801*12683SJimmy.Vetayases@oracle.com * If the PSM module is "APIX" then pass the request for 802*12683SJimmy.Vetayases@oracle.com * allocating the vector now. 803*12683SJimmy.Vetayases@oracle.com */ 804*12683SJimmy.Vetayases@oracle.com bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t)); 805*12683SJimmy.Vetayases@oracle.com info_hdl.ih_private = &type_info; 806*12683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) == 807*12683SJimmy.Vetayases@oracle.com PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) { 808*12683SJimmy.Vetayases@oracle.com ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, 809*12683SJimmy.Vetayases@oracle.com (int)hdlp->ih_inum); 810*12683SJimmy.Vetayases@oracle.com if (ispec == NULL) 811*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 812*12683SJimmy.Vetayases@oracle.com if (hdlp->ih_private == NULL) { /* allocate phdl structure */ 813*12683SJimmy.Vetayases@oracle.com free_phdl = 1; 814*12683SJimmy.Vetayases@oracle.com i_ddi_alloc_intr_phdl(hdlp); 815*12683SJimmy.Vetayases@oracle.com } 816*12683SJimmy.Vetayases@oracle.com ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 817*12683SJimmy.Vetayases@oracle.com ret = (*psm_intr_ops)(rdip, hdlp, 818*12683SJimmy.Vetayases@oracle.com PSM_INTR_OP_ALLOC_VECTORS, result); 819*12683SJimmy.Vetayases@oracle.com if (free_phdl) { /* free up the phdl structure */ 820*12683SJimmy.Vetayases@oracle.com free_phdl = 0; 821*12683SJimmy.Vetayases@oracle.com i_ddi_free_intr_phdl(hdlp); 822*12683SJimmy.Vetayases@oracle.com hdlp->ih_private = NULL; 823*12683SJimmy.Vetayases@oracle.com } 824*12683SJimmy.Vetayases@oracle.com } else { 825*12683SJimmy.Vetayases@oracle.com /* 826*12683SJimmy.Vetayases@oracle.com * No APIX module; fall back to the old scheme where the 827*12683SJimmy.Vetayases@oracle.com * interrupt vector is allocated during ddi_enable_intr() call. 828*12683SJimmy.Vetayases@oracle.com */ 829*12683SJimmy.Vetayases@oracle.com *(int *)result = 1; 830*12683SJimmy.Vetayases@oracle.com ret = DDI_SUCCESS; 831*12683SJimmy.Vetayases@oracle.com } 832*12683SJimmy.Vetayases@oracle.com 833*12683SJimmy.Vetayases@oracle.com return (ret); 834*12683SJimmy.Vetayases@oracle.com } 835*12683SJimmy.Vetayases@oracle.com 836*12683SJimmy.Vetayases@oracle.com /* 837*12683SJimmy.Vetayases@oracle.com * Free up the vector for FIXED (legacy) type interrupt. 838*12683SJimmy.Vetayases@oracle.com */ 839*12683SJimmy.Vetayases@oracle.com static int 840*12683SJimmy.Vetayases@oracle.com pci_free_intr_fixed(dev_info_t *pdip, dev_info_t *rdip, 841*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp) 842*12683SJimmy.Vetayases@oracle.com { 843*12683SJimmy.Vetayases@oracle.com struct intrspec *ispec; 844*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t info_hdl; 845*12683SJimmy.Vetayases@oracle.com int ret; 846*12683SJimmy.Vetayases@oracle.com apic_get_type_t type_info; 847*12683SJimmy.Vetayases@oracle.com 848*12683SJimmy.Vetayases@oracle.com if (psm_intr_ops == NULL) 849*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 850*12683SJimmy.Vetayases@oracle.com 851*12683SJimmy.Vetayases@oracle.com /* 852*12683SJimmy.Vetayases@oracle.com * If the PSM module is "APIX" then pass the request to it 853*12683SJimmy.Vetayases@oracle.com * to free up the vector now. 854*12683SJimmy.Vetayases@oracle.com */ 855*12683SJimmy.Vetayases@oracle.com bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t)); 856*12683SJimmy.Vetayases@oracle.com info_hdl.ih_private = &type_info; 857*12683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) == 858*12683SJimmy.Vetayases@oracle.com PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) { 859*12683SJimmy.Vetayases@oracle.com ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, 860*12683SJimmy.Vetayases@oracle.com (int)hdlp->ih_inum); 861*12683SJimmy.Vetayases@oracle.com if (ispec == NULL) 862*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 863*12683SJimmy.Vetayases@oracle.com ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 864*12683SJimmy.Vetayases@oracle.com ret = (*psm_intr_ops)(rdip, hdlp, 865*12683SJimmy.Vetayases@oracle.com PSM_INTR_OP_FREE_VECTORS, NULL); 866*12683SJimmy.Vetayases@oracle.com } else { 867*12683SJimmy.Vetayases@oracle.com /* 868*12683SJimmy.Vetayases@oracle.com * No APIX module; fall back to the old scheme where 869*12683SJimmy.Vetayases@oracle.com * the interrupt vector was already freed during 870*12683SJimmy.Vetayases@oracle.com * ddi_disable_intr() call. 871*12683SJimmy.Vetayases@oracle.com */ 872*12683SJimmy.Vetayases@oracle.com ret = DDI_SUCCESS; 873*12683SJimmy.Vetayases@oracle.com } 874*12683SJimmy.Vetayases@oracle.com 875*12683SJimmy.Vetayases@oracle.com return (ret); 876*12683SJimmy.Vetayases@oracle.com } 877*12683SJimmy.Vetayases@oracle.com 878916Sschwartz int 879916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 880916Sschwartz int vecirq, boolean_t is_irq) 881916Sschwartz { 882916Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl; 883916Sschwartz 884916Sschwartz if (is_irq) 885916Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 886916Sschwartz 887916Sschwartz /* 888916Sschwartz * For this locally-declared and used handle, ih_private will contain a 889916Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 890916Sschwartz * global interrupt handling. 891916Sschwartz */ 892916Sschwartz get_info_ii_hdl.ih_private = intrinfo_p; 893*12683SJimmy.Vetayases@oracle.com get_info_ii_hdl.ih_vector = vecirq; 894916Sschwartz 895916Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 896916Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 897916Sschwartz return (DDI_FAILURE); 898916Sschwartz 899916Sschwartz return (DDI_SUCCESS); 900916Sschwartz } 901916Sschwartz 902916Sschwartz 903916Sschwartz int 904916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 905916Sschwartz { 906916Sschwartz int rval; 907*12683SJimmy.Vetayases@oracle.com apic_get_intr_t intrinfo; 908916Sschwartz 909916Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 910916Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 911916Sschwartz 912916Sschwartz if (rval == DDI_SUCCESS) 913916Sschwartz return (intrinfo.avgi_cpu_id); 914916Sschwartz else 915916Sschwartz return (-1); 916916Sschwartz } 917916Sschwartz 918881Sjohnny 919881Sjohnny static int 920881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 921881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 922881Sjohnny { 923881Sjohnny struct intrspec *ispec; 924916Sschwartz int irq; 925916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 926881Sjohnny 927881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 928881Sjohnny (void *)hdlp, inum)); 929881Sjohnny 930881Sjohnny /* Translate the interrupt if needed */ 931881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 9322288Sanish if (ispec == NULL) 9332288Sanish return (DDI_FAILURE); 93410190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 935881Sjohnny ispec->intrspec_vec = inum; 93610190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri; 93710190SSophia.Li@Sun.COM } 938916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 939881Sjohnny 940881Sjohnny /* translate the interrupt if needed */ 94111465SKerry.Shu@Sun.COM if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) == 94211465SKerry.Shu@Sun.COM PSM_FAILURE) 94311465SKerry.Shu@Sun.COM return (DDI_FAILURE); 944916Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 945916Sschwartz hdlp->ih_pri, irq)); 946881Sjohnny 947881Sjohnny /* Add the interrupt handler */ 948881Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 949916Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 950916Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 951881Sjohnny return (DDI_FAILURE); 952881Sjohnny 953*12683SJimmy.Vetayases@oracle.com hdlp->ih_vector = irq; 954916Sschwartz 955881Sjohnny return (DDI_SUCCESS); 956881Sjohnny } 957881Sjohnny 958881Sjohnny 959881Sjohnny static void 960881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 961881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 962881Sjohnny { 963916Sschwartz int irq; 964881Sjohnny struct intrspec *ispec; 965916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 966881Sjohnny 967881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 968881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 9692288Sanish if (ispec == NULL) 9702288Sanish return; 97110190SSophia.Li@Sun.COM if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 972881Sjohnny ispec->intrspec_vec = inum; 97310190SSophia.Li@Sun.COM ispec->intrspec_pri = hdlp->ih_pri; 97410190SSophia.Li@Sun.COM } 975916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 976881Sjohnny 977881Sjohnny /* translate the interrupt if needed */ 978916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 979881Sjohnny 980881Sjohnny /* Disable the interrupt handler */ 981916Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 982916Sschwartz ihdl_plat_datap->ip_ispecp = NULL; 983881Sjohnny } 984881Sjohnny 985881Sjohnny /* 986881Sjohnny * Miscellaneous library function 987881Sjohnny */ 988881Sjohnny int 989881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 990881Sjohnny { 991881Sjohnny int i; 992881Sjohnny int number; 993881Sjohnny int assigned_addr_len; 994881Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi; 995881Sjohnny pci_regspec_t *assigned_addr; 996881Sjohnny 997881Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 998881Sjohnny (phys_hi & PCI_RELOCAT_B)) 999881Sjohnny return (DDI_SUCCESS); 1000881Sjohnny 1001881Sjohnny /* 1002881Sjohnny * the "reg" property specifies relocatable, get and interpret the 1003881Sjohnny * "assigned-addresses" property. 1004881Sjohnny */ 1005881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1006881Sjohnny "assigned-addresses", (int **)&assigned_addr, 1007881Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 1008881Sjohnny return (DDI_FAILURE); 1009881Sjohnny 1010881Sjohnny /* 1011881Sjohnny * Scan the "assigned-addresses" for one that matches the specified 1012881Sjohnny * "reg" property entry. 1013881Sjohnny */ 1014881Sjohnny phys_hi &= PCI_CONF_ADDR_MASK; 1015881Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 1016881Sjohnny for (i = 0; i < number; i++) { 1017881Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 1018881Sjohnny phys_hi) { 1019881Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 1020881Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 1021881Sjohnny ddi_prop_free(assigned_addr); 1022881Sjohnny return (DDI_SUCCESS); 1023881Sjohnny } 1024881Sjohnny } 1025881Sjohnny 1026881Sjohnny ddi_prop_free(assigned_addr); 1027881Sjohnny return (DDI_FAILURE); 1028881Sjohnny } 1029881Sjohnny 1030881Sjohnny 1031881Sjohnny /* 103210923SEvan.Yan@Sun.COM * To handle PCI tool ioctls 1033881Sjohnny */ 1034881Sjohnny 103510923SEvan.Yan@Sun.COM /*ARGSUSED*/ 1036881Sjohnny int 1037881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 1038881Sjohnny int mode, cred_t *credp, int *rvalp) 1039881Sjohnny { 104010923SEvan.Yan@Sun.COM minor_t minor = getminor(dev); 104110923SEvan.Yan@Sun.COM int rv = ENOTTY; 1042881Sjohnny 104310923SEvan.Yan@Sun.COM switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 1044881Sjohnny case PCI_TOOL_REG_MINOR_NUM: 1045881Sjohnny 1046881Sjohnny switch (cmd) { 1047881Sjohnny case PCITOOL_DEVICE_SET_REG: 1048881Sjohnny case PCITOOL_DEVICE_GET_REG: 1049881Sjohnny 1050881Sjohnny /* Require full privileges. */ 1051881Sjohnny if (secpolicy_kmdb(credp)) 1052881Sjohnny rv = EPERM; 1053881Sjohnny else 1054881Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg, 1055881Sjohnny cmd, mode); 1056881Sjohnny break; 1057881Sjohnny 1058881Sjohnny case PCITOOL_NEXUS_SET_REG: 1059881Sjohnny case PCITOOL_NEXUS_GET_REG: 1060881Sjohnny 1061881Sjohnny /* Require full privileges. */ 1062881Sjohnny if (secpolicy_kmdb(credp)) 1063881Sjohnny rv = EPERM; 1064881Sjohnny else 1065881Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg, 1066881Sjohnny cmd, mode); 1067881Sjohnny break; 1068881Sjohnny } 1069881Sjohnny break; 1070881Sjohnny 1071881Sjohnny case PCI_TOOL_INTR_MINOR_NUM: 1072881Sjohnny 1073881Sjohnny switch (cmd) { 1074881Sjohnny case PCITOOL_DEVICE_SET_INTR: 1075881Sjohnny 1076881Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 1077881Sjohnny if (secpolicy_ponline(credp)) { 1078881Sjohnny rv = EPERM; 1079881Sjohnny break; 1080881Sjohnny } 1081881Sjohnny 1082881Sjohnny /*FALLTHRU*/ 1083881Sjohnny /* These require no special privileges. */ 1084881Sjohnny case PCITOOL_DEVICE_GET_INTR: 10854397Sschwartz case PCITOOL_SYSTEM_INTR_INFO: 1086881Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 1087881Sjohnny break; 1088881Sjohnny } 1089881Sjohnny break; 1090881Sjohnny 1091881Sjohnny default: 1092881Sjohnny break; 1093881Sjohnny } 1094881Sjohnny 1095881Sjohnny return (rv); 1096881Sjohnny } 10971083Sanish 10981083Sanish 10991865Sdilpreet int 11001865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 11011865Sdilpreet { 11021865Sdilpreet size_t size = in_args->size; 11031865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 11041865Sdilpreet uintptr_t host_addr = in_args->host_addr; 11051865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 11061865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 11071865Sdilpreet size_t repcount = in_args->repcount; 11081865Sdilpreet uint_t flags = in_args->flags; 11091865Sdilpreet int err = DDI_SUCCESS; 11101865Sdilpreet 11111865Sdilpreet /* 11121865Sdilpreet * if no handle then this is a poke. We have to return failure here 11131865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 11141865Sdilpreet */ 11151865Sdilpreet if (in_args->handle == NULL) 11161865Sdilpreet return (DDI_FAILURE); 11171865Sdilpreet 11181865Sdilpreet /* 11191865Sdilpreet * rest of this function is actually for cautious puts 11201865Sdilpreet */ 11211865Sdilpreet for (; repcount; repcount--) { 11221865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 11231865Sdilpreet switch (size) { 11241865Sdilpreet case sizeof (uint8_t): 11251865Sdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr, 11261865Sdilpreet *(uint8_t *)host_addr); 11271865Sdilpreet break; 11281865Sdilpreet case sizeof (uint16_t): 11291865Sdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr, 11301865Sdilpreet *(uint16_t *)host_addr); 11311865Sdilpreet break; 11321865Sdilpreet case sizeof (uint32_t): 11331865Sdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr, 11341865Sdilpreet *(uint32_t *)host_addr); 11351865Sdilpreet break; 11361865Sdilpreet case sizeof (uint64_t): 11371865Sdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr, 11381865Sdilpreet *(uint64_t *)host_addr); 11391865Sdilpreet break; 11401865Sdilpreet default: 11411865Sdilpreet err = DDI_FAILURE; 11421865Sdilpreet break; 11431865Sdilpreet } 11441865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 11451865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 11461865Sdilpreet DDI_STRUCTURE_BE_ACC) { 11471865Sdilpreet switch (size) { 11481865Sdilpreet case sizeof (uint8_t): 11491865Sdilpreet i_ddi_io_put8(hp, 11501865Sdilpreet (uint8_t *)dev_addr, 11511865Sdilpreet *(uint8_t *)host_addr); 11521865Sdilpreet break; 11531865Sdilpreet case sizeof (uint16_t): 11541865Sdilpreet i_ddi_io_swap_put16(hp, 11551865Sdilpreet (uint16_t *)dev_addr, 11561865Sdilpreet *(uint16_t *)host_addr); 11571865Sdilpreet break; 11581865Sdilpreet case sizeof (uint32_t): 11591865Sdilpreet i_ddi_io_swap_put32(hp, 11601865Sdilpreet (uint32_t *)dev_addr, 11611865Sdilpreet *(uint32_t *)host_addr); 11621865Sdilpreet break; 11631865Sdilpreet /* 11641865Sdilpreet * note the 64-bit case is a dummy 11651865Sdilpreet * function - so no need to swap 11661865Sdilpreet */ 11671865Sdilpreet case sizeof (uint64_t): 11681865Sdilpreet i_ddi_io_put64(hp, 11691865Sdilpreet (uint64_t *)dev_addr, 11701865Sdilpreet *(uint64_t *)host_addr); 11711865Sdilpreet break; 11721865Sdilpreet default: 11731865Sdilpreet err = DDI_FAILURE; 11741865Sdilpreet break; 11751865Sdilpreet } 11761865Sdilpreet } else { 11771865Sdilpreet switch (size) { 11781865Sdilpreet case sizeof (uint8_t): 11791865Sdilpreet i_ddi_io_put8(hp, 11801865Sdilpreet (uint8_t *)dev_addr, 11811865Sdilpreet *(uint8_t *)host_addr); 11821865Sdilpreet break; 11831865Sdilpreet case sizeof (uint16_t): 11841865Sdilpreet i_ddi_io_put16(hp, 11851865Sdilpreet (uint16_t *)dev_addr, 11861865Sdilpreet *(uint16_t *)host_addr); 11871865Sdilpreet break; 11881865Sdilpreet case sizeof (uint32_t): 11891865Sdilpreet i_ddi_io_put32(hp, 11901865Sdilpreet (uint32_t *)dev_addr, 11911865Sdilpreet *(uint32_t *)host_addr); 11921865Sdilpreet break; 11931865Sdilpreet case sizeof (uint64_t): 11941865Sdilpreet i_ddi_io_put64(hp, 11951865Sdilpreet (uint64_t *)dev_addr, 11961865Sdilpreet *(uint64_t *)host_addr); 11971865Sdilpreet break; 11981865Sdilpreet default: 11991865Sdilpreet err = DDI_FAILURE; 12001865Sdilpreet break; 12011865Sdilpreet } 12021865Sdilpreet } 12031865Sdilpreet } else { 12041865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12051865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12061865Sdilpreet switch (size) { 12071865Sdilpreet case sizeof (uint8_t): 12081865Sdilpreet *(uint8_t *)dev_addr = 12091865Sdilpreet *(uint8_t *)host_addr; 12101865Sdilpreet break; 12111865Sdilpreet case sizeof (uint16_t): 12121865Sdilpreet *(uint16_t *)dev_addr = 12131865Sdilpreet ddi_swap16(*(uint16_t *)host_addr); 12141865Sdilpreet break; 12151865Sdilpreet case sizeof (uint32_t): 12161865Sdilpreet *(uint32_t *)dev_addr = 12171865Sdilpreet ddi_swap32(*(uint32_t *)host_addr); 12181865Sdilpreet break; 12191865Sdilpreet case sizeof (uint64_t): 12201865Sdilpreet *(uint64_t *)dev_addr = 12211865Sdilpreet ddi_swap64(*(uint64_t *)host_addr); 12221865Sdilpreet break; 12231865Sdilpreet default: 12241865Sdilpreet err = DDI_FAILURE; 12251865Sdilpreet break; 12261865Sdilpreet } 12271865Sdilpreet } else { 12281865Sdilpreet switch (size) { 12291865Sdilpreet case sizeof (uint8_t): 12301865Sdilpreet *(uint8_t *)dev_addr = 12311865Sdilpreet *(uint8_t *)host_addr; 12321865Sdilpreet break; 12331865Sdilpreet case sizeof (uint16_t): 12341865Sdilpreet *(uint16_t *)dev_addr = 12351865Sdilpreet *(uint16_t *)host_addr; 12361865Sdilpreet break; 12371865Sdilpreet case sizeof (uint32_t): 12381865Sdilpreet *(uint32_t *)dev_addr = 12391865Sdilpreet *(uint32_t *)host_addr; 12401865Sdilpreet break; 12411865Sdilpreet case sizeof (uint64_t): 12421865Sdilpreet *(uint64_t *)dev_addr = 12431865Sdilpreet *(uint64_t *)host_addr; 12441865Sdilpreet break; 12451865Sdilpreet default: 12461865Sdilpreet err = DDI_FAILURE; 12471865Sdilpreet break; 12481865Sdilpreet } 12491865Sdilpreet } 12501865Sdilpreet } 12511865Sdilpreet host_addr += size; 12521865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 12531865Sdilpreet dev_addr += size; 12541865Sdilpreet } 12551865Sdilpreet return (err); 12561865Sdilpreet } 12571865Sdilpreet 12581865Sdilpreet 12591865Sdilpreet int 12601865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 12611865Sdilpreet { 12621865Sdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 12631865Sdilpreet 12641865Sdilpreet /* endian-ness check */ 12651865Sdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 12661865Sdilpreet return (DDI_FAILURE); 12671865Sdilpreet 12681865Sdilpreet /* 12691865Sdilpreet * range check 12701865Sdilpreet */ 12711865Sdilpreet if ((offset >= PCI_CONF_HDR_SIZE) || 12721865Sdilpreet (len > PCI_CONF_HDR_SIZE) || 12731865Sdilpreet (offset + len > PCI_CONF_HDR_SIZE)) 12741865Sdilpreet return (DDI_FAILURE); 12751865Sdilpreet 12761865Sdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 12771865Sdilpreet /* 12781865Sdilpreet * always use cautious mechanism for config space gets 12791865Sdilpreet */ 12801865Sdilpreet ap->ahi_get8 = i_ddi_caut_get8; 12811865Sdilpreet ap->ahi_get16 = i_ddi_caut_get16; 12821865Sdilpreet ap->ahi_get32 = i_ddi_caut_get32; 12831865Sdilpreet ap->ahi_get64 = i_ddi_caut_get64; 12841865Sdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 12851865Sdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 12861865Sdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 12871865Sdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 12881865Sdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 12891865Sdilpreet ap->ahi_put8 = i_ddi_caut_put8; 12901865Sdilpreet ap->ahi_put16 = i_ddi_caut_put16; 12911865Sdilpreet ap->ahi_put32 = i_ddi_caut_put32; 12921865Sdilpreet ap->ahi_put64 = i_ddi_caut_put64; 12931865Sdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 12941865Sdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 12951865Sdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 12961865Sdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 12971865Sdilpreet } else { 12981865Sdilpreet ap->ahi_put8 = pci_config_wr8; 12991865Sdilpreet ap->ahi_put16 = pci_config_wr16; 13001865Sdilpreet ap->ahi_put32 = pci_config_wr32; 13011865Sdilpreet ap->ahi_put64 = pci_config_wr64; 13021865Sdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8; 13031865Sdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16; 13041865Sdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32; 13051865Sdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64; 13061865Sdilpreet } 13071865Sdilpreet 13081865Sdilpreet /* Initialize to default check/notify functions */ 13091865Sdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check; 13101865Sdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify; 13111865Sdilpreet ap->ahi_fault = 0; 13121865Sdilpreet impl_acc_err_init(hp); 13131865Sdilpreet return (DDI_SUCCESS); 13141865Sdilpreet } 13151865Sdilpreet 13161865Sdilpreet 13171865Sdilpreet int 13181865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 13191865Sdilpreet { 13201865Sdilpreet size_t size = in_args->size; 13211865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 13221865Sdilpreet uintptr_t host_addr = in_args->host_addr; 13231865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 13241865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 13251865Sdilpreet size_t repcount = in_args->repcount; 13261865Sdilpreet uint_t flags = in_args->flags; 13271865Sdilpreet int err = DDI_SUCCESS; 13281865Sdilpreet 13291865Sdilpreet /* 13301865Sdilpreet * if no handle then this is a peek. We have to return failure here 13311865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 13321865Sdilpreet */ 13331865Sdilpreet if (in_args->handle == NULL) 13341865Sdilpreet return (DDI_FAILURE); 13351865Sdilpreet 13361865Sdilpreet for (; repcount; repcount--) { 13371865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 13381865Sdilpreet switch (size) { 13391865Sdilpreet case sizeof (uint8_t): 13401865Sdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp, 13411865Sdilpreet (uint8_t *)dev_addr); 13421865Sdilpreet break; 13431865Sdilpreet case sizeof (uint16_t): 13441865Sdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp, 13451865Sdilpreet (uint16_t *)dev_addr); 13461865Sdilpreet break; 13471865Sdilpreet case sizeof (uint32_t): 13481865Sdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp, 13491865Sdilpreet (uint32_t *)dev_addr); 13501865Sdilpreet break; 13511865Sdilpreet case sizeof (uint64_t): 13521865Sdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp, 13531865Sdilpreet (uint64_t *)dev_addr); 13541865Sdilpreet break; 13551865Sdilpreet default: 13561865Sdilpreet err = DDI_FAILURE; 13571865Sdilpreet break; 13581865Sdilpreet } 13591865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 13601865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 13611865Sdilpreet DDI_STRUCTURE_BE_ACC) { 13621865Sdilpreet switch (size) { 13631865Sdilpreet case sizeof (uint8_t): 13641865Sdilpreet *(uint8_t *)host_addr = 13651865Sdilpreet i_ddi_io_get8(hp, 13661865Sdilpreet (uint8_t *)dev_addr); 13671865Sdilpreet break; 13681865Sdilpreet case sizeof (uint16_t): 13691865Sdilpreet *(uint16_t *)host_addr = 13701865Sdilpreet i_ddi_io_swap_get16(hp, 13711865Sdilpreet (uint16_t *)dev_addr); 13721865Sdilpreet break; 13731865Sdilpreet case sizeof (uint32_t): 13741865Sdilpreet *(uint32_t *)host_addr = 13751865Sdilpreet i_ddi_io_swap_get32(hp, 13761865Sdilpreet (uint32_t *)dev_addr); 13771865Sdilpreet break; 13781865Sdilpreet /* 13791865Sdilpreet * note the 64-bit case is a dummy 13801865Sdilpreet * function - so no need to swap 13811865Sdilpreet */ 13821865Sdilpreet case sizeof (uint64_t): 13831865Sdilpreet *(uint64_t *)host_addr = 13841865Sdilpreet i_ddi_io_get64(hp, 13851865Sdilpreet (uint64_t *)dev_addr); 13861865Sdilpreet break; 13871865Sdilpreet default: 13881865Sdilpreet err = DDI_FAILURE; 13891865Sdilpreet break; 13901865Sdilpreet } 13911865Sdilpreet } else { 13921865Sdilpreet switch (size) { 13931865Sdilpreet case sizeof (uint8_t): 13941865Sdilpreet *(uint8_t *)host_addr = 13951865Sdilpreet i_ddi_io_get8(hp, 13961865Sdilpreet (uint8_t *)dev_addr); 13971865Sdilpreet break; 13981865Sdilpreet case sizeof (uint16_t): 13991865Sdilpreet *(uint16_t *)host_addr = 14001865Sdilpreet i_ddi_io_get16(hp, 14011865Sdilpreet (uint16_t *)dev_addr); 14021865Sdilpreet break; 14031865Sdilpreet case sizeof (uint32_t): 14041865Sdilpreet *(uint32_t *)host_addr = 14051865Sdilpreet i_ddi_io_get32(hp, 14061865Sdilpreet (uint32_t *)dev_addr); 14071865Sdilpreet break; 14081865Sdilpreet case sizeof (uint64_t): 14091865Sdilpreet *(uint64_t *)host_addr = 14101865Sdilpreet i_ddi_io_get64(hp, 14111865Sdilpreet (uint64_t *)dev_addr); 14121865Sdilpreet break; 14131865Sdilpreet default: 14141865Sdilpreet err = DDI_FAILURE; 14151865Sdilpreet break; 14161865Sdilpreet } 14171865Sdilpreet } 14181865Sdilpreet } else { 14191865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 14201865Sdilpreet DDI_STRUCTURE_BE_ACC) { 14211865Sdilpreet switch (in_args->size) { 14221865Sdilpreet case sizeof (uint8_t): 14231865Sdilpreet *(uint8_t *)host_addr = 14241865Sdilpreet *(uint8_t *)dev_addr; 14251865Sdilpreet break; 14261865Sdilpreet case sizeof (uint16_t): 14271865Sdilpreet *(uint16_t *)host_addr = 14281865Sdilpreet ddi_swap16(*(uint16_t *)dev_addr); 14291865Sdilpreet break; 14301865Sdilpreet case sizeof (uint32_t): 14311865Sdilpreet *(uint32_t *)host_addr = 14321865Sdilpreet ddi_swap32(*(uint32_t *)dev_addr); 14331865Sdilpreet break; 14341865Sdilpreet case sizeof (uint64_t): 14351865Sdilpreet *(uint64_t *)host_addr = 14361865Sdilpreet ddi_swap64(*(uint64_t *)dev_addr); 14371865Sdilpreet break; 14381865Sdilpreet default: 14391865Sdilpreet err = DDI_FAILURE; 14401865Sdilpreet break; 14411865Sdilpreet } 14421865Sdilpreet } else { 14431865Sdilpreet switch (in_args->size) { 14441865Sdilpreet case sizeof (uint8_t): 14451865Sdilpreet *(uint8_t *)host_addr = 14461865Sdilpreet *(uint8_t *)dev_addr; 14471865Sdilpreet break; 14481865Sdilpreet case sizeof (uint16_t): 14491865Sdilpreet *(uint16_t *)host_addr = 14501865Sdilpreet *(uint16_t *)dev_addr; 14511865Sdilpreet break; 14521865Sdilpreet case sizeof (uint32_t): 14531865Sdilpreet *(uint32_t *)host_addr = 14541865Sdilpreet *(uint32_t *)dev_addr; 14551865Sdilpreet break; 14561865Sdilpreet case sizeof (uint64_t): 14571865Sdilpreet *(uint64_t *)host_addr = 14581865Sdilpreet *(uint64_t *)dev_addr; 14591865Sdilpreet break; 14601865Sdilpreet default: 14611865Sdilpreet err = DDI_FAILURE; 14621865Sdilpreet break; 14631865Sdilpreet } 14641865Sdilpreet } 14651865Sdilpreet } 14661865Sdilpreet host_addr += size; 14671865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 14681865Sdilpreet dev_addr += size; 14691865Sdilpreet } 14701865Sdilpreet return (err); 14711865Sdilpreet } 14721865Sdilpreet 14731865Sdilpreet /*ARGSUSED*/ 14741865Sdilpreet int 14751865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 14761865Sdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result) 14771865Sdilpreet { 14781865Sdilpreet if (ctlop == DDI_CTLOPS_PEEK) 14791865Sdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 14801865Sdilpreet else 14811865Sdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 14821865Sdilpreet } 14831865Sdilpreet 14841083Sanish /* 14851083Sanish * These are the get and put functions to be shared with drivers. The 14861083Sanish * mutex locking is done inside the functions referenced, rather than 14871083Sanish * here, and is thus shared across PCI child drivers and any other 14881083Sanish * consumers of PCI config space (such as the ACPI subsystem). 14891083Sanish * 14901083Sanish * The configuration space addresses come in as pointers. This is fine on 14911083Sanish * a 32-bit system, where the VM space and configuration space are the same 14921083Sanish * size. It's not such a good idea on a 64-bit system, where memory 14931083Sanish * addresses are twice as large as configuration space addresses. At some 14941083Sanish * point in the call tree we need to take a stand and say "you are 32-bit 14951083Sanish * from this time forth", and this seems like a nice self-contained place. 14961083Sanish */ 14971083Sanish 14981083Sanish uint8_t 14991083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 15001083Sanish { 15011083Sanish pci_acc_cfblk_t *cfp; 15021083Sanish uint8_t rval; 15031083Sanish int reg; 15041083Sanish 15051083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15061083Sanish 15071083Sanish reg = (int)(uintptr_t)addr; 15081083Sanish 15091083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15101083Sanish 15111083Sanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 15121083Sanish reg); 15131083Sanish 15141083Sanish return (rval); 15151083Sanish } 15161083Sanish 15171083Sanish void 15181083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 15191083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 15201083Sanish { 15211083Sanish uint8_t *h, *d; 15221083Sanish 15231083Sanish h = host_addr; 15241083Sanish d = dev_addr; 15251083Sanish 15261083Sanish if (flags == DDI_DEV_AUTOINCR) 15271083Sanish for (; repcount; repcount--) 15281083Sanish *h++ = pci_config_rd8(hdlp, d++); 15291083Sanish else 15301083Sanish for (; repcount; repcount--) 15311083Sanish *h++ = pci_config_rd8(hdlp, d); 15321083Sanish } 15331083Sanish 15341083Sanish uint16_t 15351083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 15361083Sanish { 15371083Sanish pci_acc_cfblk_t *cfp; 15381083Sanish uint16_t rval; 15391083Sanish int reg; 15401083Sanish 15411083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15421083Sanish 15431083Sanish reg = (int)(uintptr_t)addr; 15441083Sanish 15451083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15461083Sanish 15471083Sanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 15481083Sanish reg); 15491083Sanish 15501083Sanish return (rval); 15511083Sanish } 15521083Sanish 15531083Sanish void 15541083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 15551083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 15561083Sanish { 15571083Sanish uint16_t *h, *d; 15581083Sanish 15591083Sanish h = host_addr; 15601083Sanish d = dev_addr; 15611083Sanish 15621083Sanish if (flags == DDI_DEV_AUTOINCR) 15631083Sanish for (; repcount; repcount--) 15641083Sanish *h++ = pci_config_rd16(hdlp, d++); 15651083Sanish else 15661083Sanish for (; repcount; repcount--) 15671083Sanish *h++ = pci_config_rd16(hdlp, d); 15681083Sanish } 15691083Sanish 15701083Sanish uint32_t 15711083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 15721083Sanish { 15731083Sanish pci_acc_cfblk_t *cfp; 15741083Sanish uint32_t rval; 15751083Sanish int reg; 15761083Sanish 15771083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15781083Sanish 15791083Sanish reg = (int)(uintptr_t)addr; 15801083Sanish 15811083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15821083Sanish 15831083Sanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 15841083Sanish cfp->c_funcnum, reg); 15851083Sanish 15861083Sanish return (rval); 15871083Sanish } 15881083Sanish 15891083Sanish void 15901083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 15911083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 15921083Sanish { 15931083Sanish uint32_t *h, *d; 15941083Sanish 15951083Sanish h = host_addr; 15961083Sanish d = dev_addr; 15971083Sanish 15981083Sanish if (flags == DDI_DEV_AUTOINCR) 15991083Sanish for (; repcount; repcount--) 16001083Sanish *h++ = pci_config_rd32(hdlp, d++); 16011083Sanish else 16021083Sanish for (; repcount; repcount--) 16031083Sanish *h++ = pci_config_rd32(hdlp, d); 16041083Sanish } 16051083Sanish 16061083Sanish 16071083Sanish void 16081083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 16091083Sanish { 16101083Sanish pci_acc_cfblk_t *cfp; 16111083Sanish int reg; 16121083Sanish 16131083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 16141083Sanish 16151083Sanish reg = (int)(uintptr_t)addr; 16161083Sanish 16171083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 16181083Sanish 16191083Sanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 16201083Sanish cfp->c_funcnum, reg, value); 16211083Sanish } 16221083Sanish 16231083Sanish void 16241083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 16251083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 16261083Sanish { 16271083Sanish uint8_t *h, *d; 16281083Sanish 16291083Sanish h = host_addr; 16301083Sanish d = dev_addr; 16311083Sanish 16321083Sanish if (flags == DDI_DEV_AUTOINCR) 16331083Sanish for (; repcount; repcount--) 16341083Sanish pci_config_wr8(hdlp, d++, *h++); 16351083Sanish else 16361083Sanish for (; repcount; repcount--) 16371083Sanish pci_config_wr8(hdlp, d, *h++); 16381083Sanish } 16391083Sanish 16401083Sanish void 16411083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 16421083Sanish { 16431083Sanish pci_acc_cfblk_t *cfp; 16441083Sanish int reg; 16451083Sanish 16461083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 16471083Sanish 16481083Sanish reg = (int)(uintptr_t)addr; 16491083Sanish 16501083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 16511083Sanish 16521083Sanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 16531083Sanish cfp->c_funcnum, reg, value); 16541083Sanish } 16551083Sanish 16561083Sanish void 16571083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 16581083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 16591083Sanish { 16601083Sanish uint16_t *h, *d; 16611083Sanish 16621083Sanish h = host_addr; 16631083Sanish d = dev_addr; 16641083Sanish 16651083Sanish if (flags == DDI_DEV_AUTOINCR) 16661083Sanish for (; repcount; repcount--) 16671083Sanish pci_config_wr16(hdlp, d++, *h++); 16681083Sanish else 16691083Sanish for (; repcount; repcount--) 16701083Sanish pci_config_wr16(hdlp, d, *h++); 16711083Sanish } 16721083Sanish 16731083Sanish void 16741083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 16751083Sanish { 16761083Sanish pci_acc_cfblk_t *cfp; 16771083Sanish int reg; 16781083Sanish 16791083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 16801083Sanish 16811083Sanish reg = (int)(uintptr_t)addr; 16821083Sanish 16831083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 16841083Sanish 16851083Sanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 16861083Sanish cfp->c_funcnum, reg, value); 16871083Sanish } 16881083Sanish 16891083Sanish void 16901083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 16911083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 16921083Sanish { 16931083Sanish uint32_t *h, *d; 16941083Sanish 16951083Sanish h = host_addr; 16961083Sanish d = dev_addr; 16971083Sanish 16981083Sanish if (flags == DDI_DEV_AUTOINCR) 16991083Sanish for (; repcount; repcount--) 17001083Sanish pci_config_wr32(hdlp, d++, *h++); 17011083Sanish else 17021083Sanish for (; repcount; repcount--) 17031083Sanish pci_config_wr32(hdlp, d, *h++); 17041083Sanish } 17051083Sanish 17061083Sanish uint64_t 17071083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 17081083Sanish { 17091083Sanish uint32_t lw_val; 17101083Sanish uint32_t hi_val; 17111083Sanish uint32_t *dp; 17121083Sanish uint64_t val; 17131083Sanish 17141083Sanish dp = (uint32_t *)addr; 17151083Sanish lw_val = pci_config_rd32(hdlp, dp); 17161083Sanish dp++; 17171083Sanish hi_val = pci_config_rd32(hdlp, dp); 17181083Sanish val = ((uint64_t)hi_val << 32) | lw_val; 17191083Sanish return (val); 17201083Sanish } 17211083Sanish 17221083Sanish void 17231083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 17241083Sanish { 17251083Sanish uint32_t lw_val; 17261083Sanish uint32_t hi_val; 17271083Sanish uint32_t *dp; 17281083Sanish 17291083Sanish dp = (uint32_t *)addr; 17301083Sanish lw_val = (uint32_t)(value & 0xffffffff); 17311083Sanish hi_val = (uint32_t)(value >> 32); 17321083Sanish pci_config_wr32(hdlp, dp, lw_val); 17331083Sanish dp++; 17341083Sanish pci_config_wr32(hdlp, dp, hi_val); 17351083Sanish } 17361083Sanish 17371083Sanish void 17381083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 17391083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 17401083Sanish { 17411083Sanish if (flags == DDI_DEV_AUTOINCR) { 17421083Sanish for (; repcount; repcount--) 17431083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 17441083Sanish } else { 17451083Sanish for (; repcount; repcount--) 17461083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr); 17471083Sanish } 17481083Sanish } 17491083Sanish 17501083Sanish void 17511083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 17521083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 17531083Sanish { 17541083Sanish if (flags == DDI_DEV_AUTOINCR) { 17551083Sanish for (; repcount; repcount--) 17561083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr++); 17571083Sanish } else { 17581083Sanish for (; repcount; repcount--) 17591083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr); 17601083Sanish } 17611083Sanish } 1762