17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51de45cd9Sgovinda * Common Development and Distribution License (the "License"). 61de45cd9Sgovinda * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*fc256490SJason Beloro * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * PCI nexus utility routines: 287c478bd9Sstevel@tonic-gate * property and config routines for attach() 297c478bd9Sstevel@tonic-gate * reg/intr/range/assigned-address property routines for bus_map() 307c478bd9Sstevel@tonic-gate * init_child() 317c478bd9Sstevel@tonic-gate * fault handling 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 367c478bd9Sstevel@tonic-gate #include <sys/async.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 397c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 407c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 417c478bd9Sstevel@tonic-gate #include "px_obj.h" 42d4bc0535SKrishna Elango #include <sys/pcie_pwr.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /* 477c478bd9Sstevel@tonic-gate * px_get_props 487c478bd9Sstevel@tonic-gate * 497c478bd9Sstevel@tonic-gate * This function is called from the attach routine to get the key 507c478bd9Sstevel@tonic-gate * properties of the pci nodes. 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * used by: px_attach() 537c478bd9Sstevel@tonic-gate * 547c478bd9Sstevel@tonic-gate * return value: DDI_FAILURE on failure 557c478bd9Sstevel@tonic-gate */ 567c478bd9Sstevel@tonic-gate int 577c478bd9Sstevel@tonic-gate px_get_props(px_t *px_p, dev_info_t *dip) 587c478bd9Sstevel@tonic-gate { 597c478bd9Sstevel@tonic-gate int i, no_of_intrs; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * Get the bus-ranges property. 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate i = sizeof (px_p->px_bus_range); 657c478bd9Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 667c478bd9Sstevel@tonic-gate "bus-range", (caddr_t)&px_p->px_bus_range, &i) != DDI_SUCCESS) { 677c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no bus-range property\n", 687c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 697c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 707c478bd9Sstevel@tonic-gate } 717c478bd9Sstevel@tonic-gate DBG(DBG_ATTACH, dip, "get_px_properties: bus-range (%x,%x)\n", 727c478bd9Sstevel@tonic-gate px_p->px_bus_range.lo, px_p->px_bus_range.hi); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * Get the interrupts property. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 787c478bd9Sstevel@tonic-gate "interrupts", (caddr_t)&px_p->px_inos, 797c478bd9Sstevel@tonic-gate &px_p->px_inos_len) != DDI_SUCCESS) { 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no interrupts property\n", 827c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 837c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 847c478bd9Sstevel@tonic-gate } 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * figure out number of interrupts in the "interrupts" property 887c478bd9Sstevel@tonic-gate * and convert them all into ino. 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate i = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "#interrupt-cells", 1); 917c478bd9Sstevel@tonic-gate i = CELLS_1275_TO_BYTES(i); 927c478bd9Sstevel@tonic-gate no_of_intrs = px_p->px_inos_len / i; 937c478bd9Sstevel@tonic-gate for (i = 0; i < no_of_intrs; i++) 947c478bd9Sstevel@tonic-gate px_p->px_inos[i] = px_p->px_inos[i] & 0x3F; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * Get the ranges property. 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 1007c478bd9Sstevel@tonic-gate (caddr_t)&px_p->px_ranges_p, &px_p->px_ranges_length) != 1017c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no ranges property\n", 1047c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1057c478bd9Sstevel@tonic-gate kmem_free(px_p->px_inos, px_p->px_inos_len); 1067c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1077c478bd9Sstevel@tonic-gate } 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * px_free_props: 1147c478bd9Sstevel@tonic-gate * 1157c478bd9Sstevel@tonic-gate * This routine frees the memory used to cache the "interrupts" 1167c478bd9Sstevel@tonic-gate * and "ranges" properties of the pci bus device node. 1177c478bd9Sstevel@tonic-gate * 1187c478bd9Sstevel@tonic-gate * used by: px_detach() 1197c478bd9Sstevel@tonic-gate * 1207c478bd9Sstevel@tonic-gate * return value: none 1217c478bd9Sstevel@tonic-gate */ 1227c478bd9Sstevel@tonic-gate void 1237c478bd9Sstevel@tonic-gate px_free_props(px_t *px_p) 1247c478bd9Sstevel@tonic-gate { 1257c478bd9Sstevel@tonic-gate kmem_free(px_p->px_inos, px_p->px_inos_len); 1267c478bd9Sstevel@tonic-gate kmem_free(px_p->px_ranges_p, px_p->px_ranges_length); 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * px_reloc_reg 1317c478bd9Sstevel@tonic-gate * 1327c478bd9Sstevel@tonic-gate * If the "reg" entry (*px_rp) is relocatable, lookup "assigned-addresses" 1337c478bd9Sstevel@tonic-gate * property to fetch corresponding relocated address. 1347c478bd9Sstevel@tonic-gate * 1357c478bd9Sstevel@tonic-gate * used by: px_map() 1367c478bd9Sstevel@tonic-gate * 1377c478bd9Sstevel@tonic-gate * return value: 1387c478bd9Sstevel@tonic-gate * 1397c478bd9Sstevel@tonic-gate * DDI_SUCCESS - on success 1407c478bd9Sstevel@tonic-gate * DDI_ME_INVAL - regspec is invalid 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate int 1437c478bd9Sstevel@tonic-gate px_reloc_reg(dev_info_t *dip, dev_info_t *rdip, px_t *px_p, 1447c478bd9Sstevel@tonic-gate pci_regspec_t *rp) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate int assign_len, assign_entries, i; 1477c478bd9Sstevel@tonic-gate pci_regspec_t *assign_p; 1487c478bd9Sstevel@tonic-gate uint32_t phys_hi = rp->pci_phys_hi; 1497c478bd9Sstevel@tonic-gate uint32_t space_type = phys_hi & PCI_REG_ADDR_M; /* 28-bit */ 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate DBG(DBG_MAP | DBG_CONT, dip, "\tpx_reloc_reg fr: %x.%x.%x %x.%x\n", 1527c478bd9Sstevel@tonic-gate rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, 1537c478bd9Sstevel@tonic-gate rp->pci_size_hi, rp->pci_size_low); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if (space_type == PCI_ADDR_CONFIG || phys_hi & PCI_RELOCAT_B) 1567c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate * Hot plug will be taken care of later 1607c478bd9Sstevel@tonic-gate * if (px_p->hotplug_capable == B_FALSE) 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate { 1637c478bd9Sstevel@tonic-gate uint32_t bus = PCI_REG_BUS_G(phys_hi); 1647c478bd9Sstevel@tonic-gate if (bus < px_p->px_bus_range.lo || 1657c478bd9Sstevel@tonic-gate bus > px_p->px_bus_range.hi) { 1667c478bd9Sstevel@tonic-gate DBG(DBG_MAP | DBG_CONT, dip, "bad bus# (%x)\n", bus); 1677c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate i = ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 1727c478bd9Sstevel@tonic-gate "assigned-addresses", (caddr_t)&assign_p, &assign_len); 17326947304SEvan Yan 1747c478bd9Sstevel@tonic-gate if (i) { 1757c478bd9Sstevel@tonic-gate DBG(DBG_MAP | DBG_CONT, dip, "%s%d: assigned-addresses %d\n", 1767c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), i); 1777c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate assign_entries = assign_len / sizeof (pci_regspec_t); 1817c478bd9Sstevel@tonic-gate for (i = 0; i < assign_entries; i++, assign_p++) { 1827c478bd9Sstevel@tonic-gate uint32_t assign_type = assign_p->pci_phys_hi & PCI_REG_ADDR_M; 1837c478bd9Sstevel@tonic-gate uint32_t assign_addr = PCI_REG_BDFR_G(assign_p->pci_phys_hi); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if (PCI_REG_BDFR_G(phys_hi) != assign_addr) 1867c478bd9Sstevel@tonic-gate continue; 1877c478bd9Sstevel@tonic-gate if (space_type == assign_type) { /* exact match */ 1887c478bd9Sstevel@tonic-gate rp->pci_phys_low += assign_p->pci_phys_low; 1893c9d50fcSgovinda if (space_type == PCI_ADDR_MEM64) 1903c9d50fcSgovinda rp->pci_phys_mid += assign_p->pci_phys_mid; 1917c478bd9Sstevel@tonic-gate break; 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate if (space_type == PCI_ADDR_MEM64 && 1947c478bd9Sstevel@tonic-gate assign_type == PCI_ADDR_MEM32) { 1957c478bd9Sstevel@tonic-gate rp->pci_phys_low += assign_p->pci_phys_low; 1967c478bd9Sstevel@tonic-gate rp->pci_phys_hi ^= PCI_ADDR_MEM64 ^ PCI_ADDR_MEM32; 1977c478bd9Sstevel@tonic-gate break; 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate kmem_free(assign_p - i, assign_len); 2017c478bd9Sstevel@tonic-gate DBG(DBG_MAP | DBG_CONT, dip, "\tpx_reloc_reg to: %x.%x.%x %x.%x <%d>\n", 2027c478bd9Sstevel@tonic-gate rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, 2037c478bd9Sstevel@tonic-gate rp->pci_size_hi, rp->pci_size_low, i); 2047c478bd9Sstevel@tonic-gate return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 207d3533785Sschwartz /* 208d3533785Sschwartz * use "ranges" to translate relocated pci regspec into parent space 209d3533785Sschwartz */ 2107c478bd9Sstevel@tonic-gate int 211d3533785Sschwartz px_xlate_reg(px_t *px_p, pci_regspec_t *px_rp, struct regspec *new_rp) 2127c478bd9Sstevel@tonic-gate { 213d3533785Sschwartz int n; 21426947304SEvan Yan pci_ranges_t *rng_p = px_p->px_ranges_p; 21526947304SEvan Yan int rng_n = px_p->px_ranges_length / sizeof (pci_ranges_t); 216d3533785Sschwartz uint32_t space_type = PCI_REG_ADDR_G(px_rp->pci_phys_hi); 2173c9d50fcSgovinda uint64_t reg_begin, reg_end, reg_sz; 2183c9d50fcSgovinda uint64_t rng_begin, rng_end, rng_sz; 2193c9d50fcSgovinda uint64_t addr; 220d3533785Sschwartz 2213c9d50fcSgovinda reg_begin = (uint64_t)px_rp->pci_phys_mid << 32 | px_rp->pci_phys_low; 2223c9d50fcSgovinda reg_sz = (uint64_t)px_rp->pci_size_hi << 32 | px_rp->pci_size_low; 223d3533785Sschwartz if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 224d3533785Sschwartz if (reg_begin > PCI_CONF_HDR_SIZE) 225d3533785Sschwartz return (DDI_ME_INVAL); 2263c9d50fcSgovinda reg_sz = reg_sz ? MIN(reg_sz, PCI_CONF_HDR_SIZE) : 2273c9d50fcSgovinda PCI_CONF_HDR_SIZE; 228d3533785Sschwartz reg_begin += px_rp->pci_phys_hi << 4; 229d3533785Sschwartz } 2303c9d50fcSgovinda reg_end = reg_begin + reg_sz - 1; 231d3533785Sschwartz 2327c478bd9Sstevel@tonic-gate for (n = 0; n < rng_n; n++, rng_p++) { 2337c478bd9Sstevel@tonic-gate if (space_type != PCI_REG_ADDR_G(rng_p->child_high)) 2347c478bd9Sstevel@tonic-gate continue; /* not the same space type */ 2357c478bd9Sstevel@tonic-gate 2363c9d50fcSgovinda rng_begin = (uint64_t)rng_p->child_mid << 32 | rng_p->child_low; 2373c9d50fcSgovinda rng_sz = (uint64_t)rng_p->size_high << 32 | rng_p->size_low; 2387c478bd9Sstevel@tonic-gate if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) 2397c478bd9Sstevel@tonic-gate rng_begin += rng_p->child_high; 2407c478bd9Sstevel@tonic-gate 2413c9d50fcSgovinda rng_end = rng_begin + rng_sz - 1; 2427c478bd9Sstevel@tonic-gate if (reg_begin >= rng_begin && reg_end <= rng_end) 2437c478bd9Sstevel@tonic-gate break; 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate if (n >= rng_n) 2467c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 2477c478bd9Sstevel@tonic-gate 2483c9d50fcSgovinda addr = reg_begin - rng_begin + ((uint64_t)rng_p->parent_high << 32 | 2493c9d50fcSgovinda rng_p->parent_low); 2503c9d50fcSgovinda new_rp->regspec_addr = (uint32_t)addr; 2513c9d50fcSgovinda new_rp->regspec_bustype = (uint32_t)(addr >> 32); 2523c9d50fcSgovinda new_rp->regspec_size = (uint32_t)reg_sz; 253d3533785Sschwartz DBG(DBG_MAP | DBG_CONT, px_p->px_dip, 254d3533785Sschwartz "\tpx_xlate_reg: entry %d new_rp %x.%x %x\n", 2553c9d50fcSgovinda n, new_rp->regspec_bustype, new_rp->regspec_addr, reg_sz); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate * px_report_dev 2627c478bd9Sstevel@tonic-gate * 2637c478bd9Sstevel@tonic-gate * This function is called from our control ops routine on a 2647c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV request. 2657c478bd9Sstevel@tonic-gate * 2667c478bd9Sstevel@tonic-gate * The display format is 2677c478bd9Sstevel@tonic-gate * 2687c478bd9Sstevel@tonic-gate * <name><inst> at <pname><pinst> device <dev> function <func> 2697c478bd9Sstevel@tonic-gate * 2707c478bd9Sstevel@tonic-gate * where 2717c478bd9Sstevel@tonic-gate * 2727c478bd9Sstevel@tonic-gate * <name> this device's name property 2737c478bd9Sstevel@tonic-gate * <inst> this device's instance number 2747c478bd9Sstevel@tonic-gate * <name> parent device's name property 2757c478bd9Sstevel@tonic-gate * <inst> parent device's instance number 2767c478bd9Sstevel@tonic-gate * <dev> this device's device number 2777c478bd9Sstevel@tonic-gate * <func> this device's function number 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate int 2807c478bd9Sstevel@tonic-gate px_report_dev(dev_info_t *dip) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate if (dip == (dev_info_t *)0) 2837c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2847c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI Express-device: %s@%s, %s%d\n", 2857c478bd9Sstevel@tonic-gate ddi_node_name(dip), ddi_get_name_addr(dip), 2867c478bd9Sstevel@tonic-gate ddi_driver_name(dip), 2877c478bd9Sstevel@tonic-gate ddi_get_instance(dip)); 2887c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * reg property for pcimem nodes that covers the entire address 2947c478bd9Sstevel@tonic-gate * space for the node: config, io, or memory. 2957c478bd9Sstevel@tonic-gate */ 2967c478bd9Sstevel@tonic-gate pci_regspec_t pci_pcimem_reg[3] = 2977c478bd9Sstevel@tonic-gate { 2987c478bd9Sstevel@tonic-gate {PCI_ADDR_CONFIG, 0, 0, 0, 0x800000 }, 2997c478bd9Sstevel@tonic-gate {(uint_t)(PCI_ADDR_IO|PCI_RELOCAT_B), 0, 0, 0, PX_IO_SIZE }, 3007c478bd9Sstevel@tonic-gate {(uint_t)(PCI_ADDR_MEM32|PCI_RELOCAT_B), 0, 0, 0, PX_MEM_SIZE } 3017c478bd9Sstevel@tonic-gate }; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* 3047c478bd9Sstevel@tonic-gate * px_name_child 3057c478bd9Sstevel@tonic-gate * 3067c478bd9Sstevel@tonic-gate * This function is called from init_child to name a node. It is 3077c478bd9Sstevel@tonic-gate * also passed as a callback for node merging functions. 3087c478bd9Sstevel@tonic-gate * 3097c478bd9Sstevel@tonic-gate * return value: DDI_SUCCESS, DDI_FAILURE 3107c478bd9Sstevel@tonic-gate */ 3117c478bd9Sstevel@tonic-gate static int 3127c478bd9Sstevel@tonic-gate px_name_child(dev_info_t *child, char *name, int namelen) 3137c478bd9Sstevel@tonic-gate { 3147c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 3157c478bd9Sstevel@tonic-gate int reglen; 3167c478bd9Sstevel@tonic-gate uint_t func; 3177c478bd9Sstevel@tonic-gate char **unit_addr; 3187c478bd9Sstevel@tonic-gate uint_t n; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * Set the address portion of the node name based on 3227c478bd9Sstevel@tonic-gate * unit-address property, if it exists. 3237c478bd9Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 3247c478bd9Sstevel@tonic-gate * where DD is the device id and F is the function. 3257c478bd9Sstevel@tonic-gate */ 3267c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 3277c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) == 3287c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) { 3297c478bd9Sstevel@tonic-gate if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 3307c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "unit-address property in %s.conf" 3317c478bd9Sstevel@tonic-gate " not well-formed", ddi_driver_name(child)); 3327c478bd9Sstevel@tonic-gate ddi_prop_free(unit_addr); 3337c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%s", *unit_addr); 3367c478bd9Sstevel@tonic-gate ddi_prop_free(unit_addr); 3377c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* 3417c478bd9Sstevel@tonic-gate * The unit-address property is does not exist. Set the address 3427c478bd9Sstevel@tonic-gate * portion of the node name based on the function and device number. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 3457c478bd9Sstevel@tonic-gate "reg", (int **)&pci_rp, (uint_t *)®len) == DDI_SUCCESS) { 3467c478bd9Sstevel@tonic-gate if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) { 3477c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "reg property not well-formed"); 3487c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi); 3527c478bd9Sstevel@tonic-gate if (func != 0) 3537c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 3547c478bd9Sstevel@tonic-gate PCI_REG_DEV_G(pci_rp[0].pci_phys_hi), func); 3557c478bd9Sstevel@tonic-gate else 3567c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x", 3577c478bd9Sstevel@tonic-gate PCI_REG_DEV_G(pci_rp[0].pci_phys_hi)); 3587c478bd9Sstevel@tonic-gate ddi_prop_free(pci_rp); 3597c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child)); 3637c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate int 3677c478bd9Sstevel@tonic-gate px_uninit_child(px_t *px_p, dev_info_t *child) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate DBG(DBG_INIT_CLD, px_p->px_dip, 3707c478bd9Sstevel@tonic-gate "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n", 3717c478bd9Sstevel@tonic-gate ddi_driver_name(child), ddi_get_instance(child)); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 3747c478bd9Sstevel@tonic-gate ddi_remove_minor_node(child, NULL); 3759fc8611eSDaniel Ice 3769fc8611eSDaniel Ice /* 3779fc8611eSDaniel Ice * XXX Clear parent private data used as a flag to disable 3789fc8611eSDaniel Ice * iommu BDF protection 3799fc8611eSDaniel Ice */ 3809fc8611eSDaniel Ice if ((intptr_t)ddi_get_parent_data(child) == 1) 3819fc8611eSDaniel Ice ddi_set_parent_data(child, NULL); 3829fc8611eSDaniel Ice 3837c478bd9Sstevel@tonic-gate impl_rem_dev_props(child); 3847c478bd9Sstevel@tonic-gate 385f8d2de6bSjchu DBG(DBG_PWR, ddi_get_parent(child), "\n\n"); 386f8d2de6bSjchu 387f8d2de6bSjchu pcie_uninitchild(child); 388f8d2de6bSjchu 389f8d2de6bSjchu return (DDI_SUCCESS); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* 3937c478bd9Sstevel@tonic-gate * px_init_child 3947c478bd9Sstevel@tonic-gate * 3957c478bd9Sstevel@tonic-gate * This function is called from our control ops routine on a 3967c478bd9Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD request. It builds and sets the device's 3977c478bd9Sstevel@tonic-gate * parent private data area. 3987c478bd9Sstevel@tonic-gate * 3997c478bd9Sstevel@tonic-gate * used by: pci_ctlops() 4007c478bd9Sstevel@tonic-gate * 4017c478bd9Sstevel@tonic-gate * return value: none 4027c478bd9Sstevel@tonic-gate */ 4037c478bd9Sstevel@tonic-gate int 4047c478bd9Sstevel@tonic-gate px_init_child(px_t *px_p, dev_info_t *child) 4057c478bd9Sstevel@tonic-gate { 406f8d2de6bSjchu dev_info_t *parent_dip = px_p->px_dip; 4077c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 4087c478bd9Sstevel@tonic-gate char name[10]; 4097c478bd9Sstevel@tonic-gate int i, no_config; 4109fc8611eSDaniel Ice intptr_t ppd = NULL; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * The following is a special case for pcimem nodes. 4147c478bd9Sstevel@tonic-gate * For these nodes we create a reg property with a 4157c478bd9Sstevel@tonic-gate * single entry that covers the entire address space 4167c478bd9Sstevel@tonic-gate * for the node (config, io or memory). 4177c478bd9Sstevel@tonic-gate */ 4187c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(child), "pcimem") == 0) { 4197c478bd9Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, child, 4207c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, "reg", (caddr_t)pci_pcimem_reg, 4217c478bd9Sstevel@tonic-gate sizeof (pci_pcimem_reg)); 4227c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, "0"); 4237c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 4247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * Check whether the node has config space or is a hard decode 4297c478bd9Sstevel@tonic-gate * node (possibly created by a driver.conf file). 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate no_config = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 4327c478bd9Sstevel@tonic-gate "no-config", 0); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* 4359fc8611eSDaniel Ice * XXX set ppd to 1 to disable iommu BDF protection 4369fc8611eSDaniel Ice * It relies on unused parent private data for PCI devices. 4379fc8611eSDaniel Ice */ 4389fc8611eSDaniel Ice if (ddi_prop_exists(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, 4399fc8611eSDaniel Ice "dvma-share")) 4409fc8611eSDaniel Ice ppd = 1; 4419fc8611eSDaniel Ice 4429fc8611eSDaniel Ice /* 4437c478bd9Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 4447c478bd9Sstevel@tonic-gate * properties to be merged into the real h/w device node. 4457c478bd9Sstevel@tonic-gate * However, do not merge if the no-config property is set 4467c478bd9Sstevel@tonic-gate * (see PSARC 2000/088). 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate if ((ndi_dev_is_persistent_node(child) == 0) && (no_config == 0)) { 4497c478bd9Sstevel@tonic-gate extern int pci_allow_pseudo_children; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, 4527c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, &i) == 4537c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 4547c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "cannot merge prototype from %s.conf", 4557c478bd9Sstevel@tonic-gate ddi_driver_name(child)); 4567c478bd9Sstevel@tonic-gate kmem_free(pci_rp, i); 4577c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * Name the child 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate if (px_name_child(child, name, 10) != DDI_SUCCESS) 4637c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 4669fc8611eSDaniel Ice ddi_set_parent_data(child, (void *)ppd); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Try to merge the properties from this prototype 4707c478bd9Sstevel@tonic-gate * node into real h/w nodes. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate if (ndi_merge_node(child, px_name_child) == DDI_SUCCESS) { 4737c478bd9Sstevel@tonic-gate /* 4747c478bd9Sstevel@tonic-gate * Merged ok - return failure to remove the node. 4757c478bd9Sstevel@tonic-gate */ 4767c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 4777c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 4817c478bd9Sstevel@tonic-gate if (pci_allow_pseudo_children) 4827c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 4857c478bd9Sstevel@tonic-gate ddi_driver_name(child), ddi_get_name_addr(child), 4867c478bd9Sstevel@tonic-gate ddi_driver_name(child)); 4877c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 4887c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate if (px_name_child(child, name, 10) != DDI_SUCCESS) 4927c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4937c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate if (no_config != 0) { 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * There is no config space so there's nothing more to do. 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 502f8d2de6bSjchu if (pcie_pm_hold(parent_dip) != DDI_SUCCESS) { 503f8d2de6bSjchu DBG(DBG_PWR, parent_dip, 5047c478bd9Sstevel@tonic-gate "INITCHILD: px_pm_hold failed\n"); 5057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate /* Any return of DDI_FAILURE after this must call px_pm_release */ 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * If configuration registers were previously saved by 5117c478bd9Sstevel@tonic-gate * child (before it went to D3), then let the child do the 5127c478bd9Sstevel@tonic-gate * restore to set up the config regs as it'll first need to 5137c478bd9Sstevel@tonic-gate * power the device out of D3. 5147c478bd9Sstevel@tonic-gate */ 5157c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 5167c478bd9Sstevel@tonic-gate "config-regs-saved-by-child") == 1) { 5177c478bd9Sstevel@tonic-gate DBG(DBG_PWR, child, 5187c478bd9Sstevel@tonic-gate "INITCHILD: config regs to be restored by child\n"); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 523f8d2de6bSjchu DBG(DBG_PWR, parent_dip, 5247c478bd9Sstevel@tonic-gate "INITCHILD: config regs setup for %s@%s\n", 5257c478bd9Sstevel@tonic-gate ddi_node_name(child), ddi_get_name_addr(child)); 5267c478bd9Sstevel@tonic-gate 5279fc8611eSDaniel Ice ddi_set_parent_data(child, (void *)ppd); 528*fc256490SJason Beloro pcie_init_dom(child); 529eae2e508Skrishnae (void) pcie_initchild(child); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Handle chip specific init-child tasks. 5337c478bd9Sstevel@tonic-gate */ 534f8d2de6bSjchu pcie_pm_release(parent_dip); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * px_get_reg_set_size 5417c478bd9Sstevel@tonic-gate * 5427c478bd9Sstevel@tonic-gate * Given a dev info pointer to a pci child and a register number, this 5437c478bd9Sstevel@tonic-gate * routine returns the size element of that reg set property. 5447c478bd9Sstevel@tonic-gate * 5457c478bd9Sstevel@tonic-gate * used by: pci_ctlops() - DDI_CTLOPS_REGSIZE 5467c478bd9Sstevel@tonic-gate * 547f8d2de6bSjchu * return value: size of reg set on success, 0 on error 5487c478bd9Sstevel@tonic-gate */ 5497c478bd9Sstevel@tonic-gate off_t 5507c478bd9Sstevel@tonic-gate px_get_reg_set_size(dev_info_t *child, int rnumber) 5517c478bd9Sstevel@tonic-gate { 5527c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 553f8d2de6bSjchu off_t size = 0; 5547c478bd9Sstevel@tonic-gate int i; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate if (rnumber < 0) 557f8d2de6bSjchu return (0); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate /* 5607c478bd9Sstevel@tonic-gate * Get the reg property for the device. 5617c478bd9Sstevel@tonic-gate */ 5627c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 5637c478bd9Sstevel@tonic-gate (caddr_t)&pci_rp, &i) != DDI_SUCCESS) 564f8d2de6bSjchu return (0); 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate if (rnumber >= (i / (int)sizeof (pci_regspec_t))) 5677c478bd9Sstevel@tonic-gate goto done; 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate size = pci_rp[rnumber].pci_size_low | 5707c478bd9Sstevel@tonic-gate ((uint64_t)pci_rp[rnumber].pci_size_hi << 32); 5717c478bd9Sstevel@tonic-gate done: 5727c478bd9Sstevel@tonic-gate kmem_free(pci_rp, i); 5737c478bd9Sstevel@tonic-gate return (size); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * px_get_nreg_set 5797c478bd9Sstevel@tonic-gate * 5807c478bd9Sstevel@tonic-gate * Given a dev info pointer to a pci child, this routine returns the 5817c478bd9Sstevel@tonic-gate * number of sets in its "reg" property. 5827c478bd9Sstevel@tonic-gate * 5837c478bd9Sstevel@tonic-gate * used by: pci_ctlops() - DDI_CTLOPS_NREGS 5847c478bd9Sstevel@tonic-gate * 5857c478bd9Sstevel@tonic-gate * return value: # of reg sets on success, zero on error 5867c478bd9Sstevel@tonic-gate */ 5877c478bd9Sstevel@tonic-gate uint_t 5887c478bd9Sstevel@tonic-gate px_get_nreg_set(dev_info_t *child) 5897c478bd9Sstevel@tonic-gate { 5907c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 5917c478bd9Sstevel@tonic-gate int i, n; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * Get the reg property for the device. 5957c478bd9Sstevel@tonic-gate */ 5967c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 5977c478bd9Sstevel@tonic-gate (caddr_t)&pci_rp, &i) != DDI_SUCCESS) 5987c478bd9Sstevel@tonic-gate return (0); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate n = i / (int)sizeof (pci_regspec_t); 6017c478bd9Sstevel@tonic-gate kmem_free(pci_rp, i); 6027c478bd9Sstevel@tonic-gate return (n); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /* 6077c478bd9Sstevel@tonic-gate * px_get_nintr 6087c478bd9Sstevel@tonic-gate * 6097c478bd9Sstevel@tonic-gate * Given a dev info pointer to a pci child, this routine returns the 6107c478bd9Sstevel@tonic-gate * number of items in its "interrupts" property. 6117c478bd9Sstevel@tonic-gate * 6127c478bd9Sstevel@tonic-gate * used by: pci_ctlops() - DDI_CTLOPS_NREGS 6137c478bd9Sstevel@tonic-gate * 6147c478bd9Sstevel@tonic-gate * return value: # of interrupts on success, zero on error 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate uint_t 6177c478bd9Sstevel@tonic-gate px_get_nintr(dev_info_t *child) 6187c478bd9Sstevel@tonic-gate { 6197c478bd9Sstevel@tonic-gate int *pci_ip; 6207c478bd9Sstevel@tonic-gate int i, n; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 6237c478bd9Sstevel@tonic-gate "interrupts", (caddr_t)&pci_ip, &i) != DDI_SUCCESS) 6247c478bd9Sstevel@tonic-gate return (0); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate n = i / (int)sizeof (uint_t); 6277c478bd9Sstevel@tonic-gate kmem_free(pci_ip, i); 6287c478bd9Sstevel@tonic-gate return (n); 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate uint64_t 6327c478bd9Sstevel@tonic-gate px_get_cfg_pabase(px_t *px_p) 6337c478bd9Sstevel@tonic-gate { 6347c478bd9Sstevel@tonic-gate int i; 63526947304SEvan Yan pci_ranges_t *rangep = px_p->px_ranges_p; 63626947304SEvan Yan int nrange = px_p->px_ranges_length / sizeof (pci_ranges_t); 6377c478bd9Sstevel@tonic-gate uint32_t cfg_space_type = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate ASSERT(cfg_space_type == 0); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate for (i = 0; i < nrange; i++, rangep++) { 6427c478bd9Sstevel@tonic-gate if (PCI_REG_ADDR_G(rangep->child_high) == cfg_space_type) 6437c478bd9Sstevel@tonic-gate break; 6447c478bd9Sstevel@tonic-gate } 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate if (i >= nrange) 647b40cec45Skrishnae cmn_err(CE_PANIC, "no cfg space in px(%p) ranges prop.\n", 648b40cec45Skrishnae px_p); 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate return (((uint64_t)rangep->parent_high << 32) | rangep->parent_low); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate /* 6547c478bd9Sstevel@tonic-gate * decodes standard PCI config space 16bit error status reg 6557c478bd9Sstevel@tonic-gate */ 6567c478bd9Sstevel@tonic-gate int 6577c478bd9Sstevel@tonic-gate px_log_cfg_err(dev_info_t *dip, ushort_t status_reg, char *err_msg) 6587c478bd9Sstevel@tonic-gate { 6597c478bd9Sstevel@tonic-gate int nerr = ddi_get_instance(dip); /* temp for instance */ 6607c478bd9Sstevel@tonic-gate uint64_t perr_fatal = px_perr_fatal & (1 << nerr); 6617c478bd9Sstevel@tonic-gate uint64_t serr_fatal = px_serr_fatal & (1 << nerr); 6627c478bd9Sstevel@tonic-gate nerr = 0; 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate if ((status_reg & PCI_STAT_PERROR) && perr_fatal) 6657c478bd9Sstevel@tonic-gate nerr++; 6667c478bd9Sstevel@tonic-gate if ((status_reg & PCI_STAT_S_SYSERR) && serr_fatal) 6677c478bd9Sstevel@tonic-gate nerr++; 6687c478bd9Sstevel@tonic-gate if (status_reg & PCI_STAT_R_MAST_AB) 6697c478bd9Sstevel@tonic-gate nerr++; 6707c478bd9Sstevel@tonic-gate if ((status_reg & PCI_STAT_S_PERROR) && perr_fatal) 6717c478bd9Sstevel@tonic-gate nerr++; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: %sPCI Express config space CSR=0x%b", 6747c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), err_msg, 6757c478bd9Sstevel@tonic-gate (uint32_t)status_reg, PX_STATUS_BITS); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate return (nerr); 6787c478bd9Sstevel@tonic-gate } 679