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 /* 233446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24881Sjohnny * Use is subject to license terms. 25881Sjohnny */ 26881Sjohnny 27881Sjohnny #pragma ident "%Z%%M% %I% %E% SMI" 28881Sjohnny 29881Sjohnny /* 30881Sjohnny * File that has code which is common between pci(7d) and npe(7d) 31881Sjohnny * It shares the following: 32881Sjohnny * - interrupt code 33881Sjohnny * - pci_tools ioctl code 34881Sjohnny * - name_child code 35881Sjohnny * - set_parent_private_data code 36881Sjohnny */ 37881Sjohnny 38881Sjohnny #include <sys/conf.h> 39881Sjohnny #include <sys/pci.h> 40881Sjohnny #include <sys/sunndi.h> 41916Sschwartz #include <sys/mach_intr.h> 42881Sjohnny #include <sys/hotplug/pci/pcihp.h> 43881Sjohnny #include <sys/pci_intr_lib.h> 44881Sjohnny #include <sys/psm.h> 45881Sjohnny #include <sys/policy.h> 46881Sjohnny #include <sys/sysmacros.h> 47916Sschwartz #include <sys/clock.h> 483446Smrj #include <sys/apic.h> 49881Sjohnny #include <sys/pci_tools.h> 50881Sjohnny #include <io/pci/pci_var.h> 51881Sjohnny #include <io/pci/pci_tools_ext.h> 52881Sjohnny #include <io/pci/pci_common.h> 531083Sanish #include <sys/pci_cfgspace.h> 541083Sanish #include <sys/pci_impl.h> 55*4160Sjveta #include <sys/pci_cap.h> 56881Sjohnny 57881Sjohnny /* 58881Sjohnny * Function prototypes 59881Sjohnny */ 60881Sjohnny static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *); 61881Sjohnny static int pci_enable_intr(dev_info_t *, dev_info_t *, 62881Sjohnny ddi_intr_handle_impl_t *, uint32_t); 63881Sjohnny static void pci_disable_intr(dev_info_t *, dev_info_t *, 64881Sjohnny ddi_intr_handle_impl_t *, uint32_t); 65881Sjohnny 66881Sjohnny /* Extern decalration for pcplusmp module */ 67881Sjohnny extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 68881Sjohnny psm_intr_op_t, int *); 69881Sjohnny 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) + 148881Sjohnny 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)) { 169881Sjohnny int class = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 170881Sjohnny DDI_PROP_DONTPASS, "class-code", -1); 171881Sjohnny 172881Sjohnny *pri = (class == -1) ? 1 : pci_devclass_to_ipl(class); 173881Sjohnny pci_common_set_parent_private_data(hdlp->ih_dip); 174881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 175881Sjohnny hdlp->ih_inum); 176881Sjohnny return (DDI_SUCCESS); 177881Sjohnny } 178881Sjohnny return (DDI_FAILURE); 179881Sjohnny } 180881Sjohnny 181881Sjohnny *pri = ispec->intrspec_pri; 182881Sjohnny return (DDI_SUCCESS); 183881Sjohnny } 184881Sjohnny 185881Sjohnny 186881Sjohnny 187881Sjohnny static int pcie_pci_intr_pri_counter = 0; 188881Sjohnny 189881Sjohnny /* 190881Sjohnny * pci_common_intr_ops: bus_intr_op() function for interrupt support 191881Sjohnny */ 192881Sjohnny int 193881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 194881Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 195881Sjohnny { 196881Sjohnny int priority = 0; 197881Sjohnny int psm_status = 0; 198881Sjohnny int pci_status = 0; 199881Sjohnny int pci_rval, psm_rval = PSM_FAILURE; 200881Sjohnny int types = 0; 201881Sjohnny int pciepci = 0; 2021542Sjohnny int i, j, count; 203*4160Sjveta int rv; 204881Sjohnny int behavior; 2051997Sanish int cap_ptr; 206*4160Sjveta uint16_t msi_cap_base, msix_cap_base, cap_ctrl; 207*4160Sjveta char *prop; 208881Sjohnny ddi_intrspec_t isp; 209881Sjohnny struct intrspec *ispec; 210881Sjohnny ddi_intr_handle_impl_t tmp_hdl; 211881Sjohnny ddi_intr_msix_t *msix_p; 2121087Sschwartz ihdl_plat_t *ihdl_plat_datap; 2131542Sjohnny ddi_intr_handle_t *h_array; 2141997Sanish ddi_acc_handle_t handle; 215881Sjohnny 216881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 217881Sjohnny "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 218881Sjohnny (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 219881Sjohnny 220881Sjohnny /* Process the request */ 221881Sjohnny switch (intr_op) { 222881Sjohnny case DDI_INTROP_SUPPORTED_TYPES: 223*4160Sjveta /* 224*4160Sjveta * First we determine the interrupt types supported by the 225*4160Sjveta * device itself, then we filter them through what the OS 226*4160Sjveta * and system supports. We determine system-level 227*4160Sjveta * interrupt type support for anything other than fixed intrs 228*4160Sjveta * through the psm_intr_ops vector 229*4160Sjveta */ 230*4160Sjveta rv = DDI_FAILURE; 231*4160Sjveta 232881Sjohnny /* Fixed supported by default */ 233*4160Sjveta types = DDI_INTR_TYPE_FIXED; 234*4160Sjveta 235*4160Sjveta if (psm_intr_ops == NULL) { 236*4160Sjveta *(int *)result = types; 237*4160Sjveta return (DDI_SUCCESS); 238*4160Sjveta } 239*4160Sjveta if (pci_config_setup(rdip, &handle) != DDI_SUCCESS) 240*4160Sjveta return (DDI_FAILURE); 241881Sjohnny 242*4160Sjveta /* Sanity test cap control values if found */ 243*4160Sjveta 244*4160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) == 245*4160Sjveta DDI_SUCCESS) { 246*4160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base, 247*4160Sjveta PCI_MSI_CTRL); 248*4160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 249*4160Sjveta goto SUPPORTED_TYPES_OUT; 250*4160Sjveta 251*4160Sjveta types |= DDI_INTR_TYPE_MSI; 252*4160Sjveta } 253*4160Sjveta 254*4160Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) == 255*4160Sjveta DDI_SUCCESS) { 256*4160Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base, 257*4160Sjveta PCI_MSIX_CTRL); 258*4160Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 259*4160Sjveta goto SUPPORTED_TYPES_OUT; 260881Sjohnny 261*4160Sjveta types |= DDI_INTR_TYPE_MSIX; 262*4160Sjveta } 263*4160Sjveta 264*4160Sjveta /* 265*4160Sjveta * Filter device-level types through system-level support 266*4160Sjveta */ 267*4160Sjveta 268*4160Sjveta /* No official MSI-X support for now */ 269*4160Sjveta types &= ~DDI_INTR_TYPE_MSIX; 270*4160Sjveta 271*4160Sjveta tmp_hdl.ih_type = types; 272*4160Sjveta if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI, 273*4160Sjveta &types) != PSM_SUCCESS) 274*4160Sjveta goto SUPPORTED_TYPES_OUT; 275*4160Sjveta 276*4160Sjveta DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 277*4160Sjveta "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, 278*4160Sjveta *(int *)result)); 279881Sjohnny 280*4160Sjveta /* 281*4160Sjveta * Export any MSI/MSI-X cap locations via properties 282*4160Sjveta */ 283*4160Sjveta if (types & DDI_INTR_TYPE_MSI) { 284*4160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 285*4160Sjveta "pci-msi-capid-pointer", (int)msi_cap_base) != 286*4160Sjveta DDI_PROP_SUCCESS) 287*4160Sjveta goto SUPPORTED_TYPES_OUT; 288881Sjohnny } 289*4160Sjveta if (types & DDI_INTR_TYPE_MSIX) { 290*4160Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 291*4160Sjveta "pci-msix-capid-pointer", (int)msix_cap_base) != 292*4160Sjveta DDI_PROP_SUCCESS) 293*4160Sjveta goto SUPPORTED_TYPES_OUT; 294*4160Sjveta } 295*4160Sjveta 296*4160Sjveta rv = DDI_SUCCESS; 297*4160Sjveta 298*4160Sjveta SUPPORTED_TYPES_OUT: 299*4160Sjveta *(int *)result = types; 300*4160Sjveta pci_config_teardown(&handle); 301*4160Sjveta return (rv); 302*4160Sjveta 3032580Sanish case DDI_INTROP_NAVAIL: 304881Sjohnny case DDI_INTROP_NINTRS: 3052580Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 3062580Sanish if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type, 3072580Sanish result) != DDI_SUCCESS) 3082580Sanish return (DDI_FAILURE); 3092580Sanish } else { 3102580Sanish *(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip); 3112580Sanish if (*(int *)result == 0) 3122580Sanish return (DDI_FAILURE); 3132580Sanish } 314881Sjohnny break; 315881Sjohnny case DDI_INTROP_ALLOC: 316881Sjohnny /* 317881Sjohnny * MSI or MSIX (figure out number of vectors available) 318881Sjohnny * FIXED interrupts: just return available interrupts 319881Sjohnny */ 320881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 321881Sjohnny (psm_intr_ops != NULL) && 322881Sjohnny (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) { 323881Sjohnny /* 324881Sjohnny * Following check is a special case for 'pcie_pci'. 325881Sjohnny * This makes sure vectors with the right priority 326881Sjohnny * are allocated for pcie_pci during ALLOC time. 327881Sjohnny */ 328881Sjohnny if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) { 329881Sjohnny hdlp->ih_pri = 330881Sjohnny (pcie_pci_intr_pri_counter % 2) ? 4 : 7; 331881Sjohnny pciepci = 1; 332881Sjohnny } else 333881Sjohnny hdlp->ih_pri = priority; 3341717Swesolows behavior = (int)(uintptr_t)hdlp->ih_scratch2; 3351997Sanish 3361997Sanish /* 3371997Sanish * Cache in the config handle and cap_ptr 3381997Sanish */ 3391997Sanish if (i_ddi_get_pci_config_handle(rdip) == NULL) { 3401997Sanish if (pci_config_setup(rdip, &handle) != 3411997Sanish DDI_SUCCESS) 3421997Sanish return (DDI_FAILURE); 3431997Sanish i_ddi_set_pci_config_handle(rdip, handle); 3441997Sanish } 3451997Sanish 346*4160Sjveta prop = NULL; 347*4160Sjveta cap_ptr = 0; 348*4160Sjveta if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 349*4160Sjveta prop = "pci-msi-capid-pointer"; 350*4160Sjveta else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) 351*4160Sjveta prop = "pci-msix-capid-pointer"; 3521997Sanish 353*4160Sjveta /* 354*4160Sjveta * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES 355*4160Sjveta * for MSI(X) before allocation 356*4160Sjveta */ 357*4160Sjveta if (prop != NULL) { 3581997Sanish cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 359*4160Sjveta DDI_PROP_DONTPASS, prop, 0); 360*4160Sjveta if (cap_ptr == 0) { 361*4160Sjveta DDI_INTR_NEXDBG((CE_CONT, 362*4160Sjveta "pci_common_intr_ops: rdip: 0x%p " 363*4160Sjveta "attempted MSI(X) alloc without " 364*4160Sjveta "cap property\n", (void *)rdip)); 365*4160Sjveta return (DDI_FAILURE); 366*4160Sjveta } 3671997Sanish } 368*4160Sjveta i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); 3691997Sanish 370*4160Sjveta /* 371*4160Sjveta * Allocate interrupt vectors 372*4160Sjveta */ 373881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 374881Sjohnny PSM_INTR_OP_ALLOC_VECTORS, result); 375881Sjohnny 3763112Sanish if (*(int *)result == 0) 3773112Sanish return (DDI_INTR_NOTFOUND); 3783112Sanish 379881Sjohnny /* verify behavior flag and take appropriate action */ 380881Sjohnny if ((behavior == DDI_INTR_ALLOC_STRICT) && 381881Sjohnny (*(int *)result < hdlp->ih_scratch1)) { 382881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 383881Sjohnny "pci_common_intr_ops: behavior %x, " 384881Sjohnny "couldn't get enough intrs\n", behavior)); 385881Sjohnny hdlp->ih_scratch1 = *(int *)result; 386881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 387881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 388881Sjohnny return (DDI_EAGAIN); 389881Sjohnny } 390881Sjohnny 391881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 392881Sjohnny if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 393881Sjohnny msix_p = pci_msix_init(hdlp->ih_dip); 394881Sjohnny if (msix_p) 395881Sjohnny i_ddi_set_msix(hdlp->ih_dip, 396881Sjohnny msix_p); 397881Sjohnny } 398881Sjohnny } 399881Sjohnny 400881Sjohnny if (pciepci) { 401881Sjohnny /* update priority in ispec */ 402881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, 403881Sjohnny (int)hdlp->ih_inum); 404881Sjohnny ispec = (struct intrspec *)isp; 405881Sjohnny if (ispec) 406881Sjohnny ispec->intrspec_pri = hdlp->ih_pri; 407881Sjohnny ++pcie_pci_intr_pri_counter; 408881Sjohnny } 409881Sjohnny 410881Sjohnny } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 411881Sjohnny /* Figure out if this device supports MASKING */ 412881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 413881Sjohnny if (pci_rval == DDI_SUCCESS && pci_status) 414881Sjohnny hdlp->ih_cap |= pci_status; 415881Sjohnny *(int *)result = 1; /* DDI_INTR_TYPE_FIXED */ 416881Sjohnny } else 417881Sjohnny return (DDI_FAILURE); 418881Sjohnny break; 419881Sjohnny case DDI_INTROP_FREE: 420881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 421881Sjohnny (psm_intr_ops != NULL)) { 4222018Sanish if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 == 4232018Sanish 0) { 4241997Sanish if (handle = i_ddi_get_pci_config_handle( 4251997Sanish rdip)) { 4261997Sanish (void) pci_config_teardown(&handle); 4271997Sanish i_ddi_set_pci_config_handle(rdip, NULL); 4281997Sanish } 4291997Sanish if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip)) 4301997Sanish i_ddi_set_msi_msix_cap_ptr(rdip, 0); 4311997Sanish } 4321997Sanish 433881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 434881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 435881Sjohnny 436881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 437881Sjohnny msix_p = i_ddi_get_msix(hdlp->ih_dip); 438881Sjohnny if (msix_p && 4392018Sanish (i_ddi_intr_get_current_nintrs( 4402018Sanish hdlp->ih_dip) - 1) == 0) { 441881Sjohnny pci_msix_fini(msix_p); 442881Sjohnny i_ddi_set_msix(hdlp->ih_dip, NULL); 443881Sjohnny } 444881Sjohnny } 445881Sjohnny } 446881Sjohnny break; 447881Sjohnny case DDI_INTROP_GETPRI: 448881Sjohnny /* Get the priority */ 449881Sjohnny if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS) 450881Sjohnny return (DDI_FAILURE); 451881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 452881Sjohnny "priority = 0x%x\n", priority)); 453881Sjohnny *(int *)result = priority; 454881Sjohnny break; 455881Sjohnny case DDI_INTROP_SETPRI: 456881Sjohnny /* Validate the interrupt priority passed */ 457881Sjohnny if (*(int *)result > LOCK_LEVEL) 458881Sjohnny return (DDI_FAILURE); 459881Sjohnny 460881Sjohnny /* Ensure that PSM is all initialized */ 461881Sjohnny if (psm_intr_ops == NULL) 462881Sjohnny return (DDI_FAILURE); 463881Sjohnny 464881Sjohnny /* Change the priority */ 465881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 466881Sjohnny PSM_FAILURE) 467881Sjohnny return (DDI_FAILURE); 468881Sjohnny 469881Sjohnny /* update ispec */ 470881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 471881Sjohnny ispec = (struct intrspec *)isp; 472881Sjohnny if (ispec) 473881Sjohnny ispec->intrspec_pri = *(int *)result; 474881Sjohnny break; 475881Sjohnny case DDI_INTROP_ADDISR: 476881Sjohnny /* update ispec */ 477881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 478881Sjohnny ispec = (struct intrspec *)isp; 4791087Sschwartz if (ispec) { 480881Sjohnny ispec->intrspec_func = hdlp->ih_cb_func; 4811087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 4821087Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 4831087Sschwartz } 484881Sjohnny break; 485881Sjohnny case DDI_INTROP_REMISR: 486881Sjohnny /* Get the interrupt structure pointer */ 487881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 488881Sjohnny ispec = (struct intrspec *)isp; 4891087Sschwartz if (ispec) { 490881Sjohnny ispec->intrspec_func = (uint_t (*)()) 0; 4911087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 4921087Sschwartz if (ihdl_plat_datap->ip_ksp != NULL) 4931087Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp); 4941087Sschwartz } 495881Sjohnny break; 496881Sjohnny case DDI_INTROP_GETCAP: 497881Sjohnny /* 498881Sjohnny * First check the config space and/or 499881Sjohnny * MSI capability register(s) 500881Sjohnny */ 501881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 502881Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 503881Sjohnny &pci_status); 504881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 505881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 506881Sjohnny 507881Sjohnny /* next check with pcplusmp */ 508881Sjohnny if (psm_intr_ops != NULL) 509881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 510881Sjohnny PSM_INTR_OP_GET_CAP, &psm_status); 511881Sjohnny 512881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 513881Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n", 514881Sjohnny psm_rval, psm_status, pci_rval, pci_status)); 515881Sjohnny 516881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 517881Sjohnny *(int *)result = 0; 518881Sjohnny return (DDI_FAILURE); 519881Sjohnny } 520881Sjohnny 521881Sjohnny if (psm_rval == PSM_SUCCESS) 522881Sjohnny *(int *)result = psm_status; 523881Sjohnny 524881Sjohnny if (pci_rval == DDI_SUCCESS) 525881Sjohnny *(int *)result |= pci_status; 526881Sjohnny 527881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 528881Sjohnny *(int *)result)); 529881Sjohnny break; 530881Sjohnny case DDI_INTROP_SETCAP: 531881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 532881Sjohnny "SETCAP cap=0x%x\n", *(int *)result)); 533881Sjohnny if (psm_intr_ops == NULL) 534881Sjohnny return (DDI_FAILURE); 535881Sjohnny 536881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 537881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 538881Sjohnny " returned failure\n")); 539881Sjohnny return (DDI_FAILURE); 540881Sjohnny } 541881Sjohnny break; 542881Sjohnny case DDI_INTROP_ENABLE: 543881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 544881Sjohnny if (psm_intr_ops == NULL) 545881Sjohnny return (DDI_FAILURE); 546881Sjohnny 547881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 548881Sjohnny DDI_SUCCESS) 549881Sjohnny return (DDI_FAILURE); 550881Sjohnny 551881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 552881Sjohnny "vector=0x%x\n", hdlp->ih_vector)); 553881Sjohnny break; 554881Sjohnny case DDI_INTROP_DISABLE: 555881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 556881Sjohnny if (psm_intr_ops == NULL) 557881Sjohnny return (DDI_FAILURE); 558881Sjohnny 559881Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 560881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 561881Sjohnny "vector = %x\n", hdlp->ih_vector)); 562881Sjohnny break; 563881Sjohnny case DDI_INTROP_BLOCKENABLE: 564881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 565881Sjohnny "BLOCKENABLE\n")); 566881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 567881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 568881Sjohnny return (DDI_FAILURE); 569881Sjohnny } 570881Sjohnny 571881Sjohnny /* Check if psm_intr_ops is NULL? */ 572881Sjohnny if (psm_intr_ops == NULL) 573881Sjohnny return (DDI_FAILURE); 574881Sjohnny 5751542Sjohnny count = hdlp->ih_scratch1; 5761542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 5771542Sjohnny for (i = 0; i < count; i++) { 5781542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 579881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, 5801542Sjohnny hdlp->ih_inum) != DDI_SUCCESS) { 581881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 582881Sjohnny "pci_enable_intr failed for %d\n", i)); 5831542Sjohnny for (j = 0; j < i; j++) { 5841542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[j]; 5851542Sjohnny pci_disable_intr(pdip, rdip, hdlp, 5861542Sjohnny hdlp->ih_inum); 5871542Sjohnny } 588881Sjohnny return (DDI_FAILURE); 589881Sjohnny } 590881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 5911542Sjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 592881Sjohnny } 593881Sjohnny break; 594881Sjohnny case DDI_INTROP_BLOCKDISABLE: 595881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 596881Sjohnny "BLOCKDISABLE\n")); 597881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 598881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 599881Sjohnny return (DDI_FAILURE); 600881Sjohnny } 601881Sjohnny 602881Sjohnny /* Check if psm_intr_ops is present */ 603881Sjohnny if (psm_intr_ops == NULL) 604881Sjohnny return (DDI_FAILURE); 605881Sjohnny 6061542Sjohnny count = hdlp->ih_scratch1; 6071542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 6081542Sjohnny for (i = 0; i < count; i++) { 6091542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 6101542Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 611881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 6121542Sjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 613881Sjohnny } 614881Sjohnny break; 615881Sjohnny case DDI_INTROP_SETMASK: 616881Sjohnny case DDI_INTROP_CLRMASK: 617881Sjohnny /* 618881Sjohnny * First handle in the config space 619881Sjohnny */ 620881Sjohnny if (intr_op == DDI_INTROP_SETMASK) { 621881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 622881Sjohnny pci_status = pci_msi_set_mask(rdip, 623881Sjohnny hdlp->ih_type, hdlp->ih_inum); 624881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 625881Sjohnny pci_status = pci_intx_set_mask(rdip); 626881Sjohnny } else { 627881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 628881Sjohnny pci_status = pci_msi_clr_mask(rdip, 629881Sjohnny hdlp->ih_type, hdlp->ih_inum); 630881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 631881Sjohnny pci_status = pci_intx_clr_mask(rdip); 632881Sjohnny } 633881Sjohnny 634881Sjohnny /* For MSI/X; no need to check with pcplusmp */ 635881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 636881Sjohnny return (pci_status); 637881Sjohnny 638881Sjohnny /* For fixed interrupts only: handle config space first */ 639881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 640881Sjohnny pci_status == DDI_SUCCESS) 641881Sjohnny break; 642881Sjohnny 643881Sjohnny /* For fixed interrupts only: confer with pcplusmp next */ 644881Sjohnny if (psm_intr_ops != NULL) { 645881Sjohnny /* If interrupt is shared; do nothing */ 646881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 647881Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status); 648881Sjohnny 649881Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1) 650881Sjohnny return (pci_status); 651881Sjohnny 652881Sjohnny /* Now, pcplusmp should try to set/clear the mask */ 653881Sjohnny if (intr_op == DDI_INTROP_SETMASK) 654881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 655881Sjohnny PSM_INTR_OP_SET_MASK, NULL); 656881Sjohnny else 657881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 658881Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL); 659881Sjohnny } 660881Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 661881Sjohnny case DDI_INTROP_GETPENDING: 662881Sjohnny /* 663881Sjohnny * First check the config space and/or 664881Sjohnny * MSI capability register(s) 665881Sjohnny */ 666881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 667881Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 668881Sjohnny hdlp->ih_inum, &pci_status); 669881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 670881Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status); 671881Sjohnny 672881Sjohnny /* On failure; next try with pcplusmp */ 673881Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 674881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 675881Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status); 676881Sjohnny 677881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 678881Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, " 679881Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval, 680881Sjohnny pci_status)); 681881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 682881Sjohnny *(int *)result = 0; 683881Sjohnny return (DDI_FAILURE); 684881Sjohnny } 685881Sjohnny 686881Sjohnny if (psm_rval != PSM_FAILURE) 687881Sjohnny *(int *)result = psm_status; 688881Sjohnny else if (pci_rval != DDI_FAILURE) 689881Sjohnny *(int *)result = pci_status; 690881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 691881Sjohnny *(int *)result)); 692881Sjohnny break; 693881Sjohnny default: 694881Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 695881Sjohnny } 696881Sjohnny 697881Sjohnny return (DDI_SUCCESS); 698881Sjohnny } 699881Sjohnny 700916Sschwartz int 701916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 702916Sschwartz int vecirq, boolean_t is_irq) 703916Sschwartz { 704916Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl; 705916Sschwartz 706916Sschwartz if (is_irq) 707916Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 708916Sschwartz 709916Sschwartz /* 710916Sschwartz * For this locally-declared and used handle, ih_private will contain a 711916Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 712916Sschwartz * global interrupt handling. 713916Sschwartz */ 714916Sschwartz get_info_ii_hdl.ih_private = intrinfo_p; 715916Sschwartz get_info_ii_hdl.ih_vector = (ushort_t)vecirq; 716916Sschwartz 717916Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 718916Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 719916Sschwartz return (DDI_FAILURE); 720916Sschwartz 721916Sschwartz return (DDI_SUCCESS); 722916Sschwartz } 723916Sschwartz 724916Sschwartz 725916Sschwartz int 726916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 727916Sschwartz { 728916Sschwartz int rval; 729916Sschwartz 730916Sschwartz apic_get_intr_t intrinfo; 731916Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 732916Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 733916Sschwartz 734916Sschwartz if (rval == DDI_SUCCESS) 735916Sschwartz return (intrinfo.avgi_cpu_id); 736916Sschwartz else 737916Sschwartz return (-1); 738916Sschwartz } 739916Sschwartz 740881Sjohnny 741881Sjohnny static int 742881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 743881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 744881Sjohnny { 745881Sjohnny struct intrspec *ispec; 746916Sschwartz int irq; 747916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 748881Sjohnny 749881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 750881Sjohnny (void *)hdlp, inum)); 751881Sjohnny 752881Sjohnny /* Translate the interrupt if needed */ 753881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 7542288Sanish if (ispec == NULL) 7552288Sanish return (DDI_FAILURE); 7562288Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 757881Sjohnny ispec->intrspec_vec = inum; 758916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 759881Sjohnny 760881Sjohnny /* translate the interrupt if needed */ 761916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 762916Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 763916Sschwartz hdlp->ih_pri, irq)); 764881Sjohnny 765881Sjohnny /* Add the interrupt handler */ 766881Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 767916Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 768916Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 769881Sjohnny return (DDI_FAILURE); 770881Sjohnny 771916Sschwartz /* Note this really is an irq. */ 772916Sschwartz hdlp->ih_vector = (ushort_t)irq; 773916Sschwartz 774881Sjohnny return (DDI_SUCCESS); 775881Sjohnny } 776881Sjohnny 777881Sjohnny 778881Sjohnny static void 779881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 780881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 781881Sjohnny { 782916Sschwartz int irq; 783881Sjohnny struct intrspec *ispec; 784916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 785881Sjohnny 786881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 787881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 7882288Sanish if (ispec == NULL) 7892288Sanish return; 7902288Sanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 791881Sjohnny ispec->intrspec_vec = inum; 792916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 793881Sjohnny 794881Sjohnny /* translate the interrupt if needed */ 795916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 796881Sjohnny 797881Sjohnny /* Disable the interrupt handler */ 798916Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 799916Sschwartz ihdl_plat_datap->ip_ispecp = NULL; 800881Sjohnny } 801881Sjohnny 802881Sjohnny /* 803881Sjohnny * Miscellaneous library function 804881Sjohnny */ 805881Sjohnny int 806881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 807881Sjohnny { 808881Sjohnny int i; 809881Sjohnny int number; 810881Sjohnny int assigned_addr_len; 811881Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi; 812881Sjohnny pci_regspec_t *assigned_addr; 813881Sjohnny 814881Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 815881Sjohnny (phys_hi & PCI_RELOCAT_B)) 816881Sjohnny return (DDI_SUCCESS); 817881Sjohnny 818881Sjohnny /* 819881Sjohnny * the "reg" property specifies relocatable, get and interpret the 820881Sjohnny * "assigned-addresses" property. 821881Sjohnny */ 822881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 823881Sjohnny "assigned-addresses", (int **)&assigned_addr, 824881Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 825881Sjohnny return (DDI_FAILURE); 826881Sjohnny 827881Sjohnny /* 828881Sjohnny * Scan the "assigned-addresses" for one that matches the specified 829881Sjohnny * "reg" property entry. 830881Sjohnny */ 831881Sjohnny phys_hi &= PCI_CONF_ADDR_MASK; 832881Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 833881Sjohnny for (i = 0; i < number; i++) { 834881Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 835881Sjohnny phys_hi) { 836881Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 837881Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 838881Sjohnny ddi_prop_free(assigned_addr); 839881Sjohnny return (DDI_SUCCESS); 840881Sjohnny } 841881Sjohnny } 842881Sjohnny 843881Sjohnny ddi_prop_free(assigned_addr); 844881Sjohnny return (DDI_FAILURE); 845881Sjohnny } 846881Sjohnny 847881Sjohnny 848881Sjohnny /* 849881Sjohnny * For pci_tools 850881Sjohnny */ 851881Sjohnny 852881Sjohnny int 853881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 854881Sjohnny int mode, cred_t *credp, int *rvalp) 855881Sjohnny { 856881Sjohnny int rv = ENOTTY; 857881Sjohnny 858881Sjohnny minor_t minor = getminor(dev); 859881Sjohnny 860881Sjohnny switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 861881Sjohnny case PCI_TOOL_REG_MINOR_NUM: 862881Sjohnny 863881Sjohnny switch (cmd) { 864881Sjohnny case PCITOOL_DEVICE_SET_REG: 865881Sjohnny case PCITOOL_DEVICE_GET_REG: 866881Sjohnny 867881Sjohnny /* Require full privileges. */ 868881Sjohnny if (secpolicy_kmdb(credp)) 869881Sjohnny rv = EPERM; 870881Sjohnny else 871881Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg, 872881Sjohnny cmd, mode); 873881Sjohnny break; 874881Sjohnny 875881Sjohnny case PCITOOL_NEXUS_SET_REG: 876881Sjohnny case PCITOOL_NEXUS_GET_REG: 877881Sjohnny 878881Sjohnny /* Require full privileges. */ 879881Sjohnny if (secpolicy_kmdb(credp)) 880881Sjohnny rv = EPERM; 881881Sjohnny else 882881Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg, 883881Sjohnny cmd, mode); 884881Sjohnny break; 885881Sjohnny } 886881Sjohnny break; 887881Sjohnny 888881Sjohnny case PCI_TOOL_INTR_MINOR_NUM: 889881Sjohnny 890881Sjohnny switch (cmd) { 891881Sjohnny case PCITOOL_DEVICE_SET_INTR: 892881Sjohnny 893881Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 894881Sjohnny if (secpolicy_ponline(credp)) { 895881Sjohnny rv = EPERM; 896881Sjohnny break; 897881Sjohnny } 898881Sjohnny 899881Sjohnny /*FALLTHRU*/ 900881Sjohnny /* These require no special privileges. */ 901881Sjohnny case PCITOOL_DEVICE_GET_INTR: 902881Sjohnny case PCITOOL_DEVICE_NUM_INTR: 903881Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 904881Sjohnny break; 905881Sjohnny } 906881Sjohnny break; 907881Sjohnny 908881Sjohnny /* 909881Sjohnny * All non-PCItool ioctls go through here, including: 910881Sjohnny * devctl ioctls with minor number PCIHP_DEVCTL_MINOR and 911881Sjohnny * those for attachment points with where minor number is the 912881Sjohnny * device number. 913881Sjohnny */ 914881Sjohnny default: 915881Sjohnny rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 916881Sjohnny credp, rvalp); 917881Sjohnny break; 918881Sjohnny } 919881Sjohnny 920881Sjohnny return (rv); 921881Sjohnny } 9221083Sanish 9231083Sanish 9241865Sdilpreet int 9251865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 9261865Sdilpreet { 9271865Sdilpreet size_t size = in_args->size; 9281865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 9291865Sdilpreet uintptr_t host_addr = in_args->host_addr; 9301865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 9311865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 9321865Sdilpreet size_t repcount = in_args->repcount; 9331865Sdilpreet uint_t flags = in_args->flags; 9341865Sdilpreet int err = DDI_SUCCESS; 9351865Sdilpreet 9361865Sdilpreet /* 9371865Sdilpreet * if no handle then this is a poke. We have to return failure here 9381865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 9391865Sdilpreet */ 9401865Sdilpreet if (in_args->handle == NULL) 9411865Sdilpreet return (DDI_FAILURE); 9421865Sdilpreet 9431865Sdilpreet /* 9441865Sdilpreet * rest of this function is actually for cautious puts 9451865Sdilpreet */ 9461865Sdilpreet for (; repcount; repcount--) { 9471865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 9481865Sdilpreet switch (size) { 9491865Sdilpreet case sizeof (uint8_t): 9501865Sdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr, 9511865Sdilpreet *(uint8_t *)host_addr); 9521865Sdilpreet break; 9531865Sdilpreet case sizeof (uint16_t): 9541865Sdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr, 9551865Sdilpreet *(uint16_t *)host_addr); 9561865Sdilpreet break; 9571865Sdilpreet case sizeof (uint32_t): 9581865Sdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr, 9591865Sdilpreet *(uint32_t *)host_addr); 9601865Sdilpreet break; 9611865Sdilpreet case sizeof (uint64_t): 9621865Sdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr, 9631865Sdilpreet *(uint64_t *)host_addr); 9641865Sdilpreet break; 9651865Sdilpreet default: 9661865Sdilpreet err = DDI_FAILURE; 9671865Sdilpreet break; 9681865Sdilpreet } 9691865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 9701865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 9711865Sdilpreet DDI_STRUCTURE_BE_ACC) { 9721865Sdilpreet switch (size) { 9731865Sdilpreet case sizeof (uint8_t): 9741865Sdilpreet i_ddi_io_put8(hp, 9751865Sdilpreet (uint8_t *)dev_addr, 9761865Sdilpreet *(uint8_t *)host_addr); 9771865Sdilpreet break; 9781865Sdilpreet case sizeof (uint16_t): 9791865Sdilpreet i_ddi_io_swap_put16(hp, 9801865Sdilpreet (uint16_t *)dev_addr, 9811865Sdilpreet *(uint16_t *)host_addr); 9821865Sdilpreet break; 9831865Sdilpreet case sizeof (uint32_t): 9841865Sdilpreet i_ddi_io_swap_put32(hp, 9851865Sdilpreet (uint32_t *)dev_addr, 9861865Sdilpreet *(uint32_t *)host_addr); 9871865Sdilpreet break; 9881865Sdilpreet /* 9891865Sdilpreet * note the 64-bit case is a dummy 9901865Sdilpreet * function - so no need to swap 9911865Sdilpreet */ 9921865Sdilpreet case sizeof (uint64_t): 9931865Sdilpreet i_ddi_io_put64(hp, 9941865Sdilpreet (uint64_t *)dev_addr, 9951865Sdilpreet *(uint64_t *)host_addr); 9961865Sdilpreet break; 9971865Sdilpreet default: 9981865Sdilpreet err = DDI_FAILURE; 9991865Sdilpreet break; 10001865Sdilpreet } 10011865Sdilpreet } else { 10021865Sdilpreet switch (size) { 10031865Sdilpreet case sizeof (uint8_t): 10041865Sdilpreet i_ddi_io_put8(hp, 10051865Sdilpreet (uint8_t *)dev_addr, 10061865Sdilpreet *(uint8_t *)host_addr); 10071865Sdilpreet break; 10081865Sdilpreet case sizeof (uint16_t): 10091865Sdilpreet i_ddi_io_put16(hp, 10101865Sdilpreet (uint16_t *)dev_addr, 10111865Sdilpreet *(uint16_t *)host_addr); 10121865Sdilpreet break; 10131865Sdilpreet case sizeof (uint32_t): 10141865Sdilpreet i_ddi_io_put32(hp, 10151865Sdilpreet (uint32_t *)dev_addr, 10161865Sdilpreet *(uint32_t *)host_addr); 10171865Sdilpreet break; 10181865Sdilpreet case sizeof (uint64_t): 10191865Sdilpreet i_ddi_io_put64(hp, 10201865Sdilpreet (uint64_t *)dev_addr, 10211865Sdilpreet *(uint64_t *)host_addr); 10221865Sdilpreet break; 10231865Sdilpreet default: 10241865Sdilpreet err = DDI_FAILURE; 10251865Sdilpreet break; 10261865Sdilpreet } 10271865Sdilpreet } 10281865Sdilpreet } else { 10291865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 10301865Sdilpreet DDI_STRUCTURE_BE_ACC) { 10311865Sdilpreet switch (size) { 10321865Sdilpreet case sizeof (uint8_t): 10331865Sdilpreet *(uint8_t *)dev_addr = 10341865Sdilpreet *(uint8_t *)host_addr; 10351865Sdilpreet break; 10361865Sdilpreet case sizeof (uint16_t): 10371865Sdilpreet *(uint16_t *)dev_addr = 10381865Sdilpreet ddi_swap16(*(uint16_t *)host_addr); 10391865Sdilpreet break; 10401865Sdilpreet case sizeof (uint32_t): 10411865Sdilpreet *(uint32_t *)dev_addr = 10421865Sdilpreet ddi_swap32(*(uint32_t *)host_addr); 10431865Sdilpreet break; 10441865Sdilpreet case sizeof (uint64_t): 10451865Sdilpreet *(uint64_t *)dev_addr = 10461865Sdilpreet ddi_swap64(*(uint64_t *)host_addr); 10471865Sdilpreet break; 10481865Sdilpreet default: 10491865Sdilpreet err = DDI_FAILURE; 10501865Sdilpreet break; 10511865Sdilpreet } 10521865Sdilpreet } else { 10531865Sdilpreet switch (size) { 10541865Sdilpreet case sizeof (uint8_t): 10551865Sdilpreet *(uint8_t *)dev_addr = 10561865Sdilpreet *(uint8_t *)host_addr; 10571865Sdilpreet break; 10581865Sdilpreet case sizeof (uint16_t): 10591865Sdilpreet *(uint16_t *)dev_addr = 10601865Sdilpreet *(uint16_t *)host_addr; 10611865Sdilpreet break; 10621865Sdilpreet case sizeof (uint32_t): 10631865Sdilpreet *(uint32_t *)dev_addr = 10641865Sdilpreet *(uint32_t *)host_addr; 10651865Sdilpreet break; 10661865Sdilpreet case sizeof (uint64_t): 10671865Sdilpreet *(uint64_t *)dev_addr = 10681865Sdilpreet *(uint64_t *)host_addr; 10691865Sdilpreet break; 10701865Sdilpreet default: 10711865Sdilpreet err = DDI_FAILURE; 10721865Sdilpreet break; 10731865Sdilpreet } 10741865Sdilpreet } 10751865Sdilpreet } 10761865Sdilpreet host_addr += size; 10771865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 10781865Sdilpreet dev_addr += size; 10791865Sdilpreet } 10801865Sdilpreet return (err); 10811865Sdilpreet } 10821865Sdilpreet 10831865Sdilpreet 10841865Sdilpreet int 10851865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 10861865Sdilpreet { 10871865Sdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 10881865Sdilpreet 10891865Sdilpreet /* endian-ness check */ 10901865Sdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 10911865Sdilpreet return (DDI_FAILURE); 10921865Sdilpreet 10931865Sdilpreet /* 10941865Sdilpreet * range check 10951865Sdilpreet */ 10961865Sdilpreet if ((offset >= PCI_CONF_HDR_SIZE) || 10971865Sdilpreet (len > PCI_CONF_HDR_SIZE) || 10981865Sdilpreet (offset + len > PCI_CONF_HDR_SIZE)) 10991865Sdilpreet return (DDI_FAILURE); 11001865Sdilpreet 11011865Sdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 11021865Sdilpreet /* 11031865Sdilpreet * always use cautious mechanism for config space gets 11041865Sdilpreet */ 11051865Sdilpreet ap->ahi_get8 = i_ddi_caut_get8; 11061865Sdilpreet ap->ahi_get16 = i_ddi_caut_get16; 11071865Sdilpreet ap->ahi_get32 = i_ddi_caut_get32; 11081865Sdilpreet ap->ahi_get64 = i_ddi_caut_get64; 11091865Sdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 11101865Sdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 11111865Sdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 11121865Sdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 11131865Sdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 11141865Sdilpreet ap->ahi_put8 = i_ddi_caut_put8; 11151865Sdilpreet ap->ahi_put16 = i_ddi_caut_put16; 11161865Sdilpreet ap->ahi_put32 = i_ddi_caut_put32; 11171865Sdilpreet ap->ahi_put64 = i_ddi_caut_put64; 11181865Sdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 11191865Sdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 11201865Sdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 11211865Sdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 11221865Sdilpreet } else { 11231865Sdilpreet ap->ahi_put8 = pci_config_wr8; 11241865Sdilpreet ap->ahi_put16 = pci_config_wr16; 11251865Sdilpreet ap->ahi_put32 = pci_config_wr32; 11261865Sdilpreet ap->ahi_put64 = pci_config_wr64; 11271865Sdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8; 11281865Sdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16; 11291865Sdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32; 11301865Sdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64; 11311865Sdilpreet } 11321865Sdilpreet 11331865Sdilpreet /* Initialize to default check/notify functions */ 11341865Sdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check; 11351865Sdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify; 11361865Sdilpreet ap->ahi_fault = 0; 11371865Sdilpreet impl_acc_err_init(hp); 11381865Sdilpreet return (DDI_SUCCESS); 11391865Sdilpreet } 11401865Sdilpreet 11411865Sdilpreet 11421865Sdilpreet int 11431865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 11441865Sdilpreet { 11451865Sdilpreet size_t size = in_args->size; 11461865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 11471865Sdilpreet uintptr_t host_addr = in_args->host_addr; 11481865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 11491865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 11501865Sdilpreet size_t repcount = in_args->repcount; 11511865Sdilpreet uint_t flags = in_args->flags; 11521865Sdilpreet int err = DDI_SUCCESS; 11531865Sdilpreet 11541865Sdilpreet /* 11551865Sdilpreet * if no handle then this is a peek. We have to return failure here 11561865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 11571865Sdilpreet */ 11581865Sdilpreet if (in_args->handle == NULL) 11591865Sdilpreet return (DDI_FAILURE); 11601865Sdilpreet 11611865Sdilpreet for (; repcount; repcount--) { 11621865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 11631865Sdilpreet switch (size) { 11641865Sdilpreet case sizeof (uint8_t): 11651865Sdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp, 11661865Sdilpreet (uint8_t *)dev_addr); 11671865Sdilpreet break; 11681865Sdilpreet case sizeof (uint16_t): 11691865Sdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp, 11701865Sdilpreet (uint16_t *)dev_addr); 11711865Sdilpreet break; 11721865Sdilpreet case sizeof (uint32_t): 11731865Sdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp, 11741865Sdilpreet (uint32_t *)dev_addr); 11751865Sdilpreet break; 11761865Sdilpreet case sizeof (uint64_t): 11771865Sdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp, 11781865Sdilpreet (uint64_t *)dev_addr); 11791865Sdilpreet break; 11801865Sdilpreet default: 11811865Sdilpreet err = DDI_FAILURE; 11821865Sdilpreet break; 11831865Sdilpreet } 11841865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 11851865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 11861865Sdilpreet DDI_STRUCTURE_BE_ACC) { 11871865Sdilpreet switch (size) { 11881865Sdilpreet case sizeof (uint8_t): 11891865Sdilpreet *(uint8_t *)host_addr = 11901865Sdilpreet i_ddi_io_get8(hp, 11911865Sdilpreet (uint8_t *)dev_addr); 11921865Sdilpreet break; 11931865Sdilpreet case sizeof (uint16_t): 11941865Sdilpreet *(uint16_t *)host_addr = 11951865Sdilpreet i_ddi_io_swap_get16(hp, 11961865Sdilpreet (uint16_t *)dev_addr); 11971865Sdilpreet break; 11981865Sdilpreet case sizeof (uint32_t): 11991865Sdilpreet *(uint32_t *)host_addr = 12001865Sdilpreet i_ddi_io_swap_get32(hp, 12011865Sdilpreet (uint32_t *)dev_addr); 12021865Sdilpreet break; 12031865Sdilpreet /* 12041865Sdilpreet * note the 64-bit case is a dummy 12051865Sdilpreet * function - so no need to swap 12061865Sdilpreet */ 12071865Sdilpreet case sizeof (uint64_t): 12081865Sdilpreet *(uint64_t *)host_addr = 12091865Sdilpreet i_ddi_io_get64(hp, 12101865Sdilpreet (uint64_t *)dev_addr); 12111865Sdilpreet break; 12121865Sdilpreet default: 12131865Sdilpreet err = DDI_FAILURE; 12141865Sdilpreet break; 12151865Sdilpreet } 12161865Sdilpreet } else { 12171865Sdilpreet switch (size) { 12181865Sdilpreet case sizeof (uint8_t): 12191865Sdilpreet *(uint8_t *)host_addr = 12201865Sdilpreet i_ddi_io_get8(hp, 12211865Sdilpreet (uint8_t *)dev_addr); 12221865Sdilpreet break; 12231865Sdilpreet case sizeof (uint16_t): 12241865Sdilpreet *(uint16_t *)host_addr = 12251865Sdilpreet i_ddi_io_get16(hp, 12261865Sdilpreet (uint16_t *)dev_addr); 12271865Sdilpreet break; 12281865Sdilpreet case sizeof (uint32_t): 12291865Sdilpreet *(uint32_t *)host_addr = 12301865Sdilpreet i_ddi_io_get32(hp, 12311865Sdilpreet (uint32_t *)dev_addr); 12321865Sdilpreet break; 12331865Sdilpreet case sizeof (uint64_t): 12341865Sdilpreet *(uint64_t *)host_addr = 12351865Sdilpreet i_ddi_io_get64(hp, 12361865Sdilpreet (uint64_t *)dev_addr); 12371865Sdilpreet break; 12381865Sdilpreet default: 12391865Sdilpreet err = DDI_FAILURE; 12401865Sdilpreet break; 12411865Sdilpreet } 12421865Sdilpreet } 12431865Sdilpreet } else { 12441865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 12451865Sdilpreet DDI_STRUCTURE_BE_ACC) { 12461865Sdilpreet switch (in_args->size) { 12471865Sdilpreet case sizeof (uint8_t): 12481865Sdilpreet *(uint8_t *)host_addr = 12491865Sdilpreet *(uint8_t *)dev_addr; 12501865Sdilpreet break; 12511865Sdilpreet case sizeof (uint16_t): 12521865Sdilpreet *(uint16_t *)host_addr = 12531865Sdilpreet ddi_swap16(*(uint16_t *)dev_addr); 12541865Sdilpreet break; 12551865Sdilpreet case sizeof (uint32_t): 12561865Sdilpreet *(uint32_t *)host_addr = 12571865Sdilpreet ddi_swap32(*(uint32_t *)dev_addr); 12581865Sdilpreet break; 12591865Sdilpreet case sizeof (uint64_t): 12601865Sdilpreet *(uint64_t *)host_addr = 12611865Sdilpreet ddi_swap64(*(uint64_t *)dev_addr); 12621865Sdilpreet break; 12631865Sdilpreet default: 12641865Sdilpreet err = DDI_FAILURE; 12651865Sdilpreet break; 12661865Sdilpreet } 12671865Sdilpreet } else { 12681865Sdilpreet switch (in_args->size) { 12691865Sdilpreet case sizeof (uint8_t): 12701865Sdilpreet *(uint8_t *)host_addr = 12711865Sdilpreet *(uint8_t *)dev_addr; 12721865Sdilpreet break; 12731865Sdilpreet case sizeof (uint16_t): 12741865Sdilpreet *(uint16_t *)host_addr = 12751865Sdilpreet *(uint16_t *)dev_addr; 12761865Sdilpreet break; 12771865Sdilpreet case sizeof (uint32_t): 12781865Sdilpreet *(uint32_t *)host_addr = 12791865Sdilpreet *(uint32_t *)dev_addr; 12801865Sdilpreet break; 12811865Sdilpreet case sizeof (uint64_t): 12821865Sdilpreet *(uint64_t *)host_addr = 12831865Sdilpreet *(uint64_t *)dev_addr; 12841865Sdilpreet break; 12851865Sdilpreet default: 12861865Sdilpreet err = DDI_FAILURE; 12871865Sdilpreet break; 12881865Sdilpreet } 12891865Sdilpreet } 12901865Sdilpreet } 12911865Sdilpreet host_addr += size; 12921865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 12931865Sdilpreet dev_addr += size; 12941865Sdilpreet } 12951865Sdilpreet return (err); 12961865Sdilpreet } 12971865Sdilpreet 12981865Sdilpreet /*ARGSUSED*/ 12991865Sdilpreet int 13001865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 13011865Sdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result) 13021865Sdilpreet { 13031865Sdilpreet if (ctlop == DDI_CTLOPS_PEEK) 13041865Sdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 13051865Sdilpreet else 13061865Sdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 13071865Sdilpreet } 13081865Sdilpreet 13091083Sanish /* 13101083Sanish * These are the get and put functions to be shared with drivers. The 13111083Sanish * mutex locking is done inside the functions referenced, rather than 13121083Sanish * here, and is thus shared across PCI child drivers and any other 13131083Sanish * consumers of PCI config space (such as the ACPI subsystem). 13141083Sanish * 13151083Sanish * The configuration space addresses come in as pointers. This is fine on 13161083Sanish * a 32-bit system, where the VM space and configuration space are the same 13171083Sanish * size. It's not such a good idea on a 64-bit system, where memory 13181083Sanish * addresses are twice as large as configuration space addresses. At some 13191083Sanish * point in the call tree we need to take a stand and say "you are 32-bit 13201083Sanish * from this time forth", and this seems like a nice self-contained place. 13211083Sanish */ 13221083Sanish 13231083Sanish uint8_t 13241083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 13251083Sanish { 13261083Sanish pci_acc_cfblk_t *cfp; 13271083Sanish uint8_t rval; 13281083Sanish int reg; 13291083Sanish 13301083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13311083Sanish 13321083Sanish reg = (int)(uintptr_t)addr; 13331083Sanish 13341083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13351083Sanish 13361083Sanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 13371083Sanish reg); 13381083Sanish 13391083Sanish return (rval); 13401083Sanish } 13411083Sanish 13421083Sanish void 13431083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 13441083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 13451083Sanish { 13461083Sanish uint8_t *h, *d; 13471083Sanish 13481083Sanish h = host_addr; 13491083Sanish d = dev_addr; 13501083Sanish 13511083Sanish if (flags == DDI_DEV_AUTOINCR) 13521083Sanish for (; repcount; repcount--) 13531083Sanish *h++ = pci_config_rd8(hdlp, d++); 13541083Sanish else 13551083Sanish for (; repcount; repcount--) 13561083Sanish *h++ = pci_config_rd8(hdlp, d); 13571083Sanish } 13581083Sanish 13591083Sanish uint16_t 13601083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 13611083Sanish { 13621083Sanish pci_acc_cfblk_t *cfp; 13631083Sanish uint16_t rval; 13641083Sanish int reg; 13651083Sanish 13661083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13671083Sanish 13681083Sanish reg = (int)(uintptr_t)addr; 13691083Sanish 13701083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13711083Sanish 13721083Sanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 13731083Sanish reg); 13741083Sanish 13751083Sanish return (rval); 13761083Sanish } 13771083Sanish 13781083Sanish void 13791083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 13801083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 13811083Sanish { 13821083Sanish uint16_t *h, *d; 13831083Sanish 13841083Sanish h = host_addr; 13851083Sanish d = dev_addr; 13861083Sanish 13871083Sanish if (flags == DDI_DEV_AUTOINCR) 13881083Sanish for (; repcount; repcount--) 13891083Sanish *h++ = pci_config_rd16(hdlp, d++); 13901083Sanish else 13911083Sanish for (; repcount; repcount--) 13921083Sanish *h++ = pci_config_rd16(hdlp, d); 13931083Sanish } 13941083Sanish 13951083Sanish uint32_t 13961083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 13971083Sanish { 13981083Sanish pci_acc_cfblk_t *cfp; 13991083Sanish uint32_t rval; 14001083Sanish int reg; 14011083Sanish 14021083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14031083Sanish 14041083Sanish reg = (int)(uintptr_t)addr; 14051083Sanish 14061083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14071083Sanish 14081083Sanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 14091083Sanish cfp->c_funcnum, reg); 14101083Sanish 14111083Sanish return (rval); 14121083Sanish } 14131083Sanish 14141083Sanish void 14151083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 14161083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 14171083Sanish { 14181083Sanish uint32_t *h, *d; 14191083Sanish 14201083Sanish h = host_addr; 14211083Sanish d = dev_addr; 14221083Sanish 14231083Sanish if (flags == DDI_DEV_AUTOINCR) 14241083Sanish for (; repcount; repcount--) 14251083Sanish *h++ = pci_config_rd32(hdlp, d++); 14261083Sanish else 14271083Sanish for (; repcount; repcount--) 14281083Sanish *h++ = pci_config_rd32(hdlp, d); 14291083Sanish } 14301083Sanish 14311083Sanish 14321083Sanish void 14331083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 14341083Sanish { 14351083Sanish pci_acc_cfblk_t *cfp; 14361083Sanish int reg; 14371083Sanish 14381083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14391083Sanish 14401083Sanish reg = (int)(uintptr_t)addr; 14411083Sanish 14421083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14431083Sanish 14441083Sanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 14451083Sanish cfp->c_funcnum, reg, value); 14461083Sanish } 14471083Sanish 14481083Sanish void 14491083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 14501083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 14511083Sanish { 14521083Sanish uint8_t *h, *d; 14531083Sanish 14541083Sanish h = host_addr; 14551083Sanish d = dev_addr; 14561083Sanish 14571083Sanish if (flags == DDI_DEV_AUTOINCR) 14581083Sanish for (; repcount; repcount--) 14591083Sanish pci_config_wr8(hdlp, d++, *h++); 14601083Sanish else 14611083Sanish for (; repcount; repcount--) 14621083Sanish pci_config_wr8(hdlp, d, *h++); 14631083Sanish } 14641083Sanish 14651083Sanish void 14661083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 14671083Sanish { 14681083Sanish pci_acc_cfblk_t *cfp; 14691083Sanish int reg; 14701083Sanish 14711083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14721083Sanish 14731083Sanish reg = (int)(uintptr_t)addr; 14741083Sanish 14751083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14761083Sanish 14771083Sanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 14781083Sanish cfp->c_funcnum, reg, value); 14791083Sanish } 14801083Sanish 14811083Sanish void 14821083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 14831083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 14841083Sanish { 14851083Sanish uint16_t *h, *d; 14861083Sanish 14871083Sanish h = host_addr; 14881083Sanish d = dev_addr; 14891083Sanish 14901083Sanish if (flags == DDI_DEV_AUTOINCR) 14911083Sanish for (; repcount; repcount--) 14921083Sanish pci_config_wr16(hdlp, d++, *h++); 14931083Sanish else 14941083Sanish for (; repcount; repcount--) 14951083Sanish pci_config_wr16(hdlp, d, *h++); 14961083Sanish } 14971083Sanish 14981083Sanish void 14991083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 15001083Sanish { 15011083Sanish pci_acc_cfblk_t *cfp; 15021083Sanish int reg; 15031083Sanish 15041083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 15051083Sanish 15061083Sanish reg = (int)(uintptr_t)addr; 15071083Sanish 15081083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 15091083Sanish 15101083Sanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 15111083Sanish cfp->c_funcnum, reg, value); 15121083Sanish } 15131083Sanish 15141083Sanish void 15151083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 15161083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 15171083Sanish { 15181083Sanish uint32_t *h, *d; 15191083Sanish 15201083Sanish h = host_addr; 15211083Sanish d = dev_addr; 15221083Sanish 15231083Sanish if (flags == DDI_DEV_AUTOINCR) 15241083Sanish for (; repcount; repcount--) 15251083Sanish pci_config_wr32(hdlp, d++, *h++); 15261083Sanish else 15271083Sanish for (; repcount; repcount--) 15281083Sanish pci_config_wr32(hdlp, d, *h++); 15291083Sanish } 15301083Sanish 15311083Sanish uint64_t 15321083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 15331083Sanish { 15341083Sanish uint32_t lw_val; 15351083Sanish uint32_t hi_val; 15361083Sanish uint32_t *dp; 15371083Sanish uint64_t val; 15381083Sanish 15391083Sanish dp = (uint32_t *)addr; 15401083Sanish lw_val = pci_config_rd32(hdlp, dp); 15411083Sanish dp++; 15421083Sanish hi_val = pci_config_rd32(hdlp, dp); 15431083Sanish val = ((uint64_t)hi_val << 32) | lw_val; 15441083Sanish return (val); 15451083Sanish } 15461083Sanish 15471083Sanish void 15481083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 15491083Sanish { 15501083Sanish uint32_t lw_val; 15511083Sanish uint32_t hi_val; 15521083Sanish uint32_t *dp; 15531083Sanish 15541083Sanish dp = (uint32_t *)addr; 15551083Sanish lw_val = (uint32_t)(value & 0xffffffff); 15561083Sanish hi_val = (uint32_t)(value >> 32); 15571083Sanish pci_config_wr32(hdlp, dp, lw_val); 15581083Sanish dp++; 15591083Sanish pci_config_wr32(hdlp, dp, hi_val); 15601083Sanish } 15611083Sanish 15621083Sanish void 15631083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 15641083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 15651083Sanish { 15661083Sanish if (flags == DDI_DEV_AUTOINCR) { 15671083Sanish for (; repcount; repcount--) 15681083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 15691083Sanish } else { 15701083Sanish for (; repcount; repcount--) 15711083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr); 15721083Sanish } 15731083Sanish } 15741083Sanish 15751083Sanish void 15761083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 15771083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 15781083Sanish { 15791083Sanish if (flags == DDI_DEV_AUTOINCR) { 15801083Sanish for (; repcount; repcount--) 15811083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr++); 15821083Sanish } else { 15831083Sanish for (; repcount; repcount--) 15841083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr); 15851083Sanish } 15861083Sanish } 15871083Sanish 15881083Sanish 15891083Sanish /* 15901083Sanish * Enable Legacy PCI config space access for the following four north bridges 15911083Sanish * Host bridge: AMD HyperTransport Technology Configuration 15921083Sanish * Host bridge: AMD Address Map 15931083Sanish * Host bridge: AMD DRAM Controller 15941083Sanish * Host bridge: AMD Miscellaneous Control 15951083Sanish */ 15961083Sanish int 15971083Sanish is_amd_northbridge(dev_info_t *dip) 15981083Sanish { 15991083Sanish int vendor_id, device_id; 16001083Sanish 16011083Sanish vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 16021083Sanish "vendor-id", -1); 16031083Sanish device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 16041083Sanish "device-id", -1); 16051083Sanish 16061083Sanish if (IS_AMD_NTBRIDGE(vendor_id, device_id)) 16071083Sanish return (0); 16081083Sanish 16091083Sanish return (1); 16101083Sanish } 1611