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