170025d76Sjohnny /* 270025d76Sjohnny * CDDL HEADER START 370025d76Sjohnny * 470025d76Sjohnny * The contents of this file are subject to the terms of the 5102cb92eSjohnny * Common Development and Distribution License (the "License"). 6102cb92eSjohnny * You may not use this file except in compliance with the License. 770025d76Sjohnny * 870025d76Sjohnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 970025d76Sjohnny * or http://www.opensolaris.org/os/licensing. 1070025d76Sjohnny * See the License for the specific language governing permissions 1170025d76Sjohnny * and limitations under the License. 1270025d76Sjohnny * 1370025d76Sjohnny * When distributing Covered Code, include this CDDL HEADER in each 1470025d76Sjohnny * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1570025d76Sjohnny * If applicable, add the following below this CDDL HEADER, with the 1670025d76Sjohnny * fields enclosed by brackets "[]" replaced with your own identifying 1770025d76Sjohnny * information: Portions Copyright [yyyy] [name of copyright owner] 1870025d76Sjohnny * 1970025d76Sjohnny * CDDL HEADER END 2070025d76Sjohnny */ 2170025d76Sjohnny 2270025d76Sjohnny /* 23*5cd376e8SJimmy Vetayases * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 2470025d76Sjohnny */ 2570025d76Sjohnny 2670025d76Sjohnny /* 2770025d76Sjohnny * File that has code which is common between pci(7d) and npe(7d) 2870025d76Sjohnny * It shares the following: 2970025d76Sjohnny * - interrupt code 3070025d76Sjohnny * - pci_tools ioctl code 3170025d76Sjohnny * - name_child code 3270025d76Sjohnny * - set_parent_private_data code 3370025d76Sjohnny */ 3470025d76Sjohnny 3570025d76Sjohnny #include <sys/conf.h> 3670025d76Sjohnny #include <sys/pci.h> 3770025d76Sjohnny #include <sys/sunndi.h> 387a364d25Sschwartz #include <sys/mach_intr.h> 3970025d76Sjohnny #include <sys/pci_intr_lib.h> 4070025d76Sjohnny #include <sys/psm.h> 4170025d76Sjohnny #include <sys/policy.h> 4270025d76Sjohnny #include <sys/sysmacros.h> 437a364d25Sschwartz #include <sys/clock.h> 44ae115bc7Smrj #include <sys/apic.h> 4570025d76Sjohnny #include <sys/pci_tools.h> 4670025d76Sjohnny #include <io/pci/pci_var.h> 4770025d76Sjohnny #include <io/pci/pci_tools_ext.h> 4870025d76Sjohnny #include <io/pci/pci_common.h> 49649d4cceSanish #include <sys/pci_cfgspace.h> 50649d4cceSanish #include <sys/pci_impl.h> 51600d7745Sjveta #include <sys/pci_cap.h> 5270025d76Sjohnny 5370025d76Sjohnny /* 5470025d76Sjohnny * Function prototypes 5570025d76Sjohnny */ 5670025d76Sjohnny static int pci_get_priority(dev_info_t *, ddi_intr_handle_impl_t *, int *); 5770025d76Sjohnny static int pci_enable_intr(dev_info_t *, dev_info_t *, 5870025d76Sjohnny ddi_intr_handle_impl_t *, uint32_t); 5970025d76Sjohnny static void pci_disable_intr(dev_info_t *, dev_info_t *, 6070025d76Sjohnny ddi_intr_handle_impl_t *, uint32_t); 617ff178cdSJimmy Vetayases static int pci_alloc_intr_fixed(dev_info_t *, dev_info_t *, 627ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *, void *); 637ff178cdSJimmy Vetayases static int pci_free_intr_fixed(dev_info_t *, dev_info_t *, 647ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *); 6570025d76Sjohnny 667ff178cdSJimmy Vetayases /* Extern declarations for PSM module */ 6770025d76Sjohnny extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 6870025d76Sjohnny psm_intr_op_t, int *); 697ff178cdSJimmy Vetayases extern ddi_irm_pool_t *apix_irm_pool_p; 7070025d76Sjohnny 7170025d76Sjohnny /* 7270025d76Sjohnny * pci_name_child: 7370025d76Sjohnny * 7470025d76Sjohnny * Assign the address portion of the node name 7570025d76Sjohnny */ 7670025d76Sjohnny int 7770025d76Sjohnny pci_common_name_child(dev_info_t *child, char *name, int namelen) 7870025d76Sjohnny { 7970025d76Sjohnny int dev, func, length; 8070025d76Sjohnny char **unit_addr; 8170025d76Sjohnny uint_t n; 8270025d76Sjohnny pci_regspec_t *pci_rp; 8370025d76Sjohnny 8470025d76Sjohnny if (ndi_dev_is_persistent_node(child) == 0) { 8570025d76Sjohnny /* 8670025d76Sjohnny * For .conf node, use "unit-address" property 8770025d76Sjohnny */ 8870025d76Sjohnny if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 8970025d76Sjohnny DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 9070025d76Sjohnny DDI_PROP_SUCCESS) { 9170025d76Sjohnny cmn_err(CE_WARN, "cannot find unit-address in %s.conf", 9270025d76Sjohnny ddi_get_name(child)); 9370025d76Sjohnny return (DDI_FAILURE); 9470025d76Sjohnny } 9570025d76Sjohnny if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 9670025d76Sjohnny cmn_err(CE_WARN, "unit-address property in %s.conf" 9770025d76Sjohnny " not well-formed", ddi_get_name(child)); 9870025d76Sjohnny ddi_prop_free(unit_addr); 9970025d76Sjohnny return (DDI_FAILURE); 10070025d76Sjohnny } 10170025d76Sjohnny (void) snprintf(name, namelen, "%s", *unit_addr); 10270025d76Sjohnny ddi_prop_free(unit_addr); 10370025d76Sjohnny return (DDI_SUCCESS); 10470025d76Sjohnny } 10570025d76Sjohnny 10670025d76Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 10770025d76Sjohnny "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) { 10870025d76Sjohnny cmn_err(CE_WARN, "cannot find reg property in %s", 10970025d76Sjohnny ddi_get_name(child)); 11070025d76Sjohnny return (DDI_FAILURE); 11170025d76Sjohnny } 11270025d76Sjohnny 11370025d76Sjohnny /* copy the device identifications */ 11470025d76Sjohnny dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); 11570025d76Sjohnny func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); 11670025d76Sjohnny 11770025d76Sjohnny /* 11870025d76Sjohnny * free the memory allocated by ddi_prop_lookup_int_array 11970025d76Sjohnny */ 12070025d76Sjohnny ddi_prop_free(pci_rp); 12170025d76Sjohnny 12270025d76Sjohnny if (func != 0) { 12370025d76Sjohnny (void) snprintf(name, namelen, "%x,%x", dev, func); 12470025d76Sjohnny } else { 12570025d76Sjohnny (void) snprintf(name, namelen, "%x", dev); 12670025d76Sjohnny } 12770025d76Sjohnny 12870025d76Sjohnny return (DDI_SUCCESS); 12970025d76Sjohnny } 13070025d76Sjohnny 13170025d76Sjohnny /* 13270025d76Sjohnny * Interrupt related code: 13370025d76Sjohnny * 13470025d76Sjohnny * The following busop is common to npe and pci drivers 13570025d76Sjohnny * bus_introp 13670025d76Sjohnny */ 13770025d76Sjohnny 13870025d76Sjohnny /* 13970025d76Sjohnny * Create the ddi_parent_private_data for a pseudo child. 14070025d76Sjohnny */ 14170025d76Sjohnny void 14270025d76Sjohnny pci_common_set_parent_private_data(dev_info_t *dip) 14370025d76Sjohnny { 14470025d76Sjohnny struct ddi_parent_private_data *pdptr; 14570025d76Sjohnny 14670025d76Sjohnny pdptr = (struct ddi_parent_private_data *)kmem_zalloc( 14770025d76Sjohnny (sizeof (struct ddi_parent_private_data) + 14870025d76Sjohnny sizeof (struct intrspec)), KM_SLEEP); 14970025d76Sjohnny pdptr->par_intr = (struct intrspec *)(pdptr + 1); 15070025d76Sjohnny pdptr->par_nintr = 1; 15170025d76Sjohnny ddi_set_parent_data(dip, pdptr); 15270025d76Sjohnny } 15370025d76Sjohnny 15470025d76Sjohnny /* 15570025d76Sjohnny * pci_get_priority: 15670025d76Sjohnny * Figure out the priority of the device 15770025d76Sjohnny */ 15870025d76Sjohnny static int 15970025d76Sjohnny pci_get_priority(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, int *pri) 16070025d76Sjohnny { 16170025d76Sjohnny struct intrspec *ispec; 16270025d76Sjohnny 16370025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_get_priority: dip = 0x%p, hdlp = %p\n", 16470025d76Sjohnny (void *)dip, (void *)hdlp)); 16570025d76Sjohnny 16670025d76Sjohnny if ((ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 16770025d76Sjohnny hdlp->ih_inum)) == NULL) { 16870025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 169614edcaeSEvan Yan *pri = pci_class_to_pil(dip); 17070025d76Sjohnny pci_common_set_parent_private_data(hdlp->ih_dip); 17170025d76Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(dip, dip, 17270025d76Sjohnny hdlp->ih_inum); 17370025d76Sjohnny return (DDI_SUCCESS); 17470025d76Sjohnny } 17570025d76Sjohnny return (DDI_FAILURE); 17670025d76Sjohnny } 17770025d76Sjohnny 17870025d76Sjohnny *pri = ispec->intrspec_pri; 17970025d76Sjohnny return (DDI_SUCCESS); 18070025d76Sjohnny } 18170025d76Sjohnny 18270025d76Sjohnny 18370025d76Sjohnny 184d4bc0535SKrishna Elango static int pcieb_intr_pri_counter = 0; 18570025d76Sjohnny 18670025d76Sjohnny /* 18770025d76Sjohnny * pci_common_intr_ops: bus_intr_op() function for interrupt support 18870025d76Sjohnny */ 18970025d76Sjohnny int 19070025d76Sjohnny pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, 19170025d76Sjohnny ddi_intr_handle_impl_t *hdlp, void *result) 19270025d76Sjohnny { 19370025d76Sjohnny int priority = 0; 19470025d76Sjohnny int psm_status = 0; 19570025d76Sjohnny int pci_status = 0; 19670025d76Sjohnny int pci_rval, psm_rval = PSM_FAILURE; 19770025d76Sjohnny int types = 0; 19870025d76Sjohnny int pciepci = 0; 199102cb92eSjohnny int i, j, count; 200600d7745Sjveta int rv; 20170025d76Sjohnny int behavior; 202d12abe7cSanish int cap_ptr; 203600d7745Sjveta uint16_t msi_cap_base, msix_cap_base, cap_ctrl; 204600d7745Sjveta char *prop; 20570025d76Sjohnny ddi_intrspec_t isp; 20670025d76Sjohnny struct intrspec *ispec; 20770025d76Sjohnny ddi_intr_handle_impl_t tmp_hdl; 20870025d76Sjohnny ddi_intr_msix_t *msix_p; 209e1d9f4e6Sschwartz ihdl_plat_t *ihdl_plat_datap; 210102cb92eSjohnny ddi_intr_handle_t *h_array; 211d12abe7cSanish ddi_acc_handle_t handle; 2127ff178cdSJimmy Vetayases apic_get_intr_t intrinfo; 21370025d76Sjohnny 21470025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, 21570025d76Sjohnny "pci_common_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n", 21670025d76Sjohnny (void *)pdip, (void *)rdip, intr_op, (void *)hdlp)); 21770025d76Sjohnny 21870025d76Sjohnny /* Process the request */ 21970025d76Sjohnny switch (intr_op) { 22070025d76Sjohnny case DDI_INTROP_SUPPORTED_TYPES: 22120036fe5Segillett /* 222600d7745Sjveta * First we determine the interrupt types supported by the 223600d7745Sjveta * device itself, then we filter them through what the OS 224600d7745Sjveta * and system supports. We determine system-level 225600d7745Sjveta * interrupt type support for anything other than fixed intrs 226600d7745Sjveta * through the psm_intr_ops vector 22720036fe5Segillett */ 228600d7745Sjveta rv = DDI_FAILURE; 22970025d76Sjohnny 230600d7745Sjveta /* Fixed supported by default */ 231600d7745Sjveta types = DDI_INTR_TYPE_FIXED; 232600d7745Sjveta 233600d7745Sjveta if (psm_intr_ops == NULL) { 234600d7745Sjveta *(int *)result = types; 235600d7745Sjveta return (DDI_SUCCESS); 236600d7745Sjveta } 237600d7745Sjveta if (pci_config_setup(rdip, &handle) != DDI_SUCCESS) 238600d7745Sjveta return (DDI_FAILURE); 239600d7745Sjveta 240600d7745Sjveta /* Sanity test cap control values if found */ 241600d7745Sjveta 242600d7745Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) == 243600d7745Sjveta DDI_SUCCESS) { 244600d7745Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base, 245600d7745Sjveta PCI_MSI_CTRL); 246600d7745Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 247600d7745Sjveta goto SUPPORTED_TYPES_OUT; 248600d7745Sjveta 249600d7745Sjveta types |= DDI_INTR_TYPE_MSI; 250600d7745Sjveta } 251600d7745Sjveta 252600d7745Sjveta if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) == 253600d7745Sjveta DDI_SUCCESS) { 254600d7745Sjveta cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base, 255600d7745Sjveta PCI_MSIX_CTRL); 256600d7745Sjveta if (cap_ctrl == PCI_CAP_EINVAL16) 257600d7745Sjveta goto SUPPORTED_TYPES_OUT; 258600d7745Sjveta 259600d7745Sjveta types |= DDI_INTR_TYPE_MSIX; 260600d7745Sjveta } 261600d7745Sjveta 262600d7745Sjveta /* 263600d7745Sjveta * Filter device-level types through system-level support 264600d7745Sjveta */ 265600d7745Sjveta tmp_hdl.ih_type = types; 266600d7745Sjveta if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI, 267600d7745Sjveta &types) != PSM_SUCCESS) 268600d7745Sjveta goto SUPPORTED_TYPES_OUT; 269600d7745Sjveta 27070025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 27170025d76Sjohnny "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, 2727ff178cdSJimmy Vetayases types)); 273600d7745Sjveta 274600d7745Sjveta /* 275600d7745Sjveta * Export any MSI/MSI-X cap locations via properties 276600d7745Sjveta */ 277600d7745Sjveta if (types & DDI_INTR_TYPE_MSI) { 278600d7745Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 279600d7745Sjveta "pci-msi-capid-pointer", (int)msi_cap_base) != 280600d7745Sjveta DDI_PROP_SUCCESS) 281600d7745Sjveta goto SUPPORTED_TYPES_OUT; 28270025d76Sjohnny } 283600d7745Sjveta if (types & DDI_INTR_TYPE_MSIX) { 284600d7745Sjveta if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, 285600d7745Sjveta "pci-msix-capid-pointer", (int)msix_cap_base) != 286600d7745Sjveta DDI_PROP_SUCCESS) 287600d7745Sjveta goto SUPPORTED_TYPES_OUT; 288600d7745Sjveta } 289600d7745Sjveta 290600d7745Sjveta rv = DDI_SUCCESS; 291600d7745Sjveta 292600d7745Sjveta SUPPORTED_TYPES_OUT: 293600d7745Sjveta *(int *)result = types; 294600d7745Sjveta pci_config_teardown(&handle); 295600d7745Sjveta return (rv); 296600d7745Sjveta 297a54f81fbSanish case DDI_INTROP_NAVAIL: 29870025d76Sjohnny case DDI_INTROP_NINTRS: 299a54f81fbSanish if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 300a54f81fbSanish if (pci_msi_get_nintrs(hdlp->ih_dip, hdlp->ih_type, 301a54f81fbSanish result) != DDI_SUCCESS) 30270025d76Sjohnny return (DDI_FAILURE); 303a54f81fbSanish } else { 304a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(hdlp->ih_dip); 305a54f81fbSanish if (*(int *)result == 0) 306a54f81fbSanish return (DDI_FAILURE); 307a54f81fbSanish } 30870025d76Sjohnny break; 30970025d76Sjohnny case DDI_INTROP_ALLOC: 3107ff178cdSJimmy Vetayases 3117ff178cdSJimmy Vetayases /* 3127ff178cdSJimmy Vetayases * FIXED type 3137ff178cdSJimmy Vetayases */ 3147ff178cdSJimmy Vetayases if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 3157ff178cdSJimmy Vetayases return (pci_alloc_intr_fixed(pdip, rdip, hdlp, result)); 31670025d76Sjohnny /* 31770025d76Sjohnny * MSI or MSIX (figure out number of vectors available) 31870025d76Sjohnny */ 31970025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 32070025d76Sjohnny (psm_intr_ops != NULL) && 32170025d76Sjohnny (pci_get_priority(rdip, hdlp, &priority) == DDI_SUCCESS)) { 32270025d76Sjohnny /* 323d4bc0535SKrishna Elango * Following check is a special case for 'pcieb'. 32470025d76Sjohnny * This makes sure vectors with the right priority 325d4bc0535SKrishna Elango * are allocated for pcieb during ALLOC time. 32670025d76Sjohnny */ 327d4bc0535SKrishna Elango if (strcmp(ddi_driver_name(rdip), "pcieb") == 0) { 32870025d76Sjohnny hdlp->ih_pri = 329d4bc0535SKrishna Elango (pcieb_intr_pri_counter % 2) ? 4 : 7; 33070025d76Sjohnny pciepci = 1; 33170025d76Sjohnny } else 33270025d76Sjohnny hdlp->ih_pri = priority; 33380ab886dSwesolows behavior = (int)(uintptr_t)hdlp->ih_scratch2; 334d12abe7cSanish 335d12abe7cSanish /* 336d12abe7cSanish * Cache in the config handle and cap_ptr 337d12abe7cSanish */ 338d12abe7cSanish if (i_ddi_get_pci_config_handle(rdip) == NULL) { 339d12abe7cSanish if (pci_config_setup(rdip, &handle) != 340d12abe7cSanish DDI_SUCCESS) 341d12abe7cSanish return (DDI_FAILURE); 342d12abe7cSanish i_ddi_set_pci_config_handle(rdip, handle); 343d12abe7cSanish } 344d12abe7cSanish 345600d7745Sjveta prop = NULL; 346600d7745Sjveta cap_ptr = 0; 347600d7745Sjveta if (hdlp->ih_type == DDI_INTR_TYPE_MSI) 348600d7745Sjveta prop = "pci-msi-capid-pointer"; 349600d7745Sjveta else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) 350600d7745Sjveta prop = "pci-msix-capid-pointer"; 351d12abe7cSanish 352600d7745Sjveta /* 353600d7745Sjveta * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES 354600d7745Sjveta * for MSI(X) before allocation 355600d7745Sjveta */ 356600d7745Sjveta if (prop != NULL) { 357d12abe7cSanish cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, 358600d7745Sjveta DDI_PROP_DONTPASS, prop, 0); 359600d7745Sjveta if (cap_ptr == 0) { 360600d7745Sjveta DDI_INTR_NEXDBG((CE_CONT, 361600d7745Sjveta "pci_common_intr_ops: rdip: 0x%p " 362600d7745Sjveta "attempted MSI(X) alloc without " 363600d7745Sjveta "cap property\n", (void *)rdip)); 364600d7745Sjveta return (DDI_FAILURE); 365d12abe7cSanish } 366600d7745Sjveta } 367600d7745Sjveta i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); 368d12abe7cSanish 369600d7745Sjveta /* 370600d7745Sjveta * Allocate interrupt vectors 371600d7745Sjveta */ 37270025d76Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 37370025d76Sjohnny PSM_INTR_OP_ALLOC_VECTORS, result); 37470025d76Sjohnny 3751ac1709fSanish if (*(int *)result == 0) 3761ac1709fSanish return (DDI_INTR_NOTFOUND); 3771ac1709fSanish 37870025d76Sjohnny /* verify behavior flag and take appropriate action */ 37970025d76Sjohnny if ((behavior == DDI_INTR_ALLOC_STRICT) && 38070025d76Sjohnny (*(int *)result < hdlp->ih_scratch1)) { 38170025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, 38270025d76Sjohnny "pci_common_intr_ops: behavior %x, " 38370025d76Sjohnny "couldn't get enough intrs\n", behavior)); 38470025d76Sjohnny hdlp->ih_scratch1 = *(int *)result; 38570025d76Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 38670025d76Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 38770025d76Sjohnny return (DDI_EAGAIN); 38870025d76Sjohnny } 38970025d76Sjohnny 39070025d76Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 39170025d76Sjohnny if (!(msix_p = i_ddi_get_msix(hdlp->ih_dip))) { 39270025d76Sjohnny msix_p = pci_msix_init(hdlp->ih_dip); 393fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China if (msix_p) { 39470025d76Sjohnny i_ddi_set_msix(hdlp->ih_dip, 39570025d76Sjohnny msix_p); 396fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China } else { 397fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China DDI_INTR_NEXDBG((CE_CONT, 398fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China "pci_common_intr_ops: MSI-X" 399fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China "table initilization failed" 400fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China ", rdip 0x%p inum 0x%x\n", 401fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China (void *)rdip, 402fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China hdlp->ih_inum)); 403fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 404fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China (void) (*psm_intr_ops)(rdip, 405fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China hdlp, 406fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China PSM_INTR_OP_FREE_VECTORS, 407fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China NULL); 408fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China 409fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China return (DDI_FAILURE); 410fbb8dc2cSlipeng sang - Sun Microsystems - Beijing China } 41170025d76Sjohnny } 41270025d76Sjohnny } 41370025d76Sjohnny 41470025d76Sjohnny if (pciepci) { 41570025d76Sjohnny /* update priority in ispec */ 41670025d76Sjohnny isp = pci_intx_get_ispec(pdip, rdip, 41770025d76Sjohnny (int)hdlp->ih_inum); 41870025d76Sjohnny ispec = (struct intrspec *)isp; 41970025d76Sjohnny if (ispec) 42070025d76Sjohnny ispec->intrspec_pri = hdlp->ih_pri; 421d4bc0535SKrishna Elango ++pcieb_intr_pri_counter; 42270025d76Sjohnny } 42370025d76Sjohnny 42470025d76Sjohnny } else 42570025d76Sjohnny return (DDI_FAILURE); 42670025d76Sjohnny break; 42770025d76Sjohnny case DDI_INTROP_FREE: 42870025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type) && 42970025d76Sjohnny (psm_intr_ops != NULL)) { 43068565200Sanish if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1 == 43168565200Sanish 0) { 432d12abe7cSanish if (handle = i_ddi_get_pci_config_handle( 433d12abe7cSanish rdip)) { 434d12abe7cSanish (void) pci_config_teardown(&handle); 435d12abe7cSanish i_ddi_set_pci_config_handle(rdip, NULL); 436d12abe7cSanish } 437d12abe7cSanish if (cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip)) 438d12abe7cSanish i_ddi_set_msi_msix_cap_ptr(rdip, 0); 439d12abe7cSanish } 440d12abe7cSanish 44170025d76Sjohnny (void) (*psm_intr_ops)(rdip, hdlp, 44270025d76Sjohnny PSM_INTR_OP_FREE_VECTORS, NULL); 44370025d76Sjohnny 44470025d76Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) { 44570025d76Sjohnny msix_p = i_ddi_get_msix(hdlp->ih_dip); 44670025d76Sjohnny if (msix_p && 44768565200Sanish (i_ddi_intr_get_current_nintrs( 44868565200Sanish hdlp->ih_dip) - 1) == 0) { 44970025d76Sjohnny pci_msix_fini(msix_p); 45070025d76Sjohnny i_ddi_set_msix(hdlp->ih_dip, NULL); 45170025d76Sjohnny } 45270025d76Sjohnny } 4537ff178cdSJimmy Vetayases } else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 4547ff178cdSJimmy Vetayases return (pci_free_intr_fixed(pdip, rdip, hdlp)); 4557ff178cdSJimmy Vetayases } else 4567ff178cdSJimmy Vetayases return (DDI_FAILURE); 45770025d76Sjohnny break; 45870025d76Sjohnny case DDI_INTROP_GETPRI: 45970025d76Sjohnny /* Get the priority */ 46070025d76Sjohnny if (pci_get_priority(rdip, hdlp, &priority) != DDI_SUCCESS) 46170025d76Sjohnny return (DDI_FAILURE); 46270025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 46370025d76Sjohnny "priority = 0x%x\n", priority)); 46470025d76Sjohnny *(int *)result = priority; 46570025d76Sjohnny break; 46670025d76Sjohnny case DDI_INTROP_SETPRI: 46770025d76Sjohnny /* Validate the interrupt priority passed */ 46870025d76Sjohnny if (*(int *)result > LOCK_LEVEL) 46970025d76Sjohnny return (DDI_FAILURE); 47070025d76Sjohnny 47170025d76Sjohnny /* Ensure that PSM is all initialized */ 47270025d76Sjohnny if (psm_intr_ops == NULL) 47370025d76Sjohnny return (DDI_FAILURE); 47470025d76Sjohnny 47596f82fefSSophia Li isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 47696f82fefSSophia Li ispec = (struct intrspec *)isp; 47796f82fefSSophia Li if (ispec == NULL) 47896f82fefSSophia Li return (DDI_FAILURE); 47996f82fefSSophia Li 48096f82fefSSophia Li /* For fixed interrupts */ 48196f82fefSSophia Li if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) { 48296f82fefSSophia Li /* if interrupt is shared, return failure */ 48396f82fefSSophia Li ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 48496f82fefSSophia Li psm_rval = (*psm_intr_ops)(rdip, hdlp, 48596f82fefSSophia Li PSM_INTR_OP_GET_SHARED, &psm_status); 48696f82fefSSophia Li /* 48796f82fefSSophia Li * For fixed interrupts, the irq may not have been 48896f82fefSSophia Li * allocated when SET_PRI is called, and the above 48996f82fefSSophia Li * GET_SHARED op may return PSM_FAILURE. This is not 49096f82fefSSophia Li * a real error and is ignored below. 49196f82fefSSophia Li */ 49296f82fefSSophia Li if ((psm_rval != PSM_FAILURE) && (psm_status == 1)) { 49396f82fefSSophia Li DDI_INTR_NEXDBG((CE_CONT, 49496f82fefSSophia Li "pci_common_intr_ops: " 49596f82fefSSophia Li "dip 0x%p cannot setpri, psm_rval=%d," 49696f82fefSSophia Li "psm_status=%d\n", (void *)rdip, psm_rval, 49796f82fefSSophia Li psm_status)); 49896f82fefSSophia Li return (DDI_FAILURE); 49996f82fefSSophia Li } 50096f82fefSSophia Li } 50196f82fefSSophia Li 50270025d76Sjohnny /* Change the priority */ 50370025d76Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) == 50470025d76Sjohnny PSM_FAILURE) 50570025d76Sjohnny return (DDI_FAILURE); 50670025d76Sjohnny 50770025d76Sjohnny /* update ispec */ 50870025d76Sjohnny ispec->intrspec_pri = *(int *)result; 50970025d76Sjohnny break; 51070025d76Sjohnny case DDI_INTROP_ADDISR: 51170025d76Sjohnny /* update ispec */ 51270025d76Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 51370025d76Sjohnny ispec = (struct intrspec *)isp; 514e1d9f4e6Sschwartz if (ispec) { 51570025d76Sjohnny ispec->intrspec_func = hdlp->ih_cb_func; 516e1d9f4e6Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 517e1d9f4e6Sschwartz pci_kstat_create(&ihdl_plat_datap->ip_ksp, pdip, hdlp); 518e1d9f4e6Sschwartz } 51970025d76Sjohnny break; 52070025d76Sjohnny case DDI_INTROP_REMISR: 52170025d76Sjohnny /* Get the interrupt structure pointer */ 52270025d76Sjohnny isp = pci_intx_get_ispec(pdip, rdip, (int)hdlp->ih_inum); 52370025d76Sjohnny ispec = (struct intrspec *)isp; 524e1d9f4e6Sschwartz if (ispec) { 52570025d76Sjohnny ispec->intrspec_func = (uint_t (*)()) 0; 526e1d9f4e6Sschwartz ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 527e1d9f4e6Sschwartz if (ihdl_plat_datap->ip_ksp != NULL) 528e1d9f4e6Sschwartz pci_kstat_delete(ihdl_plat_datap->ip_ksp); 529e1d9f4e6Sschwartz } 53070025d76Sjohnny break; 53170025d76Sjohnny case DDI_INTROP_GETCAP: 53270025d76Sjohnny /* 53370025d76Sjohnny * First check the config space and/or 53470025d76Sjohnny * MSI capability register(s) 53570025d76Sjohnny */ 53670025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 53770025d76Sjohnny pci_rval = pci_msi_get_cap(rdip, hdlp->ih_type, 53870025d76Sjohnny &pci_status); 53970025d76Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 54070025d76Sjohnny pci_rval = pci_intx_get_cap(rdip, &pci_status); 54170025d76Sjohnny 5427ff178cdSJimmy Vetayases /* next check with PSM module */ 54370025d76Sjohnny if (psm_intr_ops != NULL) 54470025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 54570025d76Sjohnny PSM_INTR_OP_GET_CAP, &psm_status); 54670025d76Sjohnny 54770025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned psm_rval = %x, " 54870025d76Sjohnny "psm_status = %x, pci_rval = %x, pci_status = %x\n", 54970025d76Sjohnny psm_rval, psm_status, pci_rval, pci_status)); 55070025d76Sjohnny 55170025d76Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 55270025d76Sjohnny *(int *)result = 0; 55370025d76Sjohnny return (DDI_FAILURE); 55470025d76Sjohnny } 55570025d76Sjohnny 55670025d76Sjohnny if (psm_rval == PSM_SUCCESS) 55770025d76Sjohnny *(int *)result = psm_status; 55870025d76Sjohnny 55970025d76Sjohnny if (pci_rval == DDI_SUCCESS) 56070025d76Sjohnny *(int *)result |= pci_status; 56170025d76Sjohnny 56270025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETCAP returned = %x\n", 56370025d76Sjohnny *(int *)result)); 56470025d76Sjohnny break; 56570025d76Sjohnny case DDI_INTROP_SETCAP: 56670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 56770025d76Sjohnny "SETCAP cap=0x%x\n", *(int *)result)); 56870025d76Sjohnny if (psm_intr_ops == NULL) 56970025d76Sjohnny return (DDI_FAILURE); 57070025d76Sjohnny 57170025d76Sjohnny if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) { 57270025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops" 57370025d76Sjohnny " returned failure\n")); 57470025d76Sjohnny return (DDI_FAILURE); 57570025d76Sjohnny } 57670025d76Sjohnny break; 57770025d76Sjohnny case DDI_INTROP_ENABLE: 57870025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE\n")); 57970025d76Sjohnny if (psm_intr_ops == NULL) 58070025d76Sjohnny return (DDI_FAILURE); 58170025d76Sjohnny 58270025d76Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, hdlp->ih_inum) != 58370025d76Sjohnny DDI_SUCCESS) 58470025d76Sjohnny return (DDI_FAILURE); 58570025d76Sjohnny 58670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: ENABLE " 58770025d76Sjohnny "vector=0x%x\n", hdlp->ih_vector)); 58870025d76Sjohnny break; 58970025d76Sjohnny case DDI_INTROP_DISABLE: 59070025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE\n")); 59170025d76Sjohnny if (psm_intr_ops == NULL) 59270025d76Sjohnny return (DDI_FAILURE); 59370025d76Sjohnny 59470025d76Sjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 59570025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: DISABLE " 59670025d76Sjohnny "vector = %x\n", hdlp->ih_vector)); 59770025d76Sjohnny break; 59870025d76Sjohnny case DDI_INTROP_BLOCKENABLE: 59970025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 60070025d76Sjohnny "BLOCKENABLE\n")); 60170025d76Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 60270025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: not MSI\n")); 60370025d76Sjohnny return (DDI_FAILURE); 60470025d76Sjohnny } 60570025d76Sjohnny 60670025d76Sjohnny /* Check if psm_intr_ops is NULL? */ 60770025d76Sjohnny if (psm_intr_ops == NULL) 60870025d76Sjohnny return (DDI_FAILURE); 60970025d76Sjohnny 610102cb92eSjohnny count = hdlp->ih_scratch1; 611102cb92eSjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 612102cb92eSjohnny for (i = 0; i < count; i++) { 613102cb92eSjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 61470025d76Sjohnny if (pci_enable_intr(pdip, rdip, hdlp, 615102cb92eSjohnny hdlp->ih_inum) != DDI_SUCCESS) { 61670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKENABLE: " 61770025d76Sjohnny "pci_enable_intr failed for %d\n", i)); 618102cb92eSjohnny for (j = 0; j < i; j++) { 6192917a9c9Sschwartz hdlp = (ddi_intr_handle_impl_t *) 6202917a9c9Sschwartz h_array[j]; 62170025d76Sjohnny pci_disable_intr(pdip, rdip, hdlp, 622102cb92eSjohnny hdlp->ih_inum); 623102cb92eSjohnny } 62470025d76Sjohnny return (DDI_FAILURE); 62570025d76Sjohnny } 62670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 627102cb92eSjohnny "BLOCKENABLE inum %x done\n", hdlp->ih_inum)); 62870025d76Sjohnny } 62970025d76Sjohnny break; 63070025d76Sjohnny case DDI_INTROP_BLOCKDISABLE: 63170025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 63270025d76Sjohnny "BLOCKDISABLE\n")); 63370025d76Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_MSI) { 63470025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "BLOCKDISABLE: not MSI\n")); 63570025d76Sjohnny return (DDI_FAILURE); 63670025d76Sjohnny } 63770025d76Sjohnny 63870025d76Sjohnny /* Check if psm_intr_ops is present */ 63970025d76Sjohnny if (psm_intr_ops == NULL) 64070025d76Sjohnny return (DDI_FAILURE); 64170025d76Sjohnny 642102cb92eSjohnny count = hdlp->ih_scratch1; 643102cb92eSjohnny h_array = (ddi_intr_handle_t *)hdlp->ih_scratch2; 644102cb92eSjohnny for (i = 0; i < count; i++) { 645102cb92eSjohnny hdlp = (ddi_intr_handle_impl_t *)h_array[i]; 646102cb92eSjohnny pci_disable_intr(pdip, rdip, hdlp, hdlp->ih_inum); 64770025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " 648102cb92eSjohnny "BLOCKDISABLE inum %x done\n", hdlp->ih_inum)); 64970025d76Sjohnny } 65070025d76Sjohnny break; 65170025d76Sjohnny case DDI_INTROP_SETMASK: 65270025d76Sjohnny case DDI_INTROP_CLRMASK: 65370025d76Sjohnny /* 65470025d76Sjohnny * First handle in the config space 65570025d76Sjohnny */ 65670025d76Sjohnny if (intr_op == DDI_INTROP_SETMASK) { 65770025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 65870025d76Sjohnny pci_status = pci_msi_set_mask(rdip, 65970025d76Sjohnny hdlp->ih_type, hdlp->ih_inum); 66070025d76Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 66170025d76Sjohnny pci_status = pci_intx_set_mask(rdip); 66270025d76Sjohnny } else { 66370025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 66470025d76Sjohnny pci_status = pci_msi_clr_mask(rdip, 66570025d76Sjohnny hdlp->ih_type, hdlp->ih_inum); 66670025d76Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 66770025d76Sjohnny pci_status = pci_intx_clr_mask(rdip); 66870025d76Sjohnny } 66970025d76Sjohnny 6707ff178cdSJimmy Vetayases /* For MSI/X; no need to check with PSM module */ 67170025d76Sjohnny if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 67270025d76Sjohnny return (pci_status); 67370025d76Sjohnny 67470025d76Sjohnny /* For fixed interrupts only: handle config space first */ 67570025d76Sjohnny if (hdlp->ih_type == DDI_INTR_TYPE_FIXED && 67670025d76Sjohnny pci_status == DDI_SUCCESS) 67770025d76Sjohnny break; 67870025d76Sjohnny 6797ff178cdSJimmy Vetayases /* For fixed interrupts only: confer with PSM module next */ 68070025d76Sjohnny if (psm_intr_ops != NULL) { 68170025d76Sjohnny /* If interrupt is shared; do nothing */ 68270025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 68370025d76Sjohnny PSM_INTR_OP_GET_SHARED, &psm_status); 68470025d76Sjohnny 68570025d76Sjohnny if (psm_rval == PSM_FAILURE || psm_status == 1) 68670025d76Sjohnny return (pci_status); 68770025d76Sjohnny 6887ff178cdSJimmy Vetayases /* Now, PSM module should try to set/clear the mask */ 68970025d76Sjohnny if (intr_op == DDI_INTROP_SETMASK) 69070025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 69170025d76Sjohnny PSM_INTR_OP_SET_MASK, NULL); 69270025d76Sjohnny else 69370025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 69470025d76Sjohnny PSM_INTR_OP_CLEAR_MASK, NULL); 69570025d76Sjohnny } 69670025d76Sjohnny return ((psm_rval == PSM_FAILURE) ? DDI_FAILURE : DDI_SUCCESS); 69770025d76Sjohnny case DDI_INTROP_GETPENDING: 69870025d76Sjohnny /* 69970025d76Sjohnny * First check the config space and/or 70070025d76Sjohnny * MSI capability register(s) 70170025d76Sjohnny */ 70270025d76Sjohnny if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) 70370025d76Sjohnny pci_rval = pci_msi_get_pending(rdip, hdlp->ih_type, 70470025d76Sjohnny hdlp->ih_inum, &pci_status); 70570025d76Sjohnny else if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) 70670025d76Sjohnny pci_rval = pci_intx_get_pending(rdip, &pci_status); 70770025d76Sjohnny 7087ff178cdSJimmy Vetayases /* On failure; next try with PSM module */ 70970025d76Sjohnny if (pci_rval != DDI_SUCCESS && psm_intr_ops != NULL) 71070025d76Sjohnny psm_rval = (*psm_intr_ops)(rdip, hdlp, 71170025d76Sjohnny PSM_INTR_OP_GET_PENDING, &psm_status); 71270025d76Sjohnny 71370025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned " 71470025d76Sjohnny "psm_rval = %x, psm_status = %x, pci_rval = %x, " 71570025d76Sjohnny "pci_status = %x\n", psm_rval, psm_status, pci_rval, 71670025d76Sjohnny pci_status)); 71770025d76Sjohnny if (psm_rval == PSM_FAILURE && pci_rval == DDI_FAILURE) { 71870025d76Sjohnny *(int *)result = 0; 71970025d76Sjohnny return (DDI_FAILURE); 72070025d76Sjohnny } 72170025d76Sjohnny 72270025d76Sjohnny if (psm_rval != PSM_FAILURE) 72370025d76Sjohnny *(int *)result = psm_status; 72470025d76Sjohnny else if (pci_rval != DDI_FAILURE) 72570025d76Sjohnny *(int *)result = pci_status; 72670025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci: GETPENDING returned = %x\n", 72770025d76Sjohnny *(int *)result)); 72870025d76Sjohnny break; 72909b1eac2SEvan Yan case DDI_INTROP_GETTARGET: 73009b1eac2SEvan Yan DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET\n")); 73109b1eac2SEvan Yan 7327ff178cdSJimmy Vetayases bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t)); 7337ff178cdSJimmy Vetayases tmp_hdl.ih_private = (void *)&intrinfo; 7347ff178cdSJimmy Vetayases intrinfo.avgi_req_flags = PSMGI_INTRBY_DEFAULT; 7357ff178cdSJimmy Vetayases intrinfo.avgi_req_flags |= PSMGI_REQ_CPUID; 7367ff178cdSJimmy Vetayases 7377ff178cdSJimmy Vetayases if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_GET_INTR, 7387ff178cdSJimmy Vetayases NULL) == PSM_FAILURE) 73909b1eac2SEvan Yan return (DDI_FAILURE); 7407ff178cdSJimmy Vetayases 7417ff178cdSJimmy Vetayases *(int *)result = intrinfo.avgi_cpu_id; 74209b1eac2SEvan Yan DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: GETTARGET " 7437ff178cdSJimmy Vetayases "vector = 0x%x, cpu = 0x%x\n", hdlp->ih_vector, 7447ff178cdSJimmy Vetayases *(int *)result)); 74509b1eac2SEvan Yan break; 74609b1eac2SEvan Yan case DDI_INTROP_SETTARGET: 74709b1eac2SEvan Yan DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET\n")); 74809b1eac2SEvan Yan 7497ff178cdSJimmy Vetayases bcopy(hdlp, &tmp_hdl, sizeof (ddi_intr_handle_impl_t)); 75009b1eac2SEvan Yan tmp_hdl.ih_private = (void *)(uintptr_t)*(int *)result; 7517ff178cdSJimmy Vetayases tmp_hdl.ih_flags = PSMGI_INTRBY_DEFAULT; 75209b1eac2SEvan Yan 7537ff178cdSJimmy Vetayases if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_SET_CPU, 7547ff178cdSJimmy Vetayases &psm_status) == PSM_FAILURE) 75509b1eac2SEvan Yan return (DDI_FAILURE); 7567ff178cdSJimmy Vetayases 7577ff178cdSJimmy Vetayases hdlp->ih_vector = tmp_hdl.ih_vector; 7587ff178cdSJimmy Vetayases DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: SETTARGET " 7597ff178cdSJimmy Vetayases "vector = 0x%x\n", hdlp->ih_vector)); 76009b1eac2SEvan Yan break; 7617ff178cdSJimmy Vetayases case DDI_INTROP_GETPOOL: 7627ff178cdSJimmy Vetayases /* 7637ff178cdSJimmy Vetayases * For MSI/X interrupts use global IRM pool if available. 7647ff178cdSJimmy Vetayases */ 7657ff178cdSJimmy Vetayases if (apix_irm_pool_p && DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 7667ff178cdSJimmy Vetayases *(ddi_irm_pool_t **)result = apix_irm_pool_p; 7677ff178cdSJimmy Vetayases return (DDI_SUCCESS); 7687ff178cdSJimmy Vetayases } 7697ff178cdSJimmy Vetayases return (DDI_ENOTSUP); 77070025d76Sjohnny default: 77170025d76Sjohnny return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result)); 77270025d76Sjohnny } 77370025d76Sjohnny 77470025d76Sjohnny return (DDI_SUCCESS); 77570025d76Sjohnny } 77670025d76Sjohnny 7777ff178cdSJimmy Vetayases /* 7787ff178cdSJimmy Vetayases * Allocate a vector for FIXED type interrupt. 7797ff178cdSJimmy Vetayases */ 7807ff178cdSJimmy Vetayases int 7817ff178cdSJimmy Vetayases pci_alloc_intr_fixed(dev_info_t *pdip, dev_info_t *rdip, 7827ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *hdlp, void *result) 7837ff178cdSJimmy Vetayases { 7847ff178cdSJimmy Vetayases struct intrspec *ispec; 7857ff178cdSJimmy Vetayases ddi_intr_handle_impl_t info_hdl; 7867ff178cdSJimmy Vetayases int ret; 7877ff178cdSJimmy Vetayases int free_phdl = 0; 7887ff178cdSJimmy Vetayases int pci_rval; 7897ff178cdSJimmy Vetayases int pci_status = 0; 7907ff178cdSJimmy Vetayases apic_get_type_t type_info; 7917ff178cdSJimmy Vetayases 7927ff178cdSJimmy Vetayases if (psm_intr_ops == NULL) 7937ff178cdSJimmy Vetayases return (DDI_FAILURE); 7947ff178cdSJimmy Vetayases 7957ff178cdSJimmy Vetayases /* Figure out if this device supports MASKING */ 7967ff178cdSJimmy Vetayases pci_rval = pci_intx_get_cap(rdip, &pci_status); 7977ff178cdSJimmy Vetayases if (pci_rval == DDI_SUCCESS && pci_status) 7987ff178cdSJimmy Vetayases hdlp->ih_cap |= pci_status; 7997ff178cdSJimmy Vetayases 8007ff178cdSJimmy Vetayases /* 8017ff178cdSJimmy Vetayases * If the PSM module is "APIX" then pass the request for 8027ff178cdSJimmy Vetayases * allocating the vector now. 8037ff178cdSJimmy Vetayases */ 8047ff178cdSJimmy Vetayases bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t)); 8057ff178cdSJimmy Vetayases info_hdl.ih_private = &type_info; 8067ff178cdSJimmy Vetayases if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) == 8077ff178cdSJimmy Vetayases PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) { 8087ff178cdSJimmy Vetayases ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, 8097ff178cdSJimmy Vetayases (int)hdlp->ih_inum); 8107ff178cdSJimmy Vetayases if (ispec == NULL) 8117ff178cdSJimmy Vetayases return (DDI_FAILURE); 8127ff178cdSJimmy Vetayases if (hdlp->ih_private == NULL) { /* allocate phdl structure */ 8137ff178cdSJimmy Vetayases free_phdl = 1; 8147ff178cdSJimmy Vetayases i_ddi_alloc_intr_phdl(hdlp); 8157ff178cdSJimmy Vetayases } 8167ff178cdSJimmy Vetayases ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 8177ff178cdSJimmy Vetayases ret = (*psm_intr_ops)(rdip, hdlp, 8187ff178cdSJimmy Vetayases PSM_INTR_OP_ALLOC_VECTORS, result); 8197ff178cdSJimmy Vetayases if (free_phdl) { /* free up the phdl structure */ 8207ff178cdSJimmy Vetayases free_phdl = 0; 8217ff178cdSJimmy Vetayases i_ddi_free_intr_phdl(hdlp); 8227ff178cdSJimmy Vetayases hdlp->ih_private = NULL; 8237ff178cdSJimmy Vetayases } 8247ff178cdSJimmy Vetayases } else { 8257ff178cdSJimmy Vetayases /* 8267ff178cdSJimmy Vetayases * No APIX module; fall back to the old scheme where the 8277ff178cdSJimmy Vetayases * interrupt vector is allocated during ddi_enable_intr() call. 8287ff178cdSJimmy Vetayases */ 8297ff178cdSJimmy Vetayases *(int *)result = 1; 8307ff178cdSJimmy Vetayases ret = DDI_SUCCESS; 8317ff178cdSJimmy Vetayases } 8327ff178cdSJimmy Vetayases 8337ff178cdSJimmy Vetayases return (ret); 8347ff178cdSJimmy Vetayases } 8357ff178cdSJimmy Vetayases 8367ff178cdSJimmy Vetayases /* 8377ff178cdSJimmy Vetayases * Free up the vector for FIXED (legacy) type interrupt. 8387ff178cdSJimmy Vetayases */ 8397ff178cdSJimmy Vetayases static int 8407ff178cdSJimmy Vetayases pci_free_intr_fixed(dev_info_t *pdip, dev_info_t *rdip, 8417ff178cdSJimmy Vetayases ddi_intr_handle_impl_t *hdlp) 8427ff178cdSJimmy Vetayases { 8437ff178cdSJimmy Vetayases struct intrspec *ispec; 8447ff178cdSJimmy Vetayases ddi_intr_handle_impl_t info_hdl; 8457ff178cdSJimmy Vetayases int ret; 8467ff178cdSJimmy Vetayases apic_get_type_t type_info; 8477ff178cdSJimmy Vetayases 8487ff178cdSJimmy Vetayases if (psm_intr_ops == NULL) 8497ff178cdSJimmy Vetayases return (DDI_FAILURE); 8507ff178cdSJimmy Vetayases 8517ff178cdSJimmy Vetayases /* 8527ff178cdSJimmy Vetayases * If the PSM module is "APIX" then pass the request to it 8537ff178cdSJimmy Vetayases * to free up the vector now. 8547ff178cdSJimmy Vetayases */ 8557ff178cdSJimmy Vetayases bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t)); 8567ff178cdSJimmy Vetayases info_hdl.ih_private = &type_info; 8577ff178cdSJimmy Vetayases if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) == 8587ff178cdSJimmy Vetayases PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) { 8597ff178cdSJimmy Vetayases ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, 8607ff178cdSJimmy Vetayases (int)hdlp->ih_inum); 8617ff178cdSJimmy Vetayases if (ispec == NULL) 8627ff178cdSJimmy Vetayases return (DDI_FAILURE); 8637ff178cdSJimmy Vetayases ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 8647ff178cdSJimmy Vetayases ret = (*psm_intr_ops)(rdip, hdlp, 8657ff178cdSJimmy Vetayases PSM_INTR_OP_FREE_VECTORS, NULL); 8667ff178cdSJimmy Vetayases } else { 8677ff178cdSJimmy Vetayases /* 8687ff178cdSJimmy Vetayases * No APIX module; fall back to the old scheme where 8697ff178cdSJimmy Vetayases * the interrupt vector was already freed during 8707ff178cdSJimmy Vetayases * ddi_disable_intr() call. 8717ff178cdSJimmy Vetayases */ 8727ff178cdSJimmy Vetayases ret = DDI_SUCCESS; 8737ff178cdSJimmy Vetayases } 8747ff178cdSJimmy Vetayases 8757ff178cdSJimmy Vetayases return (ret); 8767ff178cdSJimmy Vetayases } 8777ff178cdSJimmy Vetayases 8787a364d25Sschwartz int 8797a364d25Sschwartz pci_get_intr_from_vecirq(apic_get_intr_t *intrinfo_p, 8807a364d25Sschwartz int vecirq, boolean_t is_irq) 8817a364d25Sschwartz { 8827a364d25Sschwartz ddi_intr_handle_impl_t get_info_ii_hdl; 8837a364d25Sschwartz 8847a364d25Sschwartz if (is_irq) 8857a364d25Sschwartz intrinfo_p->avgi_req_flags |= PSMGI_INTRBY_IRQ; 8867a364d25Sschwartz 8877a364d25Sschwartz /* 8887a364d25Sschwartz * For this locally-declared and used handle, ih_private will contain a 8897a364d25Sschwartz * pointer to apic_get_intr_t, not an ihdl_plat_t as used for 8907a364d25Sschwartz * global interrupt handling. 8917a364d25Sschwartz */ 8927a364d25Sschwartz get_info_ii_hdl.ih_private = intrinfo_p; 8937ff178cdSJimmy Vetayases get_info_ii_hdl.ih_vector = vecirq; 8947a364d25Sschwartz 8957a364d25Sschwartz if ((*psm_intr_ops)(NULL, &get_info_ii_hdl, 8967a364d25Sschwartz PSM_INTR_OP_GET_INTR, NULL) == PSM_FAILURE) 8977a364d25Sschwartz return (DDI_FAILURE); 8987a364d25Sschwartz 8997a364d25Sschwartz return (DDI_SUCCESS); 9007a364d25Sschwartz } 9017a364d25Sschwartz 9027a364d25Sschwartz 9037a364d25Sschwartz int 9047a364d25Sschwartz pci_get_cpu_from_vecirq(int vecirq, boolean_t is_irq) 9057a364d25Sschwartz { 9067a364d25Sschwartz int rval; 9077a364d25Sschwartz apic_get_intr_t intrinfo; 9087ff178cdSJimmy Vetayases 9097a364d25Sschwartz intrinfo.avgi_req_flags = PSMGI_REQ_CPUID; 9107a364d25Sschwartz rval = pci_get_intr_from_vecirq(&intrinfo, vecirq, is_irq); 9117a364d25Sschwartz 9127a364d25Sschwartz if (rval == DDI_SUCCESS) 9137a364d25Sschwartz return (intrinfo.avgi_cpu_id); 9147a364d25Sschwartz else 9157a364d25Sschwartz return (-1); 9167a364d25Sschwartz } 9177a364d25Sschwartz 91870025d76Sjohnny 91970025d76Sjohnny static int 92070025d76Sjohnny pci_enable_intr(dev_info_t *pdip, dev_info_t *rdip, 92170025d76Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 92270025d76Sjohnny { 92370025d76Sjohnny struct intrspec *ispec; 9247a364d25Sschwartz int irq; 9257a364d25Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 92670025d76Sjohnny 92770025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: hdlp %p inum %x\n", 92870025d76Sjohnny (void *)hdlp, inum)); 92970025d76Sjohnny 93070025d76Sjohnny /* Translate the interrupt if needed */ 93170025d76Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 9328d9a0e26Sanish if (ispec == NULL) 9338d9a0e26Sanish return (DDI_FAILURE); 93496f82fefSSophia Li if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 93570025d76Sjohnny ispec->intrspec_vec = inum; 93696f82fefSSophia Li ispec->intrspec_pri = hdlp->ih_pri; 93796f82fefSSophia Li } 9387a364d25Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 93970025d76Sjohnny 94070025d76Sjohnny /* translate the interrupt if needed */ 94186a9c507SGuoli Shu if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq) == 94286a9c507SGuoli Shu PSM_FAILURE) 94386a9c507SGuoli Shu return (DDI_FAILURE); 9447a364d25Sschwartz DDI_INTR_NEXDBG((CE_CONT, "pci_enable_intr: priority=%x irq=%x\n", 9457a364d25Sschwartz hdlp->ih_pri, irq)); 94670025d76Sjohnny 94770025d76Sjohnny /* Add the interrupt handler */ 94870025d76Sjohnny if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, 9497a364d25Sschwartz DEVI(rdip)->devi_name, irq, hdlp->ih_cb_arg1, 9507a364d25Sschwartz hdlp->ih_cb_arg2, &ihdl_plat_datap->ip_ticks, rdip)) 95170025d76Sjohnny return (DDI_FAILURE); 95270025d76Sjohnny 9537ff178cdSJimmy Vetayases hdlp->ih_vector = irq; 9547a364d25Sschwartz 95570025d76Sjohnny return (DDI_SUCCESS); 95670025d76Sjohnny } 95770025d76Sjohnny 95870025d76Sjohnny 95970025d76Sjohnny static void 96070025d76Sjohnny pci_disable_intr(dev_info_t *pdip, dev_info_t *rdip, 96170025d76Sjohnny ddi_intr_handle_impl_t *hdlp, uint32_t inum) 96270025d76Sjohnny { 9637a364d25Sschwartz int irq; 96470025d76Sjohnny struct intrspec *ispec; 9657a364d25Sschwartz ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private; 96670025d76Sjohnny 96770025d76Sjohnny DDI_INTR_NEXDBG((CE_CONT, "pci_disable_intr: \n")); 96870025d76Sjohnny ispec = (struct intrspec *)pci_intx_get_ispec(pdip, rdip, (int)inum); 9698d9a0e26Sanish if (ispec == NULL) 9708d9a0e26Sanish return; 97196f82fefSSophia Li if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { 97270025d76Sjohnny ispec->intrspec_vec = inum; 97396f82fefSSophia Li ispec->intrspec_pri = hdlp->ih_pri; 97496f82fefSSophia Li } 9757a364d25Sschwartz ihdl_plat_datap->ip_ispecp = ispec; 97670025d76Sjohnny 97770025d76Sjohnny /* translate the interrupt if needed */ 9787a364d25Sschwartz (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &irq); 97970025d76Sjohnny 98070025d76Sjohnny /* Disable the interrupt handler */ 9817a364d25Sschwartz rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, irq); 9827a364d25Sschwartz ihdl_plat_datap->ip_ispecp = NULL; 98370025d76Sjohnny } 98470025d76Sjohnny 98570025d76Sjohnny /* 98670025d76Sjohnny * Miscellaneous library function 98770025d76Sjohnny */ 98870025d76Sjohnny int 98970025d76Sjohnny pci_common_get_reg_prop(dev_info_t *dip, pci_regspec_t *pci_rp) 99070025d76Sjohnny { 99170025d76Sjohnny int i; 99270025d76Sjohnny int number; 99370025d76Sjohnny int assigned_addr_len; 99470025d76Sjohnny uint_t phys_hi = pci_rp->pci_phys_hi; 99570025d76Sjohnny pci_regspec_t *assigned_addr; 99670025d76Sjohnny 99770025d76Sjohnny if (((phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) || 99870025d76Sjohnny (phys_hi & PCI_RELOCAT_B)) 99970025d76Sjohnny return (DDI_SUCCESS); 100070025d76Sjohnny 100170025d76Sjohnny /* 100270025d76Sjohnny * the "reg" property specifies relocatable, get and interpret the 100370025d76Sjohnny * "assigned-addresses" property. 100470025d76Sjohnny */ 100570025d76Sjohnny if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 100670025d76Sjohnny "assigned-addresses", (int **)&assigned_addr, 100770025d76Sjohnny (uint_t *)&assigned_addr_len) != DDI_PROP_SUCCESS) 100870025d76Sjohnny return (DDI_FAILURE); 100970025d76Sjohnny 101070025d76Sjohnny /* 101170025d76Sjohnny * Scan the "assigned-addresses" for one that matches the specified 101270025d76Sjohnny * "reg" property entry. 101370025d76Sjohnny */ 101470025d76Sjohnny phys_hi &= PCI_CONF_ADDR_MASK; 101570025d76Sjohnny number = assigned_addr_len / (sizeof (pci_regspec_t) / sizeof (int)); 101670025d76Sjohnny for (i = 0; i < number; i++) { 101770025d76Sjohnny if ((assigned_addr[i].pci_phys_hi & PCI_CONF_ADDR_MASK) == 101870025d76Sjohnny phys_hi) { 101970025d76Sjohnny pci_rp->pci_phys_mid = assigned_addr[i].pci_phys_mid; 102070025d76Sjohnny pci_rp->pci_phys_low = assigned_addr[i].pci_phys_low; 102170025d76Sjohnny ddi_prop_free(assigned_addr); 102270025d76Sjohnny return (DDI_SUCCESS); 102370025d76Sjohnny } 102470025d76Sjohnny } 102570025d76Sjohnny 102670025d76Sjohnny ddi_prop_free(assigned_addr); 102770025d76Sjohnny return (DDI_FAILURE); 102870025d76Sjohnny } 102970025d76Sjohnny 103070025d76Sjohnny 103170025d76Sjohnny /* 103226947304SEvan Yan * To handle PCI tool ioctls 103370025d76Sjohnny */ 103470025d76Sjohnny 103526947304SEvan Yan /*ARGSUSED*/ 103670025d76Sjohnny int 103770025d76Sjohnny pci_common_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, 103870025d76Sjohnny int mode, cred_t *credp, int *rvalp) 103970025d76Sjohnny { 104026947304SEvan Yan minor_t minor = getminor(dev); 104170025d76Sjohnny int rv = ENOTTY; 104270025d76Sjohnny 104326947304SEvan Yan switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) { 104470025d76Sjohnny case PCI_TOOL_REG_MINOR_NUM: 104570025d76Sjohnny 104670025d76Sjohnny switch (cmd) { 104770025d76Sjohnny case PCITOOL_DEVICE_SET_REG: 104870025d76Sjohnny case PCITOOL_DEVICE_GET_REG: 104970025d76Sjohnny 105070025d76Sjohnny /* Require full privileges. */ 105170025d76Sjohnny if (secpolicy_kmdb(credp)) 105270025d76Sjohnny rv = EPERM; 105370025d76Sjohnny else 105470025d76Sjohnny rv = pcitool_dev_reg_ops(dip, (void *)arg, 105570025d76Sjohnny cmd, mode); 105670025d76Sjohnny break; 105770025d76Sjohnny 105870025d76Sjohnny case PCITOOL_NEXUS_SET_REG: 105970025d76Sjohnny case PCITOOL_NEXUS_GET_REG: 106070025d76Sjohnny 106170025d76Sjohnny /* Require full privileges. */ 106270025d76Sjohnny if (secpolicy_kmdb(credp)) 106370025d76Sjohnny rv = EPERM; 106470025d76Sjohnny else 106570025d76Sjohnny rv = pcitool_bus_reg_ops(dip, (void *)arg, 106670025d76Sjohnny cmd, mode); 106770025d76Sjohnny break; 106870025d76Sjohnny } 106970025d76Sjohnny break; 107070025d76Sjohnny 107170025d76Sjohnny case PCI_TOOL_INTR_MINOR_NUM: 107270025d76Sjohnny 107370025d76Sjohnny switch (cmd) { 107470025d76Sjohnny case PCITOOL_DEVICE_SET_INTR: 107570025d76Sjohnny 107670025d76Sjohnny /* Require PRIV_SYS_RES_CONFIG, same as psradm */ 107770025d76Sjohnny if (secpolicy_ponline(credp)) { 107870025d76Sjohnny rv = EPERM; 107970025d76Sjohnny break; 108070025d76Sjohnny } 108170025d76Sjohnny 108270025d76Sjohnny /*FALLTHRU*/ 108370025d76Sjohnny /* These require no special privileges. */ 108470025d76Sjohnny case PCITOOL_DEVICE_GET_INTR: 10852917a9c9Sschwartz case PCITOOL_SYSTEM_INTR_INFO: 108670025d76Sjohnny rv = pcitool_intr_admn(dip, (void *)arg, cmd, mode); 108770025d76Sjohnny break; 108870025d76Sjohnny } 108970025d76Sjohnny break; 109070025d76Sjohnny 109170025d76Sjohnny default: 109270025d76Sjohnny break; 109370025d76Sjohnny } 109470025d76Sjohnny 109570025d76Sjohnny return (rv); 109670025d76Sjohnny } 1097649d4cceSanish 1098649d4cceSanish 109900d0963fSdilpreet int 110000d0963fSdilpreet pci_common_ctlops_poke(peekpoke_ctlops_t *in_args) 110100d0963fSdilpreet { 110200d0963fSdilpreet size_t size = in_args->size; 110300d0963fSdilpreet uintptr_t dev_addr = in_args->dev_addr; 110400d0963fSdilpreet uintptr_t host_addr = in_args->host_addr; 110500d0963fSdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 110600d0963fSdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 110700d0963fSdilpreet size_t repcount = in_args->repcount; 110800d0963fSdilpreet uint_t flags = in_args->flags; 110900d0963fSdilpreet int err = DDI_SUCCESS; 111000d0963fSdilpreet 111100d0963fSdilpreet /* 111200d0963fSdilpreet * if no handle then this is a poke. We have to return failure here 111300d0963fSdilpreet * as we have no way of knowing whether this is a MEM or IO space access 111400d0963fSdilpreet */ 111500d0963fSdilpreet if (in_args->handle == NULL) 111600d0963fSdilpreet return (DDI_FAILURE); 111700d0963fSdilpreet 111800d0963fSdilpreet /* 111900d0963fSdilpreet * rest of this function is actually for cautious puts 112000d0963fSdilpreet */ 112100d0963fSdilpreet for (; repcount; repcount--) { 112200d0963fSdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 112300d0963fSdilpreet switch (size) { 112400d0963fSdilpreet case sizeof (uint8_t): 112500d0963fSdilpreet pci_config_wr8(hp, (uint8_t *)dev_addr, 112600d0963fSdilpreet *(uint8_t *)host_addr); 112700d0963fSdilpreet break; 112800d0963fSdilpreet case sizeof (uint16_t): 112900d0963fSdilpreet pci_config_wr16(hp, (uint16_t *)dev_addr, 113000d0963fSdilpreet *(uint16_t *)host_addr); 113100d0963fSdilpreet break; 113200d0963fSdilpreet case sizeof (uint32_t): 113300d0963fSdilpreet pci_config_wr32(hp, (uint32_t *)dev_addr, 113400d0963fSdilpreet *(uint32_t *)host_addr); 113500d0963fSdilpreet break; 113600d0963fSdilpreet case sizeof (uint64_t): 113700d0963fSdilpreet pci_config_wr64(hp, (uint64_t *)dev_addr, 113800d0963fSdilpreet *(uint64_t *)host_addr); 113900d0963fSdilpreet break; 114000d0963fSdilpreet default: 114100d0963fSdilpreet err = DDI_FAILURE; 114200d0963fSdilpreet break; 114300d0963fSdilpreet } 114400d0963fSdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 114500d0963fSdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 114600d0963fSdilpreet DDI_STRUCTURE_BE_ACC) { 114700d0963fSdilpreet switch (size) { 114800d0963fSdilpreet case sizeof (uint8_t): 114900d0963fSdilpreet i_ddi_io_put8(hp, 115000d0963fSdilpreet (uint8_t *)dev_addr, 115100d0963fSdilpreet *(uint8_t *)host_addr); 115200d0963fSdilpreet break; 115300d0963fSdilpreet case sizeof (uint16_t): 115400d0963fSdilpreet i_ddi_io_swap_put16(hp, 115500d0963fSdilpreet (uint16_t *)dev_addr, 115600d0963fSdilpreet *(uint16_t *)host_addr); 115700d0963fSdilpreet break; 115800d0963fSdilpreet case sizeof (uint32_t): 115900d0963fSdilpreet i_ddi_io_swap_put32(hp, 116000d0963fSdilpreet (uint32_t *)dev_addr, 116100d0963fSdilpreet *(uint32_t *)host_addr); 116200d0963fSdilpreet break; 116300d0963fSdilpreet /* 116400d0963fSdilpreet * note the 64-bit case is a dummy 116500d0963fSdilpreet * function - so no need to swap 116600d0963fSdilpreet */ 116700d0963fSdilpreet case sizeof (uint64_t): 116800d0963fSdilpreet i_ddi_io_put64(hp, 116900d0963fSdilpreet (uint64_t *)dev_addr, 117000d0963fSdilpreet *(uint64_t *)host_addr); 117100d0963fSdilpreet break; 117200d0963fSdilpreet default: 117300d0963fSdilpreet err = DDI_FAILURE; 117400d0963fSdilpreet break; 117500d0963fSdilpreet } 117600d0963fSdilpreet } else { 117700d0963fSdilpreet switch (size) { 117800d0963fSdilpreet case sizeof (uint8_t): 117900d0963fSdilpreet i_ddi_io_put8(hp, 118000d0963fSdilpreet (uint8_t *)dev_addr, 118100d0963fSdilpreet *(uint8_t *)host_addr); 118200d0963fSdilpreet break; 118300d0963fSdilpreet case sizeof (uint16_t): 118400d0963fSdilpreet i_ddi_io_put16(hp, 118500d0963fSdilpreet (uint16_t *)dev_addr, 118600d0963fSdilpreet *(uint16_t *)host_addr); 118700d0963fSdilpreet break; 118800d0963fSdilpreet case sizeof (uint32_t): 118900d0963fSdilpreet i_ddi_io_put32(hp, 119000d0963fSdilpreet (uint32_t *)dev_addr, 119100d0963fSdilpreet *(uint32_t *)host_addr); 119200d0963fSdilpreet break; 119300d0963fSdilpreet case sizeof (uint64_t): 119400d0963fSdilpreet i_ddi_io_put64(hp, 119500d0963fSdilpreet (uint64_t *)dev_addr, 119600d0963fSdilpreet *(uint64_t *)host_addr); 119700d0963fSdilpreet break; 119800d0963fSdilpreet default: 119900d0963fSdilpreet err = DDI_FAILURE; 120000d0963fSdilpreet break; 120100d0963fSdilpreet } 120200d0963fSdilpreet } 120300d0963fSdilpreet } else { 120400d0963fSdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 120500d0963fSdilpreet DDI_STRUCTURE_BE_ACC) { 120600d0963fSdilpreet switch (size) { 120700d0963fSdilpreet case sizeof (uint8_t): 120800d0963fSdilpreet *(uint8_t *)dev_addr = 120900d0963fSdilpreet *(uint8_t *)host_addr; 121000d0963fSdilpreet break; 121100d0963fSdilpreet case sizeof (uint16_t): 121200d0963fSdilpreet *(uint16_t *)dev_addr = 121300d0963fSdilpreet ddi_swap16(*(uint16_t *)host_addr); 121400d0963fSdilpreet break; 121500d0963fSdilpreet case sizeof (uint32_t): 121600d0963fSdilpreet *(uint32_t *)dev_addr = 121700d0963fSdilpreet ddi_swap32(*(uint32_t *)host_addr); 121800d0963fSdilpreet break; 121900d0963fSdilpreet case sizeof (uint64_t): 122000d0963fSdilpreet *(uint64_t *)dev_addr = 122100d0963fSdilpreet ddi_swap64(*(uint64_t *)host_addr); 122200d0963fSdilpreet break; 122300d0963fSdilpreet default: 122400d0963fSdilpreet err = DDI_FAILURE; 122500d0963fSdilpreet break; 122600d0963fSdilpreet } 122700d0963fSdilpreet } else { 122800d0963fSdilpreet switch (size) { 122900d0963fSdilpreet case sizeof (uint8_t): 123000d0963fSdilpreet *(uint8_t *)dev_addr = 123100d0963fSdilpreet *(uint8_t *)host_addr; 123200d0963fSdilpreet break; 123300d0963fSdilpreet case sizeof (uint16_t): 123400d0963fSdilpreet *(uint16_t *)dev_addr = 123500d0963fSdilpreet *(uint16_t *)host_addr; 123600d0963fSdilpreet break; 123700d0963fSdilpreet case sizeof (uint32_t): 123800d0963fSdilpreet *(uint32_t *)dev_addr = 123900d0963fSdilpreet *(uint32_t *)host_addr; 124000d0963fSdilpreet break; 124100d0963fSdilpreet case sizeof (uint64_t): 124200d0963fSdilpreet *(uint64_t *)dev_addr = 124300d0963fSdilpreet *(uint64_t *)host_addr; 124400d0963fSdilpreet break; 124500d0963fSdilpreet default: 124600d0963fSdilpreet err = DDI_FAILURE; 124700d0963fSdilpreet break; 124800d0963fSdilpreet } 124900d0963fSdilpreet } 125000d0963fSdilpreet } 125100d0963fSdilpreet host_addr += size; 125200d0963fSdilpreet if (flags == DDI_DEV_AUTOINCR) 125300d0963fSdilpreet dev_addr += size; 125400d0963fSdilpreet } 125500d0963fSdilpreet return (err); 125600d0963fSdilpreet } 125700d0963fSdilpreet 125800d0963fSdilpreet 125900d0963fSdilpreet int 126000d0963fSdilpreet pci_fm_acc_setup(ddi_acc_hdl_t *hp, off_t offset, off_t len) 126100d0963fSdilpreet { 126200d0963fSdilpreet ddi_acc_impl_t *ap = (ddi_acc_impl_t *)hp->ah_platform_private; 126300d0963fSdilpreet 126400d0963fSdilpreet /* endian-ness check */ 126500d0963fSdilpreet if (hp->ah_acc.devacc_attr_endian_flags == DDI_STRUCTURE_BE_ACC) 126600d0963fSdilpreet return (DDI_FAILURE); 126700d0963fSdilpreet 126800d0963fSdilpreet /* 126900d0963fSdilpreet * range check 127000d0963fSdilpreet */ 127100d0963fSdilpreet if ((offset >= PCI_CONF_HDR_SIZE) || 127200d0963fSdilpreet (len > PCI_CONF_HDR_SIZE) || 127300d0963fSdilpreet (offset + len > PCI_CONF_HDR_SIZE)) 127400d0963fSdilpreet return (DDI_FAILURE); 127500d0963fSdilpreet 127600d0963fSdilpreet ap->ahi_acc_attr |= DDI_ACCATTR_CONFIG_SPACE; 127700d0963fSdilpreet /* 127800d0963fSdilpreet * always use cautious mechanism for config space gets 127900d0963fSdilpreet */ 128000d0963fSdilpreet ap->ahi_get8 = i_ddi_caut_get8; 128100d0963fSdilpreet ap->ahi_get16 = i_ddi_caut_get16; 128200d0963fSdilpreet ap->ahi_get32 = i_ddi_caut_get32; 128300d0963fSdilpreet ap->ahi_get64 = i_ddi_caut_get64; 128400d0963fSdilpreet ap->ahi_rep_get8 = i_ddi_caut_rep_get8; 128500d0963fSdilpreet ap->ahi_rep_get16 = i_ddi_caut_rep_get16; 128600d0963fSdilpreet ap->ahi_rep_get32 = i_ddi_caut_rep_get32; 128700d0963fSdilpreet ap->ahi_rep_get64 = i_ddi_caut_rep_get64; 128800d0963fSdilpreet if (hp->ah_acc.devacc_attr_access == DDI_CAUTIOUS_ACC) { 128900d0963fSdilpreet ap->ahi_put8 = i_ddi_caut_put8; 129000d0963fSdilpreet ap->ahi_put16 = i_ddi_caut_put16; 129100d0963fSdilpreet ap->ahi_put32 = i_ddi_caut_put32; 129200d0963fSdilpreet ap->ahi_put64 = i_ddi_caut_put64; 129300d0963fSdilpreet ap->ahi_rep_put8 = i_ddi_caut_rep_put8; 129400d0963fSdilpreet ap->ahi_rep_put16 = i_ddi_caut_rep_put16; 129500d0963fSdilpreet ap->ahi_rep_put32 = i_ddi_caut_rep_put32; 129600d0963fSdilpreet ap->ahi_rep_put64 = i_ddi_caut_rep_put64; 129700d0963fSdilpreet } else { 129800d0963fSdilpreet ap->ahi_put8 = pci_config_wr8; 129900d0963fSdilpreet ap->ahi_put16 = pci_config_wr16; 130000d0963fSdilpreet ap->ahi_put32 = pci_config_wr32; 130100d0963fSdilpreet ap->ahi_put64 = pci_config_wr64; 130200d0963fSdilpreet ap->ahi_rep_put8 = pci_config_rep_wr8; 130300d0963fSdilpreet ap->ahi_rep_put16 = pci_config_rep_wr16; 130400d0963fSdilpreet ap->ahi_rep_put32 = pci_config_rep_wr32; 130500d0963fSdilpreet ap->ahi_rep_put64 = pci_config_rep_wr64; 130600d0963fSdilpreet } 130700d0963fSdilpreet 130800d0963fSdilpreet /* Initialize to default check/notify functions */ 130900d0963fSdilpreet ap->ahi_fault_check = i_ddi_acc_fault_check; 131000d0963fSdilpreet ap->ahi_fault_notify = i_ddi_acc_fault_notify; 131100d0963fSdilpreet ap->ahi_fault = 0; 131200d0963fSdilpreet impl_acc_err_init(hp); 131300d0963fSdilpreet return (DDI_SUCCESS); 131400d0963fSdilpreet } 131500d0963fSdilpreet 131600d0963fSdilpreet 131700d0963fSdilpreet int 131800d0963fSdilpreet pci_common_ctlops_peek(peekpoke_ctlops_t *in_args) 131900d0963fSdilpreet { 132000d0963fSdilpreet size_t size = in_args->size; 132100d0963fSdilpreet uintptr_t dev_addr = in_args->dev_addr; 132200d0963fSdilpreet uintptr_t host_addr = in_args->host_addr; 132300d0963fSdilpreet ddi_acc_impl_t *hp = (ddi_acc_impl_t *)in_args->handle; 132400d0963fSdilpreet ddi_acc_hdl_t *hdlp = (ddi_acc_hdl_t *)in_args->handle; 132500d0963fSdilpreet size_t repcount = in_args->repcount; 132600d0963fSdilpreet uint_t flags = in_args->flags; 132700d0963fSdilpreet int err = DDI_SUCCESS; 132800d0963fSdilpreet 132900d0963fSdilpreet /* 133000d0963fSdilpreet * if no handle then this is a peek. We have to return failure here 133100d0963fSdilpreet * as we have no way of knowing whether this is a MEM or IO space access 133200d0963fSdilpreet */ 133300d0963fSdilpreet if (in_args->handle == NULL) 133400d0963fSdilpreet return (DDI_FAILURE); 133500d0963fSdilpreet 133600d0963fSdilpreet for (; repcount; repcount--) { 133700d0963fSdilpreet if (hp->ahi_acc_attr == DDI_ACCATTR_CONFIG_SPACE) { 133800d0963fSdilpreet switch (size) { 133900d0963fSdilpreet case sizeof (uint8_t): 134000d0963fSdilpreet *(uint8_t *)host_addr = pci_config_rd8(hp, 134100d0963fSdilpreet (uint8_t *)dev_addr); 134200d0963fSdilpreet break; 134300d0963fSdilpreet case sizeof (uint16_t): 134400d0963fSdilpreet *(uint16_t *)host_addr = pci_config_rd16(hp, 134500d0963fSdilpreet (uint16_t *)dev_addr); 134600d0963fSdilpreet break; 134700d0963fSdilpreet case sizeof (uint32_t): 134800d0963fSdilpreet *(uint32_t *)host_addr = pci_config_rd32(hp, 134900d0963fSdilpreet (uint32_t *)dev_addr); 135000d0963fSdilpreet break; 135100d0963fSdilpreet case sizeof (uint64_t): 135200d0963fSdilpreet *(uint64_t *)host_addr = pci_config_rd64(hp, 135300d0963fSdilpreet (uint64_t *)dev_addr); 135400d0963fSdilpreet break; 135500d0963fSdilpreet default: 135600d0963fSdilpreet err = DDI_FAILURE; 135700d0963fSdilpreet break; 135800d0963fSdilpreet } 135900d0963fSdilpreet } else if (hp->ahi_acc_attr & DDI_ACCATTR_IO_SPACE) { 136000d0963fSdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 136100d0963fSdilpreet DDI_STRUCTURE_BE_ACC) { 136200d0963fSdilpreet switch (size) { 136300d0963fSdilpreet case sizeof (uint8_t): 136400d0963fSdilpreet *(uint8_t *)host_addr = 136500d0963fSdilpreet i_ddi_io_get8(hp, 136600d0963fSdilpreet (uint8_t *)dev_addr); 136700d0963fSdilpreet break; 136800d0963fSdilpreet case sizeof (uint16_t): 136900d0963fSdilpreet *(uint16_t *)host_addr = 137000d0963fSdilpreet i_ddi_io_swap_get16(hp, 137100d0963fSdilpreet (uint16_t *)dev_addr); 137200d0963fSdilpreet break; 137300d0963fSdilpreet case sizeof (uint32_t): 137400d0963fSdilpreet *(uint32_t *)host_addr = 137500d0963fSdilpreet i_ddi_io_swap_get32(hp, 137600d0963fSdilpreet (uint32_t *)dev_addr); 137700d0963fSdilpreet break; 137800d0963fSdilpreet /* 137900d0963fSdilpreet * note the 64-bit case is a dummy 138000d0963fSdilpreet * function - so no need to swap 138100d0963fSdilpreet */ 138200d0963fSdilpreet case sizeof (uint64_t): 138300d0963fSdilpreet *(uint64_t *)host_addr = 138400d0963fSdilpreet i_ddi_io_get64(hp, 138500d0963fSdilpreet (uint64_t *)dev_addr); 138600d0963fSdilpreet break; 138700d0963fSdilpreet default: 138800d0963fSdilpreet err = DDI_FAILURE; 138900d0963fSdilpreet break; 139000d0963fSdilpreet } 139100d0963fSdilpreet } else { 139200d0963fSdilpreet switch (size) { 139300d0963fSdilpreet case sizeof (uint8_t): 139400d0963fSdilpreet *(uint8_t *)host_addr = 139500d0963fSdilpreet i_ddi_io_get8(hp, 139600d0963fSdilpreet (uint8_t *)dev_addr); 139700d0963fSdilpreet break; 139800d0963fSdilpreet case sizeof (uint16_t): 139900d0963fSdilpreet *(uint16_t *)host_addr = 140000d0963fSdilpreet i_ddi_io_get16(hp, 140100d0963fSdilpreet (uint16_t *)dev_addr); 140200d0963fSdilpreet break; 140300d0963fSdilpreet case sizeof (uint32_t): 140400d0963fSdilpreet *(uint32_t *)host_addr = 140500d0963fSdilpreet i_ddi_io_get32(hp, 140600d0963fSdilpreet (uint32_t *)dev_addr); 140700d0963fSdilpreet break; 140800d0963fSdilpreet case sizeof (uint64_t): 140900d0963fSdilpreet *(uint64_t *)host_addr = 141000d0963fSdilpreet i_ddi_io_get64(hp, 141100d0963fSdilpreet (uint64_t *)dev_addr); 141200d0963fSdilpreet break; 141300d0963fSdilpreet default: 141400d0963fSdilpreet err = DDI_FAILURE; 141500d0963fSdilpreet break; 141600d0963fSdilpreet } 141700d0963fSdilpreet } 141800d0963fSdilpreet } else { 141900d0963fSdilpreet if (hdlp->ah_acc.devacc_attr_endian_flags == 142000d0963fSdilpreet DDI_STRUCTURE_BE_ACC) { 142100d0963fSdilpreet switch (in_args->size) { 142200d0963fSdilpreet case sizeof (uint8_t): 142300d0963fSdilpreet *(uint8_t *)host_addr = 142400d0963fSdilpreet *(uint8_t *)dev_addr; 142500d0963fSdilpreet break; 142600d0963fSdilpreet case sizeof (uint16_t): 142700d0963fSdilpreet *(uint16_t *)host_addr = 142800d0963fSdilpreet ddi_swap16(*(uint16_t *)dev_addr); 142900d0963fSdilpreet break; 143000d0963fSdilpreet case sizeof (uint32_t): 143100d0963fSdilpreet *(uint32_t *)host_addr = 143200d0963fSdilpreet ddi_swap32(*(uint32_t *)dev_addr); 143300d0963fSdilpreet break; 143400d0963fSdilpreet case sizeof (uint64_t): 143500d0963fSdilpreet *(uint64_t *)host_addr = 143600d0963fSdilpreet ddi_swap64(*(uint64_t *)dev_addr); 143700d0963fSdilpreet break; 143800d0963fSdilpreet default: 143900d0963fSdilpreet err = DDI_FAILURE; 144000d0963fSdilpreet break; 144100d0963fSdilpreet } 144200d0963fSdilpreet } else { 144300d0963fSdilpreet switch (in_args->size) { 144400d0963fSdilpreet case sizeof (uint8_t): 144500d0963fSdilpreet *(uint8_t *)host_addr = 144600d0963fSdilpreet *(uint8_t *)dev_addr; 144700d0963fSdilpreet break; 144800d0963fSdilpreet case sizeof (uint16_t): 144900d0963fSdilpreet *(uint16_t *)host_addr = 145000d0963fSdilpreet *(uint16_t *)dev_addr; 145100d0963fSdilpreet break; 145200d0963fSdilpreet case sizeof (uint32_t): 145300d0963fSdilpreet *(uint32_t *)host_addr = 145400d0963fSdilpreet *(uint32_t *)dev_addr; 145500d0963fSdilpreet break; 145600d0963fSdilpreet case sizeof (uint64_t): 145700d0963fSdilpreet *(uint64_t *)host_addr = 145800d0963fSdilpreet *(uint64_t *)dev_addr; 145900d0963fSdilpreet break; 146000d0963fSdilpreet default: 146100d0963fSdilpreet err = DDI_FAILURE; 146200d0963fSdilpreet break; 146300d0963fSdilpreet } 146400d0963fSdilpreet } 146500d0963fSdilpreet } 146600d0963fSdilpreet host_addr += size; 146700d0963fSdilpreet if (flags == DDI_DEV_AUTOINCR) 146800d0963fSdilpreet dev_addr += size; 146900d0963fSdilpreet } 147000d0963fSdilpreet return (err); 147100d0963fSdilpreet } 147200d0963fSdilpreet 147300d0963fSdilpreet /*ARGSUSED*/ 147400d0963fSdilpreet int 147500d0963fSdilpreet pci_common_peekpoke(dev_info_t *dip, dev_info_t *rdip, 147600d0963fSdilpreet ddi_ctl_enum_t ctlop, void *arg, void *result) 147700d0963fSdilpreet { 147800d0963fSdilpreet if (ctlop == DDI_CTLOPS_PEEK) 147900d0963fSdilpreet return (pci_common_ctlops_peek((peekpoke_ctlops_t *)arg)); 148000d0963fSdilpreet else 148100d0963fSdilpreet return (pci_common_ctlops_poke((peekpoke_ctlops_t *)arg)); 148200d0963fSdilpreet } 148300d0963fSdilpreet 1484649d4cceSanish /* 1485649d4cceSanish * These are the get and put functions to be shared with drivers. The 1486649d4cceSanish * mutex locking is done inside the functions referenced, rather than 1487649d4cceSanish * here, and is thus shared across PCI child drivers and any other 1488649d4cceSanish * consumers of PCI config space (such as the ACPI subsystem). 1489649d4cceSanish * 1490649d4cceSanish * The configuration space addresses come in as pointers. This is fine on 1491649d4cceSanish * a 32-bit system, where the VM space and configuration space are the same 1492649d4cceSanish * size. It's not such a good idea on a 64-bit system, where memory 1493649d4cceSanish * addresses are twice as large as configuration space addresses. At some 1494649d4cceSanish * point in the call tree we need to take a stand and say "you are 32-bit 1495649d4cceSanish * from this time forth", and this seems like a nice self-contained place. 1496649d4cceSanish */ 1497649d4cceSanish 1498649d4cceSanish uint8_t 1499649d4cceSanish pci_config_rd8(ddi_acc_impl_t *hdlp, uint8_t *addr) 1500649d4cceSanish { 1501649d4cceSanish pci_acc_cfblk_t *cfp; 1502649d4cceSanish uint8_t rval; 1503649d4cceSanish int reg; 1504649d4cceSanish 1505649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0); 1506649d4cceSanish 1507649d4cceSanish reg = (int)(uintptr_t)addr; 1508649d4cceSanish 1509649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1510649d4cceSanish 1511649d4cceSanish rval = (*pci_getb_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 1512649d4cceSanish reg); 1513649d4cceSanish 1514649d4cceSanish return (rval); 1515649d4cceSanish } 1516649d4cceSanish 1517649d4cceSanish void 1518649d4cceSanish pci_config_rep_rd8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1519649d4cceSanish uint8_t *dev_addr, size_t repcount, uint_t flags) 1520649d4cceSanish { 1521649d4cceSanish uint8_t *h, *d; 1522649d4cceSanish 1523649d4cceSanish h = host_addr; 1524649d4cceSanish d = dev_addr; 1525649d4cceSanish 1526649d4cceSanish if (flags == DDI_DEV_AUTOINCR) 1527649d4cceSanish for (; repcount; repcount--) 1528649d4cceSanish *h++ = pci_config_rd8(hdlp, d++); 1529649d4cceSanish else 1530649d4cceSanish for (; repcount; repcount--) 1531649d4cceSanish *h++ = pci_config_rd8(hdlp, d); 1532649d4cceSanish } 1533649d4cceSanish 1534649d4cceSanish uint16_t 1535649d4cceSanish pci_config_rd16(ddi_acc_impl_t *hdlp, uint16_t *addr) 1536649d4cceSanish { 1537649d4cceSanish pci_acc_cfblk_t *cfp; 1538649d4cceSanish uint16_t rval; 1539649d4cceSanish int reg; 1540649d4cceSanish 1541649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0); 1542649d4cceSanish 1543649d4cceSanish reg = (int)(uintptr_t)addr; 1544649d4cceSanish 1545649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1546649d4cceSanish 1547649d4cceSanish rval = (*pci_getw_func)(cfp->c_busnum, cfp->c_devnum, cfp->c_funcnum, 1548649d4cceSanish reg); 1549649d4cceSanish 1550649d4cceSanish return (rval); 1551649d4cceSanish } 1552649d4cceSanish 1553649d4cceSanish void 1554649d4cceSanish pci_config_rep_rd16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1555649d4cceSanish uint16_t *dev_addr, size_t repcount, uint_t flags) 1556649d4cceSanish { 1557649d4cceSanish uint16_t *h, *d; 1558649d4cceSanish 1559649d4cceSanish h = host_addr; 1560649d4cceSanish d = dev_addr; 1561649d4cceSanish 1562649d4cceSanish if (flags == DDI_DEV_AUTOINCR) 1563649d4cceSanish for (; repcount; repcount--) 1564649d4cceSanish *h++ = pci_config_rd16(hdlp, d++); 1565649d4cceSanish else 1566649d4cceSanish for (; repcount; repcount--) 1567649d4cceSanish *h++ = pci_config_rd16(hdlp, d); 1568649d4cceSanish } 1569649d4cceSanish 1570649d4cceSanish uint32_t 1571649d4cceSanish pci_config_rd32(ddi_acc_impl_t *hdlp, uint32_t *addr) 1572649d4cceSanish { 1573649d4cceSanish pci_acc_cfblk_t *cfp; 1574649d4cceSanish uint32_t rval; 1575649d4cceSanish int reg; 1576649d4cceSanish 1577649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0); 1578649d4cceSanish 1579649d4cceSanish reg = (int)(uintptr_t)addr; 1580649d4cceSanish 1581649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1582649d4cceSanish 1583649d4cceSanish rval = (*pci_getl_func)(cfp->c_busnum, cfp->c_devnum, 1584649d4cceSanish cfp->c_funcnum, reg); 1585649d4cceSanish 1586649d4cceSanish return (rval); 1587649d4cceSanish } 1588649d4cceSanish 1589649d4cceSanish void 1590649d4cceSanish pci_config_rep_rd32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1591649d4cceSanish uint32_t *dev_addr, size_t repcount, uint_t flags) 1592649d4cceSanish { 1593649d4cceSanish uint32_t *h, *d; 1594649d4cceSanish 1595649d4cceSanish h = host_addr; 1596649d4cceSanish d = dev_addr; 1597649d4cceSanish 1598649d4cceSanish if (flags == DDI_DEV_AUTOINCR) 1599649d4cceSanish for (; repcount; repcount--) 1600649d4cceSanish *h++ = pci_config_rd32(hdlp, d++); 1601649d4cceSanish else 1602649d4cceSanish for (; repcount; repcount--) 1603649d4cceSanish *h++ = pci_config_rd32(hdlp, d); 1604649d4cceSanish } 1605649d4cceSanish 1606649d4cceSanish 1607649d4cceSanish void 1608649d4cceSanish pci_config_wr8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value) 1609649d4cceSanish { 1610649d4cceSanish pci_acc_cfblk_t *cfp; 1611649d4cceSanish int reg; 1612649d4cceSanish 1613649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0); 1614649d4cceSanish 1615649d4cceSanish reg = (int)(uintptr_t)addr; 1616649d4cceSanish 1617649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1618649d4cceSanish 1619649d4cceSanish (*pci_putb_func)(cfp->c_busnum, cfp->c_devnum, 1620649d4cceSanish cfp->c_funcnum, reg, value); 1621649d4cceSanish } 1622649d4cceSanish 1623649d4cceSanish void 1624649d4cceSanish pci_config_rep_wr8(ddi_acc_impl_t *hdlp, uint8_t *host_addr, 1625649d4cceSanish uint8_t *dev_addr, size_t repcount, uint_t flags) 1626649d4cceSanish { 1627649d4cceSanish uint8_t *h, *d; 1628649d4cceSanish 1629649d4cceSanish h = host_addr; 1630649d4cceSanish d = dev_addr; 1631649d4cceSanish 1632649d4cceSanish if (flags == DDI_DEV_AUTOINCR) 1633649d4cceSanish for (; repcount; repcount--) 1634649d4cceSanish pci_config_wr8(hdlp, d++, *h++); 1635649d4cceSanish else 1636649d4cceSanish for (; repcount; repcount--) 1637649d4cceSanish pci_config_wr8(hdlp, d, *h++); 1638649d4cceSanish } 1639649d4cceSanish 1640649d4cceSanish void 1641649d4cceSanish pci_config_wr16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value) 1642649d4cceSanish { 1643649d4cceSanish pci_acc_cfblk_t *cfp; 1644649d4cceSanish int reg; 1645649d4cceSanish 1646649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0); 1647649d4cceSanish 1648649d4cceSanish reg = (int)(uintptr_t)addr; 1649649d4cceSanish 1650649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1651649d4cceSanish 1652649d4cceSanish (*pci_putw_func)(cfp->c_busnum, cfp->c_devnum, 1653649d4cceSanish cfp->c_funcnum, reg, value); 1654649d4cceSanish } 1655649d4cceSanish 1656649d4cceSanish void 1657649d4cceSanish pci_config_rep_wr16(ddi_acc_impl_t *hdlp, uint16_t *host_addr, 1658649d4cceSanish uint16_t *dev_addr, size_t repcount, uint_t flags) 1659649d4cceSanish { 1660649d4cceSanish uint16_t *h, *d; 1661649d4cceSanish 1662649d4cceSanish h = host_addr; 1663649d4cceSanish d = dev_addr; 1664649d4cceSanish 1665649d4cceSanish if (flags == DDI_DEV_AUTOINCR) 1666649d4cceSanish for (; repcount; repcount--) 1667649d4cceSanish pci_config_wr16(hdlp, d++, *h++); 1668649d4cceSanish else 1669649d4cceSanish for (; repcount; repcount--) 1670649d4cceSanish pci_config_wr16(hdlp, d, *h++); 1671649d4cceSanish } 1672649d4cceSanish 1673649d4cceSanish void 1674649d4cceSanish pci_config_wr32(ddi_acc_impl_t *hdlp, uint32_t *addr, uint32_t value) 1675649d4cceSanish { 1676649d4cceSanish pci_acc_cfblk_t *cfp; 1677649d4cceSanish int reg; 1678649d4cceSanish 1679649d4cceSanish ASSERT64(((uintptr_t)addr >> 32) == 0); 1680649d4cceSanish 1681649d4cceSanish reg = (int)(uintptr_t)addr; 1682649d4cceSanish 1683649d4cceSanish cfp = (pci_acc_cfblk_t *)&hdlp->ahi_common.ah_bus_private; 1684649d4cceSanish 1685649d4cceSanish (*pci_putl_func)(cfp->c_busnum, cfp->c_devnum, 1686649d4cceSanish cfp->c_funcnum, reg, value); 1687649d4cceSanish } 1688649d4cceSanish 1689649d4cceSanish void 1690649d4cceSanish pci_config_rep_wr32(ddi_acc_impl_t *hdlp, uint32_t *host_addr, 1691649d4cceSanish uint32_t *dev_addr, size_t repcount, uint_t flags) 1692649d4cceSanish { 1693649d4cceSanish uint32_t *h, *d; 1694649d4cceSanish 1695649d4cceSanish h = host_addr; 1696649d4cceSanish d = dev_addr; 1697649d4cceSanish 1698649d4cceSanish if (flags == DDI_DEV_AUTOINCR) 1699649d4cceSanish for (; repcount; repcount--) 1700649d4cceSanish pci_config_wr32(hdlp, d++, *h++); 1701649d4cceSanish else 1702649d4cceSanish for (; repcount; repcount--) 1703649d4cceSanish pci_config_wr32(hdlp, d, *h++); 1704649d4cceSanish } 1705649d4cceSanish 1706649d4cceSanish uint64_t 1707649d4cceSanish pci_config_rd64(ddi_acc_impl_t *hdlp, uint64_t *addr) 1708649d4cceSanish { 1709649d4cceSanish uint32_t lw_val; 1710649d4cceSanish uint32_t hi_val; 1711649d4cceSanish uint32_t *dp; 1712649d4cceSanish uint64_t val; 1713649d4cceSanish 1714649d4cceSanish dp = (uint32_t *)addr; 1715649d4cceSanish lw_val = pci_config_rd32(hdlp, dp); 1716649d4cceSanish dp++; 1717649d4cceSanish hi_val = pci_config_rd32(hdlp, dp); 1718649d4cceSanish val = ((uint64_t)hi_val << 32) | lw_val; 1719649d4cceSanish return (val); 1720649d4cceSanish } 1721649d4cceSanish 1722649d4cceSanish void 1723649d4cceSanish pci_config_wr64(ddi_acc_impl_t *hdlp, uint64_t *addr, uint64_t value) 1724649d4cceSanish { 1725649d4cceSanish uint32_t lw_val; 1726649d4cceSanish uint32_t hi_val; 1727649d4cceSanish uint32_t *dp; 1728649d4cceSanish 1729649d4cceSanish dp = (uint32_t *)addr; 1730649d4cceSanish lw_val = (uint32_t)(value & 0xffffffff); 1731649d4cceSanish hi_val = (uint32_t)(value >> 32); 1732649d4cceSanish pci_config_wr32(hdlp, dp, lw_val); 1733649d4cceSanish dp++; 1734649d4cceSanish pci_config_wr32(hdlp, dp, hi_val); 1735649d4cceSanish } 1736649d4cceSanish 1737649d4cceSanish void 1738649d4cceSanish pci_config_rep_rd64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1739649d4cceSanish uint64_t *dev_addr, size_t repcount, uint_t flags) 1740649d4cceSanish { 1741649d4cceSanish if (flags == DDI_DEV_AUTOINCR) { 1742649d4cceSanish for (; repcount; repcount--) 1743649d4cceSanish *host_addr++ = pci_config_rd64(hdlp, dev_addr++); 1744649d4cceSanish } else { 1745649d4cceSanish for (; repcount; repcount--) 1746649d4cceSanish *host_addr++ = pci_config_rd64(hdlp, dev_addr); 1747649d4cceSanish } 1748649d4cceSanish } 1749649d4cceSanish 1750649d4cceSanish void 1751649d4cceSanish pci_config_rep_wr64(ddi_acc_impl_t *hdlp, uint64_t *host_addr, 1752649d4cceSanish uint64_t *dev_addr, size_t repcount, uint_t flags) 1753649d4cceSanish { 1754649d4cceSanish if (flags == DDI_DEV_AUTOINCR) { 1755649d4cceSanish for (; repcount; repcount--) 1756649d4cceSanish pci_config_wr64(hdlp, host_addr++, *dev_addr++); 1757649d4cceSanish } else { 1758649d4cceSanish for (; repcount; repcount--) 1759649d4cceSanish pci_config_wr64(hdlp, host_addr++, *dev_addr); 1760649d4cceSanish } 1761649d4cceSanish } 1762