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 /* 231542Sjohnny * Copyright 2006 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> 48916Sschwartz #include <io/pcplusmp/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> 55881Sjohnny 56881Sjohnny /* 57881Sjohnny * Function prototypes 58881Sjohnny */ 59881Sjohnny static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *); 60881Sjohnny static int pci_get_nintrs(dev_info_t *, int, 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 * pci_get_nintrs: 188881Sjohnny * Figure out how many interrupts the device supports 189881Sjohnny */ 190881Sjohnny static int 191881Sjohnny pci_get_nintrs(dev_info_t *dip, int type, int *nintrs) 192881Sjohnny { 193881Sjohnny int ret; 194881Sjohnny 195881Sjohnny *nintrs = 0; 196881Sjohnny 197881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(type)) 198881Sjohnny ret = pci_msi_get_nintrs(dip, type, nintrs); 199881Sjohnny else { 200881Sjohnny ret = DDI_FAILURE; 201881Sjohnny if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 202881Sjohnny "interrupts", -1) != -1) { 203881Sjohnny *nintrs = 1; 204881Sjohnny ret = DDI_SUCCESS; 205881Sjohnny } 206881Sjohnny } 207881Sjohnny 208881Sjohnny return (ret); 209881Sjohnny } 210881Sjohnny 211881Sjohnny static int pcie_pci_intr_pri_counter = 0; 212881Sjohnny 213881Sjohnny /* 214881Sjohnny * pci_common_intr_ops: bus_intr_op() function for interrupt support 215881Sjohnny */ 216881Sjohnny int 217881Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 218881Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 219881Sjohnny { 220881Sjohnny int priority = 0; 221881Sjohnny int psm_status = 0; 222881Sjohnny int pci_status = 0; 223881Sjohnny int pci_rval, psm_rval = PSM_FAILURE; 224881Sjohnny int types = 0; 225881Sjohnny int pciepci = 0; 2261542Sjohnny int i, j, count; 227881Sjohnny int behavior; 228*1997Sanish int cap_ptr; 229881Sjohnny ddi_intrspec_t isp; 230881Sjohnny struct intrspec *ispec; 231881Sjohnny ddi_intr_handle_impl_t tmp_hdl; 232881Sjohnny ddi_intr_msix_t *msix_p; 2331087Sschwartz ihdl_plat_t *ihdl_plat_datap; 2341542Sjohnny ddi_intr_handle_t *h_array; 235*1997Sanish ddi_acc_handle_t handle; 236881Sjohnny 237881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 238881Sjohnny "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 239881Sjohnny (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 240881Sjohnny 241881Sjohnny /* Process the request */ 242881Sjohnny switch (intr_op) { 243881Sjohnny case DDI_INTROP_SUPPORTED_TYPES: 244881Sjohnny /* Fixed supported by default */ 245881Sjohnny *(int *)result = DDI_INTR_TYPE_FIXED; 246881Sjohnny 247881Sjohnny /* Figure out if MSI or MSI-X is supported? */ 248881Sjohnny if (pci_msi_get_supported_type(rdip, &types) != DDI_SUCCESS) 249881Sjohnny return (DDI_SUCCESS); 250881Sjohnny 251881Sjohnny if (psm_intr_ops != NULL) { 2521725Segillett /* 2531725Segillett * Only support MSI for now, OR it in 2541725Segillett */ 2551725Segillett *(int *)result |= (types & DDI_INTR_TYPE_MSI); 256881Sjohnny 257881Sjohnny tmp_hdl.ih_type = *(int *)result; 258881Sjohnny (void) (*psm_intr_ops)(rdip, &tmp_hdl, 259881Sjohnny PSM_INTR_OP_CHECK_MSI, result); 260881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 261881Sjohnny "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, 262881Sjohnny *(int *)result)); 263881Sjohnny } 264881Sjohnny break; 265881Sjohnny case DDI_INTROP_NINTRS: 266881Sjohnny if (pci_get_nintrs(rdip, hdlp->ih_type, result) != DDI_SUCCESS) 267881Sjohnny return (DDI_FAILURE); 268881Sjohnny break; 269881Sjohnny case DDI_INTROP_ALLOC: 270881Sjohnny /* 271881Sjohnny * MSI or MSIX (figure out number of vectors available) 272881Sjohnny * FIXED interrupts: just return available interrupts 273881Sjohnny */ 274881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 275881Sjohnny (psm_intr_ops != NULL) && 276881Sjohnny (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) { 277881Sjohnny /* 278881Sjohnny * Following check is a special case for 'pcie_pci'. 279881Sjohnny * This makes sure vectors with the right priority 280881Sjohnny * are allocated for pcie_pci during ALLOC time. 281881Sjohnny */ 282881Sjohnny if (strcmp(ddi_driver_name(rdip), "pcie_pci") == 0) { 283881Sjohnny hdlp->ih_pri = 284881Sjohnny (pcie_pci_intr_pri_counter % 2) ? 4 : 7; 285881Sjohnny pciepci = 1; 286881Sjohnny } else 287881Sjohnny hdlp->ih_pri = priority; 2881717Swesolows behavior = (int)(uintptr_t)hdlp->ih_scratch2; 289*1997Sanish 290*1997Sanish /* 291*1997Sanish * Cache in the config handle and cap_ptr 292*1997Sanish */ 293*1997Sanish if (i_ddi_get_pci_config_handle(rdip) == NULL) { 294*1997Sanish if (pci_config_setup(rdip, &handle) != 295*1997Sanish DDI_SUCCESS) 296*1997Sanish return (DDI_FAILURE); 297*1997Sanish i_ddi_set_pci_config_handle(rdip, handle); 298*1997Sanish } 299*1997Sanish 300*1997Sanish if (i_ddi_get_msi_msix_cap_ptr(rdip) == 0) { 301*1997Sanish char *prop = 302*1997Sanish (hdlp->ih_type == DDI_INTR_TYPE_MSI) ? 303*1997Sanish "pci-msi-capid-pointer" : 304*1997Sanish "pci-msix-capid-pointer"; 305*1997Sanish 306*1997Sanish cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 307*1997Sanish DDI_PROP_DONTPASS, prop, 308*1997Sanish PCI_CAP_NEXT_PTR_NULL); 309*1997Sanish i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); 310*1997Sanish } 311*1997Sanish 312*1997Sanish 313881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 314881Sjohnny PSM_INTR_OP_ALLOC_VECTORS, result); 315881Sjohnny 316881Sjohnny /* verify behavior flag and take appropriate action */ 317881Sjohnny if ((behavior == DDI_INTR_ALLOC_STRICT) && 318881Sjohnny (*(int *)result < hdlp->ih_scratch1)) { 319881Sjohnny DDI_INTR_NEXDBG((CE_CONT, 320881Sjohnny "pci_common_intr_ops: behavior %x, " 321881Sjohnny "couldn't get enough intrs\n", behavior)); 322881Sjohnny hdlp->ih_scratch1 = *(int *)result; 323881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 324881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 325881Sjohnny return (DDI_EAGAIN); 326881Sjohnny } 327881Sjohnny 328881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 329881Sjohnny if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 330881Sjohnny msix_p = pci_msix_init(hdlp->ih_dip); 331881Sjohnny if (msix_p) 332881Sjohnny i_ddi_set_msix(hdlp->ih_dip, 333881Sjohnny msix_p); 334881Sjohnny } 335881Sjohnny } 336881Sjohnny 337881Sjohnny if (pciepci) { 338881Sjohnny /* update priority in ispec */ 339881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, 340881Sjohnny (int)hdlp->ih_inum); 341881Sjohnny ispec = (struct intrspec *)isp; 342881Sjohnny if (ispec) 343881Sjohnny ispec->intrspec_pri = hdlp->ih_pri; 344881Sjohnny ++pcie_pci_intr_pri_counter; 345881Sjohnny } 346881Sjohnny 347881Sjohnny } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 348881Sjohnny /* Figure out if this device supports MASKING */ 349881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 350881Sjohnny if (pci_rval == DDI_SUCCESS && pci_status) 351881Sjohnny hdlp->ih_cap |= pci_status; 352881Sjohnny *(int *)result = 1; /* DDI_INTR_TYPE_FIXED */ 353881Sjohnny } else 354881Sjohnny return (DDI_FAILURE); 355881Sjohnny break; 356881Sjohnny case DDI_INTROP_FREE: 357881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 358881Sjohnny (psm_intr_ops != NULL)) { 359*1997Sanish if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) == 0) { 360*1997Sanish if (handle = i_ddi_get_pci_config_handle( 361*1997Sanish rdip)) { 362*1997Sanish (void) pci_config_teardown(&handle); 363*1997Sanish i_ddi_set_pci_config_handle(rdip, NULL); 364*1997Sanish } 365*1997Sanish if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip)) 366*1997Sanish i_ddi_set_msi_msix_cap_ptr(rdip, 0); 367*1997Sanish } 368*1997Sanish 369881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 370881Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 371881Sjohnny 372881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 373881Sjohnny msix_p = i_ddi_get_msix(hdlp->ih_dip); 374881Sjohnny if (msix_p && 3751725Segillett i_ddi_intr_get_current_nintrs(hdlp->ih_dip) 3761725Segillett == 0) { 377881Sjohnny pci_msix_fini(msix_p); 378881Sjohnny i_ddi_set_msix(hdlp->ih_dip, NULL); 379881Sjohnny } 380881Sjohnny } 381881Sjohnny } 382881Sjohnny break; 383881Sjohnny case DDI_INTROP_GETPRI: 384881Sjohnny /* Get the priority */ 385881Sjohnny if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS) 386881Sjohnny return (DDI_FAILURE); 387881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 388881Sjohnny "priority = 0x%x\n", priority)); 389881Sjohnny *(int *)result = priority; 390881Sjohnny break; 391881Sjohnny case DDI_INTROP_SETPRI: 392881Sjohnny /* Validate the interrupt priority passed */ 393881Sjohnny if (*(int *)result > LOCK_LEVEL) 394881Sjohnny return (DDI_FAILURE); 395881Sjohnny 396881Sjohnny /* Ensure that PSM is all initialized */ 397881Sjohnny if (psm_intr_ops == NULL) 398881Sjohnny return (DDI_FAILURE); 399881Sjohnny 400881Sjohnny /* Change the priority */ 401881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 402881Sjohnny PSM_FAILURE) 403881Sjohnny return (DDI_FAILURE); 404881Sjohnny 405881Sjohnny /* update ispec */ 406881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 407881Sjohnny ispec = (struct intrspec *)isp; 408881Sjohnny if (ispec) 409881Sjohnny ispec->intrspec_pri = *(int *)result; 410881Sjohnny break; 411881Sjohnny case DDI_INTROP_ADDISR: 412881Sjohnny /* update ispec */ 413881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 414881Sjohnny ispec = (struct intrspec *)isp; 4151087Sschwartz if (ispec) { 416881Sjohnny ispec->intrspec_func = hdlp->ih_cb_func; 4171087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 4181087Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 4191087Sschwartz } 420881Sjohnny break; 421881Sjohnny case DDI_INTROP_REMISR: 422881Sjohnny /* Get the interrupt structure pointer */ 423881Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 424881Sjohnny ispec = (struct intrspec *)isp; 4251087Sschwartz if (ispec) { 426881Sjohnny ispec->intrspec_func = (uint_t (*)()) 0; 4271087Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 4281087Sschwartz if (ihdl_plat_datap->ip_ksp != NULL) 4291087Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp); 4301087Sschwartz } 431881Sjohnny break; 432881Sjohnny case DDI_INTROP_GETCAP: 433881Sjohnny /* 434881Sjohnny * First check the config space and/or 435881Sjohnny * MSI capability register(s) 436881Sjohnny */ 437881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 438881Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 439881Sjohnny &pci_status); 440881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 441881Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 442881Sjohnny 443881Sjohnny /* next check with pcplusmp */ 444881Sjohnny if (psm_intr_ops != NULL) 445881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 446881Sjohnny PSM_INTR_OP_GET_CAP, &psm_status); 447881Sjohnny 448881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 449881Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n", 450881Sjohnny psm_rval, psm_status, pci_rval, pci_status)); 451881Sjohnny 452881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 453881Sjohnny *(int *)result = 0; 454881Sjohnny return (DDI_FAILURE); 455881Sjohnny } 456881Sjohnny 457881Sjohnny if (psm_rval == PSM_SUCCESS) 458881Sjohnny *(int *)result = psm_status; 459881Sjohnny 460881Sjohnny if (pci_rval == DDI_SUCCESS) 461881Sjohnny *(int *)result |= pci_status; 462881Sjohnny 463881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 464881Sjohnny *(int *)result)); 465881Sjohnny break; 466881Sjohnny case DDI_INTROP_SETCAP: 467881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 468881Sjohnny "SETCAP cap=0x%x\n", *(int *)result)); 469881Sjohnny if (psm_intr_ops == NULL) 470881Sjohnny return (DDI_FAILURE); 471881Sjohnny 472881Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 473881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 474881Sjohnny " returned failure\n")); 475881Sjohnny return (DDI_FAILURE); 476881Sjohnny } 477881Sjohnny break; 478881Sjohnny case DDI_INTROP_ENABLE: 479881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 480881Sjohnny if (psm_intr_ops == NULL) 481881Sjohnny return (DDI_FAILURE); 482881Sjohnny 483881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 484881Sjohnny DDI_SUCCESS) 485881Sjohnny return (DDI_FAILURE); 486881Sjohnny 487881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 488881Sjohnny "vector=0x%x\n", hdlp->ih_vector)); 489881Sjohnny break; 490881Sjohnny case DDI_INTROP_DISABLE: 491881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 492881Sjohnny if (psm_intr_ops == NULL) 493881Sjohnny return (DDI_FAILURE); 494881Sjohnny 495881Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 496881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 497881Sjohnny "vector = %x\n", hdlp->ih_vector)); 498881Sjohnny break; 499881Sjohnny case DDI_INTROP_BLOCKENABLE: 500881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 501881Sjohnny "BLOCKENABLE\n")); 502881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 503881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 504881Sjohnny return (DDI_FAILURE); 505881Sjohnny } 506881Sjohnny 507881Sjohnny /* Check if psm_intr_ops is NULL? */ 508881Sjohnny if (psm_intr_ops == NULL) 509881Sjohnny return (DDI_FAILURE); 510881Sjohnny 5111542Sjohnny count = hdlp->ih_scratch1; 5121542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 5131542Sjohnny for (i = 0; i < count; i++) { 5141542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 515881Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, 5161542Sjohnny hdlp->ih_inum) != DDI_SUCCESS) { 517881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 518881Sjohnny "pci_enable_intr failed for %d\n", i)); 5191542Sjohnny for (j = 0; j < i; j++) { 5201542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[j]; 5211542Sjohnny pci_disable_intr(pdip, rdip, hdlp, 5221542Sjohnny hdlp->ih_inum); 5231542Sjohnny } 524881Sjohnny return (DDI_FAILURE); 525881Sjohnny } 526881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 5271542Sjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 528881Sjohnny } 529881Sjohnny break; 530881Sjohnny case DDI_INTROP_BLOCKDISABLE: 531881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 532881Sjohnny "BLOCKDISABLE\n")); 533881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 534881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 535881Sjohnny return (DDI_FAILURE); 536881Sjohnny } 537881Sjohnny 538881Sjohnny /* Check if psm_intr_ops is present */ 539881Sjohnny if (psm_intr_ops == NULL) 540881Sjohnny return (DDI_FAILURE); 541881Sjohnny 5421542Sjohnny count = hdlp->ih_scratch1; 5431542Sjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 5441542Sjohnny for (i = 0; i < count; i++) { 5451542Sjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 5461542Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 547881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 5481542Sjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 549881Sjohnny } 550881Sjohnny break; 551881Sjohnny case DDI_INTROP_SETMASK: 552881Sjohnny case DDI_INTROP_CLRMASK: 553881Sjohnny /* 554881Sjohnny * First handle in the config space 555881Sjohnny */ 556881Sjohnny if (intr_op == DDI_INTROP_SETMASK) { 557881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 558881Sjohnny pci_status = pci_msi_set_mask(rdip, 559881Sjohnny hdlp->ih_type, hdlp->ih_inum); 560881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 561881Sjohnny pci_status = pci_intx_set_mask(rdip); 562881Sjohnny } else { 563881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 564881Sjohnny pci_status = pci_msi_clr_mask(rdip, 565881Sjohnny hdlp->ih_type, hdlp->ih_inum); 566881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 567881Sjohnny pci_status = pci_intx_clr_mask(rdip); 568881Sjohnny } 569881Sjohnny 570881Sjohnny /* For MSI/X; no need to check with pcplusmp */ 571881Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 572881Sjohnny return (pci_status); 573881Sjohnny 574881Sjohnny /* For fixed interrupts only: handle config space first */ 575881Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 576881Sjohnny pci_status == DDI_SUCCESS) 577881Sjohnny break; 578881Sjohnny 579881Sjohnny /* For fixed interrupts only: confer with pcplusmp next */ 580881Sjohnny if (psm_intr_ops != NULL) { 581881Sjohnny /* If interrupt is shared; do nothing */ 582881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 583881Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status); 584881Sjohnny 585881Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1) 586881Sjohnny return (pci_status); 587881Sjohnny 588881Sjohnny /* Now, pcplusmp should try to set/clear the mask */ 589881Sjohnny if (intr_op == DDI_INTROP_SETMASK) 590881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 591881Sjohnny PSM_INTR_OP_SET_MASK, NULL); 592881Sjohnny else 593881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 594881Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL); 595881Sjohnny } 596881Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 597881Sjohnny case DDI_INTROP_GETPENDING: 598881Sjohnny /* 599881Sjohnny * First check the config space and/or 600881Sjohnny * MSI capability register(s) 601881Sjohnny */ 602881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 603881Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 604881Sjohnny hdlp->ih_inum, &pci_status); 605881Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 606881Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status); 607881Sjohnny 608881Sjohnny /* On failure; next try with pcplusmp */ 609881Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 610881Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 611881Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status); 612881Sjohnny 613881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 614881Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, " 615881Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval, 616881Sjohnny pci_status)); 617881Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 618881Sjohnny *(int *)result = 0; 619881Sjohnny return (DDI_FAILURE); 620881Sjohnny } 621881Sjohnny 622881Sjohnny if (psm_rval != PSM_FAILURE) 623881Sjohnny *(int *)result = psm_status; 624881Sjohnny else if (pci_rval != DDI_FAILURE) 625881Sjohnny *(int *)result = pci_status; 626881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 627881Sjohnny *(int *)result)); 628881Sjohnny break; 629881Sjohnny case DDI_INTROP_NAVAIL: 630881Sjohnny if ((psm_intr_ops != NULL) && (pci_get_priority(rdip, 631881Sjohnny hdlp, &priority) == DDI_SUCCESS)) { 632881Sjohnny /* Priority in the handle not initialized yet */ 633881Sjohnny hdlp->ih_pri = priority; 634881Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 635881Sjohnny PSM_INTR_OP_NAVAIL_VECTORS, result); 636881Sjohnny } else { 637881Sjohnny *(int *)result = 1; 638881Sjohnny } 639881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: NAVAIL returned = %x\n", 640881Sjohnny *(int *)result)); 641881Sjohnny break; 642881Sjohnny default: 643881Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 644881Sjohnny } 645881Sjohnny 646881Sjohnny return (DDI_SUCCESS); 647881Sjohnny } 648881Sjohnny 649916Sschwartz int 650916Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 651916Sschwartz int vecirq, boolean_t is_irq) 652916Sschwartz { 653916Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl; 654916Sschwartz 655916Sschwartz if (is_irq) 656916Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 657916Sschwartz 658916Sschwartz /* 659916Sschwartz * For this locally-declared and used handle, ih_private will contain a 660916Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 661916Sschwartz * global interrupt handling. 662916Sschwartz */ 663916Sschwartz get_info_ii_hdl.ih_private = intrinfo_p; 664916Sschwartz get_info_ii_hdl.ih_vector = (ushort_t)vecirq; 665916Sschwartz 666916Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 667916Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 668916Sschwartz return (DDI_FAILURE); 669916Sschwartz 670916Sschwartz return (DDI_SUCCESS); 671916Sschwartz } 672916Sschwartz 673916Sschwartz 674916Sschwartz int 675916Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 676916Sschwartz { 677916Sschwartz int rval; 678916Sschwartz 679916Sschwartz apic_get_intr_t intrinfo; 680916Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 681916Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 682916Sschwartz 683916Sschwartz if (rval == DDI_SUCCESS) 684916Sschwartz return (intrinfo.avgi_cpu_id); 685916Sschwartz else 686916Sschwartz return (-1); 687916Sschwartz } 688916Sschwartz 689881Sjohnny 690881Sjohnny static int 691881Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 692881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 693881Sjohnny { 694881Sjohnny struct intrspec *ispec; 695916Sschwartz int irq; 696916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 697881Sjohnny 698881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 699881Sjohnny (void *)hdlp, inum)); 700881Sjohnny 701881Sjohnny /* Translate the interrupt if needed */ 702881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 703881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && ispec) 704881Sjohnny ispec->intrspec_vec = inum; 705916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 706881Sjohnny 707881Sjohnny /* translate the interrupt if needed */ 708916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 709916Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 710916Sschwartz hdlp->ih_pri, irq)); 711881Sjohnny 712881Sjohnny /* Add the interrupt handler */ 713881Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 714916Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 715916Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 716881Sjohnny return (DDI_FAILURE); 717881Sjohnny 718916Sschwartz /* Note this really is an irq. */ 719916Sschwartz hdlp->ih_vector = (ushort_t)irq; 720916Sschwartz 721881Sjohnny return (DDI_SUCCESS); 722881Sjohnny } 723881Sjohnny 724881Sjohnny 725881Sjohnny static void 726881Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 727881Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 728881Sjohnny { 729916Sschwartz int irq; 730881Sjohnny struct intrspec *ispec; 731916Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 732881Sjohnny 733881Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 734881Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 735881Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && ispec) 736881Sjohnny ispec->intrspec_vec = inum; 737916Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 738881Sjohnny 739881Sjohnny /* translate the interrupt if needed */ 740916Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 741881Sjohnny 742881Sjohnny /* Disable the interrupt handler */ 743916Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 744916Sschwartz ihdl_plat_datap->ip_ispecp = NULL; 745881Sjohnny } 746881Sjohnny 747881Sjohnny /* 748881Sjohnny * Miscellaneous library function 749881Sjohnny */ 750881Sjohnny int 751881Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 752881Sjohnny { 753881Sjohnny int i; 754881Sjohnny int number; 755881Sjohnny int assigned_addr_len; 756881Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi; 757881Sjohnny pci_regspec_t *assigned_addr; 758881Sjohnny 759881Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 760881Sjohnny (phys_hi & PCI_RELOCAT_B)) 761881Sjohnny return (DDI_SUCCESS); 762881Sjohnny 763881Sjohnny /* 764881Sjohnny * the "reg" property specifies relocatable, get and interpret the 765881Sjohnny * "assigned-addresses" property. 766881Sjohnny */ 767881Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 768881Sjohnny "assigned-addresses", (int **)&assigned_addr, 769881Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 770881Sjohnny return (DDI_FAILURE); 771881Sjohnny 772881Sjohnny /* 773881Sjohnny * Scan the "assigned-addresses" for one that matches the specified 774881Sjohnny * "reg" property entry. 775881Sjohnny */ 776881Sjohnny phys_hi &= PCI_CONF_ADDR_MASK; 777881Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 778881Sjohnny for (i = 0; i < number; i++) { 779881Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 780881Sjohnny phys_hi) { 781881Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 782881Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 783881Sjohnny ddi_prop_free(assigned_addr); 784881Sjohnny return (DDI_SUCCESS); 785881Sjohnny } 786881Sjohnny } 787881Sjohnny 788881Sjohnny ddi_prop_free(assigned_addr); 789881Sjohnny return (DDI_FAILURE); 790881Sjohnny } 791881Sjohnny 792881Sjohnny 793881Sjohnny /* 794881Sjohnny * For pci_tools 795881Sjohnny */ 796881Sjohnny 797881Sjohnny int 798881Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 799881Sjohnny int mode, cred_t *credp, int *rvalp) 800881Sjohnny { 801881Sjohnny int rv = ENOTTY; 802881Sjohnny 803881Sjohnny minor_t minor = getminor(dev); 804881Sjohnny 805881Sjohnny switch (PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 806881Sjohnny case PCI_TOOL_REG_MINOR_NUM: 807881Sjohnny 808881Sjohnny switch (cmd) { 809881Sjohnny case PCITOOL_DEVICE_SET_REG: 810881Sjohnny case PCITOOL_DEVICE_GET_REG: 811881Sjohnny 812881Sjohnny /* Require full privileges. */ 813881Sjohnny if (secpolicy_kmdb(credp)) 814881Sjohnny rv = EPERM; 815881Sjohnny else 816881Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg, 817881Sjohnny cmd, mode); 818881Sjohnny break; 819881Sjohnny 820881Sjohnny case PCITOOL_NEXUS_SET_REG: 821881Sjohnny case PCITOOL_NEXUS_GET_REG: 822881Sjohnny 823881Sjohnny /* Require full privileges. */ 824881Sjohnny if (secpolicy_kmdb(credp)) 825881Sjohnny rv = EPERM; 826881Sjohnny else 827881Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg, 828881Sjohnny cmd, mode); 829881Sjohnny break; 830881Sjohnny } 831881Sjohnny break; 832881Sjohnny 833881Sjohnny case PCI_TOOL_INTR_MINOR_NUM: 834881Sjohnny 835881Sjohnny switch (cmd) { 836881Sjohnny case PCITOOL_DEVICE_SET_INTR: 837881Sjohnny 838881Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 839881Sjohnny if (secpolicy_ponline(credp)) { 840881Sjohnny rv = EPERM; 841881Sjohnny break; 842881Sjohnny } 843881Sjohnny 844881Sjohnny /*FALLTHRU*/ 845881Sjohnny /* These require no special privileges. */ 846881Sjohnny case PCITOOL_DEVICE_GET_INTR: 847881Sjohnny case PCITOOL_DEVICE_NUM_INTR: 848881Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 849881Sjohnny break; 850881Sjohnny } 851881Sjohnny break; 852881Sjohnny 853881Sjohnny /* 854881Sjohnny * All non-PCItool ioctls go through here, including: 855881Sjohnny * devctl ioctls with minor number PCIHP_DEVCTL_MINOR and 856881Sjohnny * those for attachment points with where minor number is the 857881Sjohnny * device number. 858881Sjohnny */ 859881Sjohnny default: 860881Sjohnny rv = (pcihp_get_cb_ops())->cb_ioctl(dev, cmd, arg, mode, 861881Sjohnny credp, rvalp); 862881Sjohnny break; 863881Sjohnny } 864881Sjohnny 865881Sjohnny return (rv); 866881Sjohnny } 8671083Sanish 8681083Sanish 8691865Sdilpreet int 8701865Sdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 8711865Sdilpreet { 8721865Sdilpreet size_t size = in_args->size; 8731865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 8741865Sdilpreet uintptr_t host_addr = in_args->host_addr; 8751865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 8761865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 8771865Sdilpreet size_t repcount = in_args->repcount; 8781865Sdilpreet uint_t flags = in_args->flags; 8791865Sdilpreet int err = DDI_SUCCESS; 8801865Sdilpreet 8811865Sdilpreet /* 8821865Sdilpreet * if no handle then this is a poke. We have to return failure here 8831865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 8841865Sdilpreet */ 8851865Sdilpreet if (in_args->handle == NULL) 8861865Sdilpreet return (DDI_FAILURE); 8871865Sdilpreet 8881865Sdilpreet /* 8891865Sdilpreet * rest of this function is actually for cautious puts 8901865Sdilpreet */ 8911865Sdilpreet for (; repcount; repcount--) { 8921865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 8931865Sdilpreet switch (size) { 8941865Sdilpreet case sizeof (uint8_t): 8951865Sdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr, 8961865Sdilpreet *(uint8_t *)host_addr); 8971865Sdilpreet break; 8981865Sdilpreet case sizeof (uint16_t): 8991865Sdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr, 9001865Sdilpreet *(uint16_t *)host_addr); 9011865Sdilpreet break; 9021865Sdilpreet case sizeof (uint32_t): 9031865Sdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr, 9041865Sdilpreet *(uint32_t *)host_addr); 9051865Sdilpreet break; 9061865Sdilpreet case sizeof (uint64_t): 9071865Sdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr, 9081865Sdilpreet *(uint64_t *)host_addr); 9091865Sdilpreet break; 9101865Sdilpreet default: 9111865Sdilpreet err = DDI_FAILURE; 9121865Sdilpreet break; 9131865Sdilpreet } 9141865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 9151865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 9161865Sdilpreet DDI_STRUCTURE_BE_ACC) { 9171865Sdilpreet switch (size) { 9181865Sdilpreet case sizeof (uint8_t): 9191865Sdilpreet i_ddi_io_put8(hp, 9201865Sdilpreet (uint8_t *)dev_addr, 9211865Sdilpreet *(uint8_t *)host_addr); 9221865Sdilpreet break; 9231865Sdilpreet case sizeof (uint16_t): 9241865Sdilpreet i_ddi_io_swap_put16(hp, 9251865Sdilpreet (uint16_t *)dev_addr, 9261865Sdilpreet *(uint16_t *)host_addr); 9271865Sdilpreet break; 9281865Sdilpreet case sizeof (uint32_t): 9291865Sdilpreet i_ddi_io_swap_put32(hp, 9301865Sdilpreet (uint32_t *)dev_addr, 9311865Sdilpreet *(uint32_t *)host_addr); 9321865Sdilpreet break; 9331865Sdilpreet /* 9341865Sdilpreet * note the 64-bit case is a dummy 9351865Sdilpreet * function - so no need to swap 9361865Sdilpreet */ 9371865Sdilpreet case sizeof (uint64_t): 9381865Sdilpreet i_ddi_io_put64(hp, 9391865Sdilpreet (uint64_t *)dev_addr, 9401865Sdilpreet *(uint64_t *)host_addr); 9411865Sdilpreet break; 9421865Sdilpreet default: 9431865Sdilpreet err = DDI_FAILURE; 9441865Sdilpreet break; 9451865Sdilpreet } 9461865Sdilpreet } else { 9471865Sdilpreet switch (size) { 9481865Sdilpreet case sizeof (uint8_t): 9491865Sdilpreet i_ddi_io_put8(hp, 9501865Sdilpreet (uint8_t *)dev_addr, 9511865Sdilpreet *(uint8_t *)host_addr); 9521865Sdilpreet break; 9531865Sdilpreet case sizeof (uint16_t): 9541865Sdilpreet i_ddi_io_put16(hp, 9551865Sdilpreet (uint16_t *)dev_addr, 9561865Sdilpreet *(uint16_t *)host_addr); 9571865Sdilpreet break; 9581865Sdilpreet case sizeof (uint32_t): 9591865Sdilpreet i_ddi_io_put32(hp, 9601865Sdilpreet (uint32_t *)dev_addr, 9611865Sdilpreet *(uint32_t *)host_addr); 9621865Sdilpreet break; 9631865Sdilpreet case sizeof (uint64_t): 9641865Sdilpreet i_ddi_io_put64(hp, 9651865Sdilpreet (uint64_t *)dev_addr, 9661865Sdilpreet *(uint64_t *)host_addr); 9671865Sdilpreet break; 9681865Sdilpreet default: 9691865Sdilpreet err = DDI_FAILURE; 9701865Sdilpreet break; 9711865Sdilpreet } 9721865Sdilpreet } 9731865Sdilpreet } else { 9741865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 9751865Sdilpreet DDI_STRUCTURE_BE_ACC) { 9761865Sdilpreet switch (size) { 9771865Sdilpreet case sizeof (uint8_t): 9781865Sdilpreet *(uint8_t *)dev_addr = 9791865Sdilpreet *(uint8_t *)host_addr; 9801865Sdilpreet break; 9811865Sdilpreet case sizeof (uint16_t): 9821865Sdilpreet *(uint16_t *)dev_addr = 9831865Sdilpreet ddi_swap16(*(uint16_t *)host_addr); 9841865Sdilpreet break; 9851865Sdilpreet case sizeof (uint32_t): 9861865Sdilpreet *(uint32_t *)dev_addr = 9871865Sdilpreet ddi_swap32(*(uint32_t *)host_addr); 9881865Sdilpreet break; 9891865Sdilpreet case sizeof (uint64_t): 9901865Sdilpreet *(uint64_t *)dev_addr = 9911865Sdilpreet ddi_swap64(*(uint64_t *)host_addr); 9921865Sdilpreet break; 9931865Sdilpreet default: 9941865Sdilpreet err = DDI_FAILURE; 9951865Sdilpreet break; 9961865Sdilpreet } 9971865Sdilpreet } else { 9981865Sdilpreet switch (size) { 9991865Sdilpreet case sizeof (uint8_t): 10001865Sdilpreet *(uint8_t *)dev_addr = 10011865Sdilpreet *(uint8_t *)host_addr; 10021865Sdilpreet break; 10031865Sdilpreet case sizeof (uint16_t): 10041865Sdilpreet *(uint16_t *)dev_addr = 10051865Sdilpreet *(uint16_t *)host_addr; 10061865Sdilpreet break; 10071865Sdilpreet case sizeof (uint32_t): 10081865Sdilpreet *(uint32_t *)dev_addr = 10091865Sdilpreet *(uint32_t *)host_addr; 10101865Sdilpreet break; 10111865Sdilpreet case sizeof (uint64_t): 10121865Sdilpreet *(uint64_t *)dev_addr = 10131865Sdilpreet *(uint64_t *)host_addr; 10141865Sdilpreet break; 10151865Sdilpreet default: 10161865Sdilpreet err = DDI_FAILURE; 10171865Sdilpreet break; 10181865Sdilpreet } 10191865Sdilpreet } 10201865Sdilpreet } 10211865Sdilpreet host_addr += size; 10221865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 10231865Sdilpreet dev_addr += size; 10241865Sdilpreet } 10251865Sdilpreet return (err); 10261865Sdilpreet } 10271865Sdilpreet 10281865Sdilpreet 10291865Sdilpreet int 10301865Sdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 10311865Sdilpreet { 10321865Sdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 10331865Sdilpreet 10341865Sdilpreet /* endian-ness check */ 10351865Sdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 10361865Sdilpreet return (DDI_FAILURE); 10371865Sdilpreet 10381865Sdilpreet /* 10391865Sdilpreet * range check 10401865Sdilpreet */ 10411865Sdilpreet if ((offset >= PCI_CONF_HDR_SIZE) || 10421865Sdilpreet (len > PCI_CONF_HDR_SIZE) || 10431865Sdilpreet (offset + len > PCI_CONF_HDR_SIZE)) 10441865Sdilpreet return (DDI_FAILURE); 10451865Sdilpreet 10461865Sdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 10471865Sdilpreet /* 10481865Sdilpreet * always use cautious mechanism for config space gets 10491865Sdilpreet */ 10501865Sdilpreet ap->ahi_get8 = i_ddi_caut_get8; 10511865Sdilpreet ap->ahi_get16 = i_ddi_caut_get16; 10521865Sdilpreet ap->ahi_get32 = i_ddi_caut_get32; 10531865Sdilpreet ap->ahi_get64 = i_ddi_caut_get64; 10541865Sdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 10551865Sdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 10561865Sdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 10571865Sdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 10581865Sdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 10591865Sdilpreet ap->ahi_put8 = i_ddi_caut_put8; 10601865Sdilpreet ap->ahi_put16 = i_ddi_caut_put16; 10611865Sdilpreet ap->ahi_put32 = i_ddi_caut_put32; 10621865Sdilpreet ap->ahi_put64 = i_ddi_caut_put64; 10631865Sdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 10641865Sdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 10651865Sdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 10661865Sdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 10671865Sdilpreet } else { 10681865Sdilpreet ap->ahi_put8 = pci_config_wr8; 10691865Sdilpreet ap->ahi_put16 = pci_config_wr16; 10701865Sdilpreet ap->ahi_put32 = pci_config_wr32; 10711865Sdilpreet ap->ahi_put64 = pci_config_wr64; 10721865Sdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8; 10731865Sdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16; 10741865Sdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32; 10751865Sdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64; 10761865Sdilpreet } 10771865Sdilpreet 10781865Sdilpreet /* Initialize to default check/notify functions */ 10791865Sdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check; 10801865Sdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify; 10811865Sdilpreet ap->ahi_fault = 0; 10821865Sdilpreet impl_acc_err_init(hp); 10831865Sdilpreet return (DDI_SUCCESS); 10841865Sdilpreet } 10851865Sdilpreet 10861865Sdilpreet 10871865Sdilpreet int 10881865Sdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 10891865Sdilpreet { 10901865Sdilpreet size_t size = in_args->size; 10911865Sdilpreet uintptr_t dev_addr = in_args->dev_addr; 10921865Sdilpreet uintptr_t host_addr = in_args->host_addr; 10931865Sdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 10941865Sdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 10951865Sdilpreet size_t repcount = in_args->repcount; 10961865Sdilpreet uint_t flags = in_args->flags; 10971865Sdilpreet int err = DDI_SUCCESS; 10981865Sdilpreet 10991865Sdilpreet /* 11001865Sdilpreet * if no handle then this is a peek. We have to return failure here 11011865Sdilpreet * as we have no way of knowing whether this is a MEM or IO space access 11021865Sdilpreet */ 11031865Sdilpreet if (in_args->handle == NULL) 11041865Sdilpreet return (DDI_FAILURE); 11051865Sdilpreet 11061865Sdilpreet for (; repcount; repcount--) { 11071865Sdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 11081865Sdilpreet switch (size) { 11091865Sdilpreet case sizeof (uint8_t): 11101865Sdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp, 11111865Sdilpreet (uint8_t *)dev_addr); 11121865Sdilpreet break; 11131865Sdilpreet case sizeof (uint16_t): 11141865Sdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp, 11151865Sdilpreet (uint16_t *)dev_addr); 11161865Sdilpreet break; 11171865Sdilpreet case sizeof (uint32_t): 11181865Sdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp, 11191865Sdilpreet (uint32_t *)dev_addr); 11201865Sdilpreet break; 11211865Sdilpreet case sizeof (uint64_t): 11221865Sdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp, 11231865Sdilpreet (uint64_t *)dev_addr); 11241865Sdilpreet break; 11251865Sdilpreet default: 11261865Sdilpreet err = DDI_FAILURE; 11271865Sdilpreet break; 11281865Sdilpreet } 11291865Sdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 11301865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 11311865Sdilpreet DDI_STRUCTURE_BE_ACC) { 11321865Sdilpreet switch (size) { 11331865Sdilpreet case sizeof (uint8_t): 11341865Sdilpreet *(uint8_t *)host_addr = 11351865Sdilpreet i_ddi_io_get8(hp, 11361865Sdilpreet (uint8_t *)dev_addr); 11371865Sdilpreet break; 11381865Sdilpreet case sizeof (uint16_t): 11391865Sdilpreet *(uint16_t *)host_addr = 11401865Sdilpreet i_ddi_io_swap_get16(hp, 11411865Sdilpreet (uint16_t *)dev_addr); 11421865Sdilpreet break; 11431865Sdilpreet case sizeof (uint32_t): 11441865Sdilpreet *(uint32_t *)host_addr = 11451865Sdilpreet i_ddi_io_swap_get32(hp, 11461865Sdilpreet (uint32_t *)dev_addr); 11471865Sdilpreet break; 11481865Sdilpreet /* 11491865Sdilpreet * note the 64-bit case is a dummy 11501865Sdilpreet * function - so no need to swap 11511865Sdilpreet */ 11521865Sdilpreet case sizeof (uint64_t): 11531865Sdilpreet *(uint64_t *)host_addr = 11541865Sdilpreet i_ddi_io_get64(hp, 11551865Sdilpreet (uint64_t *)dev_addr); 11561865Sdilpreet break; 11571865Sdilpreet default: 11581865Sdilpreet err = DDI_FAILURE; 11591865Sdilpreet break; 11601865Sdilpreet } 11611865Sdilpreet } else { 11621865Sdilpreet switch (size) { 11631865Sdilpreet case sizeof (uint8_t): 11641865Sdilpreet *(uint8_t *)host_addr = 11651865Sdilpreet i_ddi_io_get8(hp, 11661865Sdilpreet (uint8_t *)dev_addr); 11671865Sdilpreet break; 11681865Sdilpreet case sizeof (uint16_t): 11691865Sdilpreet *(uint16_t *)host_addr = 11701865Sdilpreet i_ddi_io_get16(hp, 11711865Sdilpreet (uint16_t *)dev_addr); 11721865Sdilpreet break; 11731865Sdilpreet case sizeof (uint32_t): 11741865Sdilpreet *(uint32_t *)host_addr = 11751865Sdilpreet i_ddi_io_get32(hp, 11761865Sdilpreet (uint32_t *)dev_addr); 11771865Sdilpreet break; 11781865Sdilpreet case sizeof (uint64_t): 11791865Sdilpreet *(uint64_t *)host_addr = 11801865Sdilpreet i_ddi_io_get64(hp, 11811865Sdilpreet (uint64_t *)dev_addr); 11821865Sdilpreet break; 11831865Sdilpreet default: 11841865Sdilpreet err = DDI_FAILURE; 11851865Sdilpreet break; 11861865Sdilpreet } 11871865Sdilpreet } 11881865Sdilpreet } else { 11891865Sdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 11901865Sdilpreet DDI_STRUCTURE_BE_ACC) { 11911865Sdilpreet switch (in_args->size) { 11921865Sdilpreet case sizeof (uint8_t): 11931865Sdilpreet *(uint8_t *)host_addr = 11941865Sdilpreet *(uint8_t *)dev_addr; 11951865Sdilpreet break; 11961865Sdilpreet case sizeof (uint16_t): 11971865Sdilpreet *(uint16_t *)host_addr = 11981865Sdilpreet ddi_swap16(*(uint16_t *)dev_addr); 11991865Sdilpreet break; 12001865Sdilpreet case sizeof (uint32_t): 12011865Sdilpreet *(uint32_t *)host_addr = 12021865Sdilpreet ddi_swap32(*(uint32_t *)dev_addr); 12031865Sdilpreet break; 12041865Sdilpreet case sizeof (uint64_t): 12051865Sdilpreet *(uint64_t *)host_addr = 12061865Sdilpreet ddi_swap64(*(uint64_t *)dev_addr); 12071865Sdilpreet break; 12081865Sdilpreet default: 12091865Sdilpreet err = DDI_FAILURE; 12101865Sdilpreet break; 12111865Sdilpreet } 12121865Sdilpreet } else { 12131865Sdilpreet switch (in_args->size) { 12141865Sdilpreet case sizeof (uint8_t): 12151865Sdilpreet *(uint8_t *)host_addr = 12161865Sdilpreet *(uint8_t *)dev_addr; 12171865Sdilpreet break; 12181865Sdilpreet case sizeof (uint16_t): 12191865Sdilpreet *(uint16_t *)host_addr = 12201865Sdilpreet *(uint16_t *)dev_addr; 12211865Sdilpreet break; 12221865Sdilpreet case sizeof (uint32_t): 12231865Sdilpreet *(uint32_t *)host_addr = 12241865Sdilpreet *(uint32_t *)dev_addr; 12251865Sdilpreet break; 12261865Sdilpreet case sizeof (uint64_t): 12271865Sdilpreet *(uint64_t *)host_addr = 12281865Sdilpreet *(uint64_t *)dev_addr; 12291865Sdilpreet break; 12301865Sdilpreet default: 12311865Sdilpreet err = DDI_FAILURE; 12321865Sdilpreet break; 12331865Sdilpreet } 12341865Sdilpreet } 12351865Sdilpreet } 12361865Sdilpreet host_addr += size; 12371865Sdilpreet if (flags == DDI_DEV_AUTOINCR) 12381865Sdilpreet dev_addr += size; 12391865Sdilpreet } 12401865Sdilpreet return (err); 12411865Sdilpreet } 12421865Sdilpreet 12431865Sdilpreet /*ARGSUSED*/ 12441865Sdilpreet int 12451865Sdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 12461865Sdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result) 12471865Sdilpreet { 12481865Sdilpreet if (ctlop == DDI_CTLOPS_PEEK) 12491865Sdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 12501865Sdilpreet else 12511865Sdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 12521865Sdilpreet } 12531865Sdilpreet 12541083Sanish /* 12551083Sanish * These are the get and put functions to be shared with drivers. The 12561083Sanish * mutex locking is done inside the functions referenced, rather than 12571083Sanish * here, and is thus shared across PCI child drivers and any other 12581083Sanish * consumers of PCI config space (such as the ACPI subsystem). 12591083Sanish * 12601083Sanish * The configuration space addresses come in as pointers. This is fine on 12611083Sanish * a 32-bit system, where the VM space and configuration space are the same 12621083Sanish * size. It's not such a good idea on a 64-bit system, where memory 12631083Sanish * addresses are twice as large as configuration space addresses. At some 12641083Sanish * point in the call tree we need to take a stand and say "you are 32-bit 12651083Sanish * from this time forth", and this seems like a nice self-contained place. 12661083Sanish */ 12671083Sanish 12681083Sanish uint8_t 12691083Sanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 12701083Sanish { 12711083Sanish pci_acc_cfblk_t *cfp; 12721083Sanish uint8_t rval; 12731083Sanish int reg; 12741083Sanish 12751083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 12761083Sanish 12771083Sanish reg = (int)(uintptr_t)addr; 12781083Sanish 12791083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 12801083Sanish 12811083Sanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 12821083Sanish reg); 12831083Sanish 12841083Sanish return (rval); 12851083Sanish } 12861083Sanish 12871083Sanish void 12881083Sanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 12891083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 12901083Sanish { 12911083Sanish uint8_t *h, *d; 12921083Sanish 12931083Sanish h = host_addr; 12941083Sanish d = dev_addr; 12951083Sanish 12961083Sanish if (flags == DDI_DEV_AUTOINCR) 12971083Sanish for (; repcount; repcount--) 12981083Sanish *h++ = pci_config_rd8(hdlp, d++); 12991083Sanish else 13001083Sanish for (; repcount; repcount--) 13011083Sanish *h++ = pci_config_rd8(hdlp, d); 13021083Sanish } 13031083Sanish 13041083Sanish uint16_t 13051083Sanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 13061083Sanish { 13071083Sanish pci_acc_cfblk_t *cfp; 13081083Sanish uint16_t rval; 13091083Sanish int reg; 13101083Sanish 13111083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13121083Sanish 13131083Sanish reg = (int)(uintptr_t)addr; 13141083Sanish 13151083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13161083Sanish 13171083Sanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 13181083Sanish reg); 13191083Sanish 13201083Sanish return (rval); 13211083Sanish } 13221083Sanish 13231083Sanish void 13241083Sanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 13251083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 13261083Sanish { 13271083Sanish uint16_t *h, *d; 13281083Sanish 13291083Sanish h = host_addr; 13301083Sanish d = dev_addr; 13311083Sanish 13321083Sanish if (flags == DDI_DEV_AUTOINCR) 13331083Sanish for (; repcount; repcount--) 13341083Sanish *h++ = pci_config_rd16(hdlp, d++); 13351083Sanish else 13361083Sanish for (; repcount; repcount--) 13371083Sanish *h++ = pci_config_rd16(hdlp, d); 13381083Sanish } 13391083Sanish 13401083Sanish uint32_t 13411083Sanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 13421083Sanish { 13431083Sanish pci_acc_cfblk_t *cfp; 13441083Sanish uint32_t rval; 13451083Sanish int reg; 13461083Sanish 13471083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13481083Sanish 13491083Sanish reg = (int)(uintptr_t)addr; 13501083Sanish 13511083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13521083Sanish 13531083Sanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 13541083Sanish cfp->c_funcnum, reg); 13551083Sanish 13561083Sanish return (rval); 13571083Sanish } 13581083Sanish 13591083Sanish void 13601083Sanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 13611083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 13621083Sanish { 13631083Sanish uint32_t *h, *d; 13641083Sanish 13651083Sanish h = host_addr; 13661083Sanish d = dev_addr; 13671083Sanish 13681083Sanish if (flags == DDI_DEV_AUTOINCR) 13691083Sanish for (; repcount; repcount--) 13701083Sanish *h++ = pci_config_rd32(hdlp, d++); 13711083Sanish else 13721083Sanish for (; repcount; repcount--) 13731083Sanish *h++ = pci_config_rd32(hdlp, d); 13741083Sanish } 13751083Sanish 13761083Sanish 13771083Sanish void 13781083Sanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 13791083Sanish { 13801083Sanish pci_acc_cfblk_t *cfp; 13811083Sanish int reg; 13821083Sanish 13831083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 13841083Sanish 13851083Sanish reg = (int)(uintptr_t)addr; 13861083Sanish 13871083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 13881083Sanish 13891083Sanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 13901083Sanish cfp->c_funcnum, reg, value); 13911083Sanish } 13921083Sanish 13931083Sanish void 13941083Sanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 13951083Sanish uint8_t *dev_addr, size_t repcount, uint_t flags) 13961083Sanish { 13971083Sanish uint8_t *h, *d; 13981083Sanish 13991083Sanish h = host_addr; 14001083Sanish d = dev_addr; 14011083Sanish 14021083Sanish if (flags == DDI_DEV_AUTOINCR) 14031083Sanish for (; repcount; repcount--) 14041083Sanish pci_config_wr8(hdlp, d++, *h++); 14051083Sanish else 14061083Sanish for (; repcount; repcount--) 14071083Sanish pci_config_wr8(hdlp, d, *h++); 14081083Sanish } 14091083Sanish 14101083Sanish void 14111083Sanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 14121083Sanish { 14131083Sanish pci_acc_cfblk_t *cfp; 14141083Sanish int reg; 14151083Sanish 14161083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14171083Sanish 14181083Sanish reg = (int)(uintptr_t)addr; 14191083Sanish 14201083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14211083Sanish 14221083Sanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 14231083Sanish cfp->c_funcnum, reg, value); 14241083Sanish } 14251083Sanish 14261083Sanish void 14271083Sanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 14281083Sanish uint16_t *dev_addr, size_t repcount, uint_t flags) 14291083Sanish { 14301083Sanish uint16_t *h, *d; 14311083Sanish 14321083Sanish h = host_addr; 14331083Sanish d = dev_addr; 14341083Sanish 14351083Sanish if (flags == DDI_DEV_AUTOINCR) 14361083Sanish for (; repcount; repcount--) 14371083Sanish pci_config_wr16(hdlp, d++, *h++); 14381083Sanish else 14391083Sanish for (; repcount; repcount--) 14401083Sanish pci_config_wr16(hdlp, d, *h++); 14411083Sanish } 14421083Sanish 14431083Sanish void 14441083Sanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 14451083Sanish { 14461083Sanish pci_acc_cfblk_t *cfp; 14471083Sanish int reg; 14481083Sanish 14491083Sanish ASSERT64(((uintptr_t)addr >> 32) == 0); 14501083Sanish 14511083Sanish reg = (int)(uintptr_t)addr; 14521083Sanish 14531083Sanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 14541083Sanish 14551083Sanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 14561083Sanish cfp->c_funcnum, reg, value); 14571083Sanish } 14581083Sanish 14591083Sanish void 14601083Sanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 14611083Sanish uint32_t *dev_addr, size_t repcount, uint_t flags) 14621083Sanish { 14631083Sanish uint32_t *h, *d; 14641083Sanish 14651083Sanish h = host_addr; 14661083Sanish d = dev_addr; 14671083Sanish 14681083Sanish if (flags == DDI_DEV_AUTOINCR) 14691083Sanish for (; repcount; repcount--) 14701083Sanish pci_config_wr32(hdlp, d++, *h++); 14711083Sanish else 14721083Sanish for (; repcount; repcount--) 14731083Sanish pci_config_wr32(hdlp, d, *h++); 14741083Sanish } 14751083Sanish 14761083Sanish uint64_t 14771083Sanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 14781083Sanish { 14791083Sanish uint32_t lw_val; 14801083Sanish uint32_t hi_val; 14811083Sanish uint32_t *dp; 14821083Sanish uint64_t val; 14831083Sanish 14841083Sanish dp = (uint32_t *)addr; 14851083Sanish lw_val = pci_config_rd32(hdlp, dp); 14861083Sanish dp++; 14871083Sanish hi_val = pci_config_rd32(hdlp, dp); 14881083Sanish val = ((uint64_t)hi_val << 32) | lw_val; 14891083Sanish return (val); 14901083Sanish } 14911083Sanish 14921083Sanish void 14931083Sanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 14941083Sanish { 14951083Sanish uint32_t lw_val; 14961083Sanish uint32_t hi_val; 14971083Sanish uint32_t *dp; 14981083Sanish 14991083Sanish dp = (uint32_t *)addr; 15001083Sanish lw_val = (uint32_t)(value & 0xffffffff); 15011083Sanish hi_val = (uint32_t)(value >> 32); 15021083Sanish pci_config_wr32(hdlp, dp, lw_val); 15031083Sanish dp++; 15041083Sanish pci_config_wr32(hdlp, dp, hi_val); 15051083Sanish } 15061083Sanish 15071083Sanish void 15081083Sanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 15091083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 15101083Sanish { 15111083Sanish if (flags == DDI_DEV_AUTOINCR) { 15121083Sanish for (; repcount; repcount--) 15131083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 15141083Sanish } else { 15151083Sanish for (; repcount; repcount--) 15161083Sanish *host_addr++ = pci_config_rd64(hdlp, dev_addr); 15171083Sanish } 15181083Sanish } 15191083Sanish 15201083Sanish void 15211083Sanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 15221083Sanish uint64_t *dev_addr, size_t repcount, uint_t flags) 15231083Sanish { 15241083Sanish if (flags == DDI_DEV_AUTOINCR) { 15251083Sanish for (; repcount; repcount--) 15261083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr++); 15271083Sanish } else { 15281083Sanish for (; repcount; repcount--) 15291083Sanish pci_config_wr64(hdlp, host_addr++, *dev_addr); 15301083Sanish } 15311083Sanish } 15321083Sanish 15331083Sanish 15341083Sanish /* 15351083Sanish * Enable Legacy PCI config space access for the following four north bridges 15361083Sanish * Host bridge: AMD HyperTransport Technology Configuration 15371083Sanish * Host bridge: AMD Address Map 15381083Sanish * Host bridge: AMD DRAM Controller 15391083Sanish * Host bridge: AMD Miscellaneous Control 15401083Sanish */ 15411083Sanish int 15421083Sanish is_amd_northbridge(dev_info_t *dip) 15431083Sanish { 15441083Sanish int vendor_id, device_id; 15451083Sanish 15461083Sanish vendor_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 15471083Sanish "vendor-id", -1); 15481083Sanish device_id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 15491083Sanish "device-id", -1); 15501083Sanish 15511083Sanish if (IS_AMD_NTBRIDGE(vendor_id, device_id)) 15521083Sanish return (0); 15531083Sanish 15541083Sanish return (1); 15551083Sanish } 1556