10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * PCI nexus utility routines: 310Sstevel@tonic-gate * property and config routines for attach() 320Sstevel@tonic-gate * reg/intr/range/assigned-address property routines for bus_map() 330Sstevel@tonic-gate * init_child() 340Sstevel@tonic-gate * fault handling 350Sstevel@tonic-gate */ 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include <sys/types.h> 380Sstevel@tonic-gate #include <sys/kmem.h> 390Sstevel@tonic-gate #include <sys/async.h> 400Sstevel@tonic-gate #include <sys/sysmacros.h> 410Sstevel@tonic-gate #include <sys/sunddi.h> 420Sstevel@tonic-gate #include <sys/sunndi.h> 430Sstevel@tonic-gate #include <sys/fm/protocol.h> 440Sstevel@tonic-gate #include <sys/fm/io/pci.h> 450Sstevel@tonic-gate #include <sys/fm/util.h> 460Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 470Sstevel@tonic-gate #include <sys/pci/pci_obj.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate /*LINTLIBRARY*/ 500Sstevel@tonic-gate 510Sstevel@tonic-gate /* 520Sstevel@tonic-gate * get_pci_properties 530Sstevel@tonic-gate * 540Sstevel@tonic-gate * This function is called from the attach routine to get the key 550Sstevel@tonic-gate * properties of the pci nodes. 560Sstevel@tonic-gate * 570Sstevel@tonic-gate * used by: pci_attach() 580Sstevel@tonic-gate * 590Sstevel@tonic-gate * return value: DDI_FAILURE on failure 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate int 620Sstevel@tonic-gate get_pci_properties(pci_t *pci_p, dev_info_t *dip) 630Sstevel@tonic-gate { 640Sstevel@tonic-gate int i; 650Sstevel@tonic-gate 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * Get the device's port id. 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate if ((pci_p->pci_id = (uint32_t)pci_get_portid(dip)) == -1u) { 700Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no portid property\n", 710Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 720Sstevel@tonic-gate return (DDI_FAILURE); 730Sstevel@tonic-gate } 740Sstevel@tonic-gate 750Sstevel@tonic-gate /* 760Sstevel@tonic-gate * Get the bus-ranges property. 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate i = sizeof (pci_p->pci_bus_range); 790Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 800Sstevel@tonic-gate "bus-range", (caddr_t)&pci_p->pci_bus_range, &i) != DDI_SUCCESS) { 810Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no bus-range property\n", 820Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 830Sstevel@tonic-gate return (DDI_FAILURE); 840Sstevel@tonic-gate } 850Sstevel@tonic-gate DEBUG2(DBG_ATTACH, dip, "get_pci_properties: bus-range (%x,%x)\n", 860Sstevel@tonic-gate pci_p->pci_bus_range.lo, pci_p->pci_bus_range.hi); 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * disable streaming cache if necessary, this must be done 900Sstevel@tonic-gate * before PBM is configured. 910Sstevel@tonic-gate */ 920Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 930Sstevel@tonic-gate "no-streaming-cache")) { 940Sstevel@tonic-gate pci_stream_buf_enable = 0; 950Sstevel@tonic-gate pci_stream_buf_exists = 0; 960Sstevel@tonic-gate } 970Sstevel@tonic-gate 980Sstevel@tonic-gate /* 990Sstevel@tonic-gate * Get the ranges property. 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 1020Sstevel@tonic-gate (caddr_t)&pci_p->pci_ranges, &pci_p->pci_ranges_length) != 1030Sstevel@tonic-gate DDI_SUCCESS) { 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no ranges property\n", 1060Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1070Sstevel@tonic-gate return (DDI_FAILURE); 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate pci_fix_ranges(pci_p->pci_ranges, 1100Sstevel@tonic-gate pci_p->pci_ranges_length / sizeof (pci_ranges_t)); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate /* 1130Sstevel@tonic-gate * Determine the number upa slot interrupts. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate pci_p->pci_numproxy = pci_get_numproxy(pci_p->pci_dip); 1160Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "get_pci_properties: numproxy=%d\n", 1170Sstevel@tonic-gate pci_p->pci_numproxy); 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate pci_p->pci_thermal_interrupt = 1200Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1210Sstevel@tonic-gate "thermal-interrupt", -1); 1220Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "get_pci_properties: thermal_interrupt=%d\n", 1230Sstevel@tonic-gate pci_p->pci_thermal_interrupt); 1240Sstevel@tonic-gate return (DDI_SUCCESS); 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * free_pci_properties: 1290Sstevel@tonic-gate * 1300Sstevel@tonic-gate * This routine frees the memory used to cache the 1310Sstevel@tonic-gate * "ranges" properties of the pci bus device node. 1320Sstevel@tonic-gate * 1330Sstevel@tonic-gate * used by: pci_detach() 1340Sstevel@tonic-gate * 1350Sstevel@tonic-gate * return value: none 1360Sstevel@tonic-gate */ 1370Sstevel@tonic-gate void 1380Sstevel@tonic-gate free_pci_properties(pci_t *pci_p) 1390Sstevel@tonic-gate { 1400Sstevel@tonic-gate kmem_free(pci_p->pci_ranges, pci_p->pci_ranges_length); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate /* 1440Sstevel@tonic-gate * pci_reloc_reg 1450Sstevel@tonic-gate * 1460Sstevel@tonic-gate * If the "reg" entry (*pci_rp) is relocatable, lookup "assigned-addresses" 1470Sstevel@tonic-gate * property to fetch corresponding relocated address. 1480Sstevel@tonic-gate * 1490Sstevel@tonic-gate * used by: pci_map() 1500Sstevel@tonic-gate * 1510Sstevel@tonic-gate * return value: 1520Sstevel@tonic-gate * 1530Sstevel@tonic-gate * DDI_SUCCESS - on success 1540Sstevel@tonic-gate * DDI_ME_INVAL - regspec is invalid 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate int 1570Sstevel@tonic-gate pci_reloc_reg(dev_info_t *dip, dev_info_t *rdip, pci_t *pci_p, 1580Sstevel@tonic-gate pci_regspec_t *rp) 1590Sstevel@tonic-gate { 1600Sstevel@tonic-gate int assign_len, assign_entries, i; 1610Sstevel@tonic-gate pci_regspec_t *assign_p; 1620Sstevel@tonic-gate register uint32_t phys_hi = rp->pci_phys_hi; 1630Sstevel@tonic-gate register uint32_t mask = PCI_REG_ADDR_M | PCI_CONF_ADDR_MASK; 1640Sstevel@tonic-gate register uint32_t phys_addr = phys_hi & mask; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate DEBUG5(DBG_MAP | DBG_CONT, dip, "\tpci_reloc_reg fr: %x.%x.%x %x.%x\n", 1670Sstevel@tonic-gate rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, 1680Sstevel@tonic-gate rp->pci_size_hi, rp->pci_size_low); 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate if ((phys_hi & PCI_RELOCAT_B) || !(phys_hi & PCI_ADDR_MASK)) 1710Sstevel@tonic-gate return (DDI_SUCCESS); 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate if (pci_p->hotplug_capable == B_FALSE) { /* validate bus # */ 1740Sstevel@tonic-gate uint32_t bus = PCI_REG_BUS_G(phys_hi); 1750Sstevel@tonic-gate if (bus < pci_p->pci_bus_range.lo || 1760Sstevel@tonic-gate bus > pci_p->pci_bus_range.hi) { 1770Sstevel@tonic-gate DEBUG1(DBG_MAP | DBG_CONT, dip, "bad bus# (%x)\n", bus); 1780Sstevel@tonic-gate return (DDI_ME_INVAL); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* phys_mid must be 0 regardless space type. */ 1830Sstevel@tonic-gate if (rp->pci_phys_mid != 0 || rp->pci_size_hi != 0) { 1840Sstevel@tonic-gate DEBUG0(DBG_MAP | DBG_CONT, pci_p->pci_dip, 1850Sstevel@tonic-gate "phys_mid or size_hi not 0\n"); 1860Sstevel@tonic-gate return (DDI_ME_INVAL); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 1900Sstevel@tonic-gate "assigned-addresses", (caddr_t)&assign_p, &assign_len)) 1910Sstevel@tonic-gate return (DDI_ME_INVAL); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate assign_entries = assign_len / sizeof (pci_regspec_t); 1940Sstevel@tonic-gate for (i = 0; i < assign_entries; i++, assign_p++) { 1950Sstevel@tonic-gate if ((assign_p->pci_phys_hi & mask) == phys_addr) { 1960Sstevel@tonic-gate rp->pci_phys_low += assign_p->pci_phys_low; 1970Sstevel@tonic-gate break; 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate kmem_free(assign_p - i, assign_len); 2010Sstevel@tonic-gate DEBUG5(DBG_MAP | DBG_CONT, dip, "\tpci_reloc_reg to: %x.%x.%x %x.%x\n", 2020Sstevel@tonic-gate rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, 2030Sstevel@tonic-gate rp->pci_size_hi, rp->pci_size_low); 2040Sstevel@tonic-gate return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate /* 2080Sstevel@tonic-gate * use "ranges" to translate relocated pci regspec into parent space 2090Sstevel@tonic-gate */ 2100Sstevel@tonic-gate int 2110Sstevel@tonic-gate pci_xlate_reg(pci_t *pci_p, pci_regspec_t *pci_rp, struct regspec *new_rp) 2120Sstevel@tonic-gate { 2130Sstevel@tonic-gate int n; 2140Sstevel@tonic-gate pci_ranges_t *rng_p = pci_p->pci_ranges; 2150Sstevel@tonic-gate int rng_n = pci_p->pci_ranges_length / sizeof (pci_ranges_t); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate uint32_t space_type = PCI_REG_ADDR_G(pci_rp->pci_phys_hi); 2180Sstevel@tonic-gate uint32_t reg_end, reg_begin = pci_rp->pci_phys_low; 2190Sstevel@tonic-gate uint32_t sz = pci_rp->pci_size_low; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate uint32_t rng_begin, rng_end; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 2240Sstevel@tonic-gate if (reg_begin > PCI_CONF_HDR_SIZE) 2250Sstevel@tonic-gate return (DDI_ME_INVAL); 2260Sstevel@tonic-gate sz = sz ? MIN(sz, PCI_CONF_HDR_SIZE) : PCI_CONF_HDR_SIZE; 2270Sstevel@tonic-gate reg_begin += pci_rp->pci_phys_hi; 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate reg_end = reg_begin + sz - 1; 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate for (n = 0; n < rng_n; n++, rng_p++) { 2320Sstevel@tonic-gate if (space_type != PCI_REG_ADDR_G(rng_p->child_high)) 2330Sstevel@tonic-gate continue; /* not the same space type */ 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate rng_begin = rng_p->child_low; 2360Sstevel@tonic-gate if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) 2370Sstevel@tonic-gate rng_begin += rng_p->child_high; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate rng_end = rng_begin + rng_p->size_low - 1; 2400Sstevel@tonic-gate if (reg_begin >= rng_begin && reg_end <= rng_end) 2410Sstevel@tonic-gate break; 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate if (n >= rng_n) 2440Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate new_rp->regspec_addr = reg_begin - rng_begin + rng_p->parent_low; 2470Sstevel@tonic-gate new_rp->regspec_bustype = rng_p->parent_high; 2480Sstevel@tonic-gate new_rp->regspec_size = sz; 2490Sstevel@tonic-gate DEBUG4(DBG_MAP | DBG_CONT, pci_p->pci_dip, 2500Sstevel@tonic-gate "\tpci_xlate_reg: entry %d new_rp %x.%x %x\n", 2510Sstevel@tonic-gate n, new_rp->regspec_bustype, new_rp->regspec_addr, sz); 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate return (DDI_SUCCESS); 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate /* 2580Sstevel@tonic-gate * report_dev 2590Sstevel@tonic-gate * 2600Sstevel@tonic-gate * This function is called from our control ops routine on a 2610Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV request. 2620Sstevel@tonic-gate * 2630Sstevel@tonic-gate * The display format is 2640Sstevel@tonic-gate * 2650Sstevel@tonic-gate * <name><inst> at <pname><pinst> device <dev> function <func> 2660Sstevel@tonic-gate * 2670Sstevel@tonic-gate * where 2680Sstevel@tonic-gate * 2690Sstevel@tonic-gate * <name> this device's name property 2700Sstevel@tonic-gate * <inst> this device's instance number 2710Sstevel@tonic-gate * <name> parent device's name property 2720Sstevel@tonic-gate * <inst> parent device's instance number 2730Sstevel@tonic-gate * <dev> this device's device number 2740Sstevel@tonic-gate * <func> this device's function number 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate int 2770Sstevel@tonic-gate report_dev(dev_info_t *dip) 2780Sstevel@tonic-gate { 2790Sstevel@tonic-gate if (dip == (dev_info_t *)0) 2800Sstevel@tonic-gate return (DDI_FAILURE); 2810Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 2820Sstevel@tonic-gate ddi_node_name(dip), ddi_get_name_addr(dip), 2830Sstevel@tonic-gate ddi_driver_name(dip), 2840Sstevel@tonic-gate ddi_get_instance(dip)); 2850Sstevel@tonic-gate return (DDI_SUCCESS); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* 2900Sstevel@tonic-gate * reg property for pcimem nodes that covers the entire address 2910Sstevel@tonic-gate * space for the node: config, io, or memory. 2920Sstevel@tonic-gate */ 2930Sstevel@tonic-gate pci_regspec_t pci_pcimem_reg[3] = 2940Sstevel@tonic-gate { 2950Sstevel@tonic-gate {PCI_ADDR_CONFIG, 0, 0, 0, 0x800000 }, 2960Sstevel@tonic-gate {(uint_t)(PCI_ADDR_IO|PCI_RELOCAT_B), 0, 0, 0, PCI_IO_SIZE }, 2970Sstevel@tonic-gate {(uint_t)(PCI_ADDR_MEM32|PCI_RELOCAT_B), 0, 0, 0, PCI_MEM_SIZE } 2980Sstevel@tonic-gate }; 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * name_child 3020Sstevel@tonic-gate * 3030Sstevel@tonic-gate * This function is called from init_child to name a node. It is 3040Sstevel@tonic-gate * also passed as a callback for node merging functions. 3050Sstevel@tonic-gate * 3060Sstevel@tonic-gate * return value: DDI_SUCCESS, DDI_FAILURE 3070Sstevel@tonic-gate */ 3080Sstevel@tonic-gate static int 3090Sstevel@tonic-gate name_child(dev_info_t *child, char *name, int namelen) 3100Sstevel@tonic-gate { 3110Sstevel@tonic-gate pci_regspec_t *pci_rp; 3120Sstevel@tonic-gate int reglen; 3130Sstevel@tonic-gate uint_t func; 3140Sstevel@tonic-gate char **unit_addr; 3150Sstevel@tonic-gate uint_t n; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * Set the address portion of the node name based on 3190Sstevel@tonic-gate * unit-address property, if it exists. 3200Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 3210Sstevel@tonic-gate * where DD is the device id and F is the function. 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 3240Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) == 3250Sstevel@tonic-gate DDI_PROP_SUCCESS) { 3260Sstevel@tonic-gate if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 3270Sstevel@tonic-gate cmn_err(CE_WARN, "unit-address property in %s.conf" 3280Sstevel@tonic-gate " not well-formed", ddi_driver_name(child)); 3290Sstevel@tonic-gate ddi_prop_free(unit_addr); 3300Sstevel@tonic-gate return (DDI_FAILURE); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate (void) snprintf(name, namelen, "%s", *unit_addr); 3330Sstevel@tonic-gate ddi_prop_free(unit_addr); 3340Sstevel@tonic-gate return (DDI_SUCCESS); 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate /* 3380Sstevel@tonic-gate * The unit-address property is does not exist. Set the address 3390Sstevel@tonic-gate * portion of the node name based on the function and device number. 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 3420Sstevel@tonic-gate "reg", (int **)&pci_rp, (uint_t *)®len) == DDI_SUCCESS) { 3430Sstevel@tonic-gate if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) { 3440Sstevel@tonic-gate cmn_err(CE_WARN, "reg property not well-formed"); 3450Sstevel@tonic-gate return (DDI_FAILURE); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi); 3490Sstevel@tonic-gate if (func != 0) 3500Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 3510Sstevel@tonic-gate PCI_REG_DEV_G(pci_rp[0].pci_phys_hi), func); 3520Sstevel@tonic-gate else 3530Sstevel@tonic-gate (void) snprintf(name, namelen, "%x", 3540Sstevel@tonic-gate PCI_REG_DEV_G(pci_rp[0].pci_phys_hi)); 3550Sstevel@tonic-gate ddi_prop_free(pci_rp); 3560Sstevel@tonic-gate return (DDI_SUCCESS); 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child)); 3600Sstevel@tonic-gate return (DDI_FAILURE); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate int 3640Sstevel@tonic-gate uninit_child(pci_t *pci_p, dev_info_t *child) 3650Sstevel@tonic-gate { 3660Sstevel@tonic-gate DEBUG2(DBG_CTLOPS, pci_p->pci_dip, 3670Sstevel@tonic-gate "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n", 3680Sstevel@tonic-gate ddi_driver_name(child), ddi_get_instance(child)); 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate (void) pm_uninit_child(child); 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 3740Sstevel@tonic-gate ddi_remove_minor_node(child, NULL); 3750Sstevel@tonic-gate impl_rem_dev_props(child); 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate DEBUG0(DBG_PWR, ddi_get_parent(child), "\n\n"); 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate /* 3800Sstevel@tonic-gate * Handle chip specific post-uninit-child tasks. 3810Sstevel@tonic-gate */ 3820Sstevel@tonic-gate pci_post_uninit_child(pci_p); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate return (DDI_SUCCESS); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate /* 3880Sstevel@tonic-gate * init_child 3890Sstevel@tonic-gate * 3900Sstevel@tonic-gate * This function is called from our control ops routine on a 3910Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD request. It builds and sets the device's 3920Sstevel@tonic-gate * parent private data area. 3930Sstevel@tonic-gate * 3940Sstevel@tonic-gate * used by: pci_ctlops() 3950Sstevel@tonic-gate * 3960Sstevel@tonic-gate * return value: none 3970Sstevel@tonic-gate */ 3980Sstevel@tonic-gate int 3990Sstevel@tonic-gate init_child(pci_t *pci_p, dev_info_t *child) 4000Sstevel@tonic-gate { 4010Sstevel@tonic-gate pci_regspec_t *pci_rp; 4020Sstevel@tonic-gate char name[10]; 4030Sstevel@tonic-gate ddi_acc_handle_t config_handle; 4040Sstevel@tonic-gate uint16_t command_preserve, command; 4050Sstevel@tonic-gate uint8_t bcr; 4060Sstevel@tonic-gate uint8_t header_type, min_gnt; 4070Sstevel@tonic-gate uint16_t latency_timer; 4080Sstevel@tonic-gate uint_t n; 4090Sstevel@tonic-gate int i, no_config; 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* 4120Sstevel@tonic-gate * The following is a special case for pcimem nodes. 4130Sstevel@tonic-gate * For these nodes we create a reg property with a 4140Sstevel@tonic-gate * single entry that covers the entire address space 4150Sstevel@tonic-gate * for the node (config, io or memory). 4160Sstevel@tonic-gate */ 4170Sstevel@tonic-gate if (strcmp(ddi_driver_name(child), "pcimem") == 0) { 4180Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, child, 4190Sstevel@tonic-gate DDI_PROP_CANSLEEP, "reg", (caddr_t)pci_pcimem_reg, 4200Sstevel@tonic-gate sizeof (pci_pcimem_reg)); 4210Sstevel@tonic-gate ddi_set_name_addr(child, "0"); 4220Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 4230Sstevel@tonic-gate return (DDI_SUCCESS); 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate /* 4270Sstevel@tonic-gate * Check whether the node has config space or is a hard decode 4280Sstevel@tonic-gate * node (possibly created by a driver.conf file). 4290Sstevel@tonic-gate */ 4300Sstevel@tonic-gate no_config = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 4310Sstevel@tonic-gate "no-config", 0); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate /* 4340Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 4350Sstevel@tonic-gate * properties to be merged into the real h/w device node. 4360Sstevel@tonic-gate * However, do not merge if the no-config property is set 4370Sstevel@tonic-gate * (see PSARC 2000/088). 4380Sstevel@tonic-gate */ 4390Sstevel@tonic-gate if ((ndi_dev_is_persistent_node(child) == 0) && (no_config == 0)) { 4400Sstevel@tonic-gate extern int pci_allow_pseudo_children; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, 4430Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, &i) == 4440Sstevel@tonic-gate DDI_SUCCESS) { 4450Sstevel@tonic-gate cmn_err(CE_WARN, "cannot merge prototype from %s.conf", 4460Sstevel@tonic-gate ddi_driver_name(child)); 4470Sstevel@tonic-gate kmem_free(pci_rp, i); 4480Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * Name the child 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate if (name_child(child, name, 10) != DDI_SUCCESS) 4540Sstevel@tonic-gate return (DDI_FAILURE); 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate ddi_set_name_addr(child, name); 4570Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate /* 4600Sstevel@tonic-gate * Try to merge the properties from this prototype 4610Sstevel@tonic-gate * node into real h/w nodes. 4620Sstevel@tonic-gate */ 4630Sstevel@tonic-gate if (ndi_merge_node(child, name_child) == DDI_SUCCESS) { 4640Sstevel@tonic-gate /* 4650Sstevel@tonic-gate * Merged ok - return failure to remove the node. 4660Sstevel@tonic-gate */ 4670Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 4680Sstevel@tonic-gate return (DDI_FAILURE); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 4720Sstevel@tonic-gate if (pci_allow_pseudo_children) 4730Sstevel@tonic-gate return (DDI_SUCCESS); 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 4760Sstevel@tonic-gate ddi_driver_name(child), ddi_get_name_addr(child), 4770Sstevel@tonic-gate ddi_driver_name(child)); 4780Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 4790Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate if (name_child(child, name, 10) != DDI_SUCCESS) 4830Sstevel@tonic-gate return (DDI_FAILURE); 4840Sstevel@tonic-gate ddi_set_name_addr(child, name); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate if (no_config != 0) { 4870Sstevel@tonic-gate /* 4880Sstevel@tonic-gate * There is no config space so there's nothing more to do. 4890Sstevel@tonic-gate */ 4900Sstevel@tonic-gate return (DDI_SUCCESS); 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate if (pm_init_child(child) != DDI_SUCCESS) 4940Sstevel@tonic-gate return (DDI_FAILURE); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate /* 4980Sstevel@tonic-gate * If configuration registers were previously saved by 4990Sstevel@tonic-gate * child (before it went to D3), then let the child do the 5000Sstevel@tonic-gate * restore to set up the config regs as it'll first need to 5010Sstevel@tonic-gate * power the device out of D3. 5020Sstevel@tonic-gate */ 5030Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 5040Sstevel@tonic-gate "config-regs-saved-by-child") == 1) { 5050Sstevel@tonic-gate DEBUG0(DBG_PWR, child, 5060Sstevel@tonic-gate "INITCHILD: config regs to be restored by child\n"); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate return (DDI_SUCCESS); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate DEBUG2(DBG_PWR, ddi_get_parent(child), 5120Sstevel@tonic-gate "INITCHILD: config regs setup for %s@%s\n", 5130Sstevel@tonic-gate ddi_node_name(child), ddi_get_name_addr(child)); 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate /* 5160Sstevel@tonic-gate * Map the child configuration space to for initialization. 5170Sstevel@tonic-gate * We assume the obp will do the following in the devices 5180Sstevel@tonic-gate * config space: 5190Sstevel@tonic-gate * 5200Sstevel@tonic-gate * Set the latency-timer register to values appropriate 5210Sstevel@tonic-gate * for the devices on the bus (based on other devices 5220Sstevel@tonic-gate * MIN_GNT and MAX_LAT registers. 5230Sstevel@tonic-gate * 5240Sstevel@tonic-gate * Set the fast back-to-back enable bit in the command 5250Sstevel@tonic-gate * register if it's supported and all devices on the bus 5260Sstevel@tonic-gate * have the capability. 5270Sstevel@tonic-gate * 5280Sstevel@tonic-gate */ 5290Sstevel@tonic-gate if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { 5300Sstevel@tonic-gate (void) pm_uninit_child(child); 5310Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate return (DDI_FAILURE); 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate /* 5370Sstevel@tonic-gate * Determine the configuration header type. 5380Sstevel@tonic-gate */ 5390Sstevel@tonic-gate header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); 5400Sstevel@tonic-gate DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: header_type=%x\n", 5410Sstevel@tonic-gate ddi_driver_name(child), header_type); 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /* 5440Sstevel@tonic-gate * Support for "command-preserve" property. Note that we 5450Sstevel@tonic-gate * add PCI_COMM_BACK2BACK_ENAB to the bits to be preserved 5460Sstevel@tonic-gate * since the obp will set this if the device supports and 5470Sstevel@tonic-gate * all targets on the same bus support it. Since psycho 5480Sstevel@tonic-gate * doesn't support PCI_COMM_BACK2BACK_ENAB, it will never 5490Sstevel@tonic-gate * be set. This is just here in case future revs do support 5500Sstevel@tonic-gate * PCI_COMM_BACK2BACK_ENAB. 5510Sstevel@tonic-gate */ 5520Sstevel@tonic-gate command_preserve = 5530Sstevel@tonic-gate ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 5540Sstevel@tonic-gate "command-preserve", 0); 5550Sstevel@tonic-gate DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: command-preserve=%x\n", 5560Sstevel@tonic-gate ddi_driver_name(child), command_preserve); 5570Sstevel@tonic-gate command = pci_config_get16(config_handle, PCI_CONF_COMM); 5580Sstevel@tonic-gate command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 5590Sstevel@tonic-gate command |= (pci_command_default & ~command_preserve); 5600Sstevel@tonic-gate pci_config_put16(config_handle, PCI_CONF_COMM, command); 5610Sstevel@tonic-gate command = pci_config_get16(config_handle, PCI_CONF_COMM); 5620Sstevel@tonic-gate DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: command=%x\n", 5630Sstevel@tonic-gate ddi_driver_name(child), 5640Sstevel@tonic-gate pci_config_get16(config_handle, PCI_CONF_COMM)); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * If the device has a bus control register then program it 5680Sstevel@tonic-gate * based on the settings in the command register. 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 5710Sstevel@tonic-gate bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL); 5720Sstevel@tonic-gate if (pci_command_default & PCI_COMM_PARITY_DETECT) 5730Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 5740Sstevel@tonic-gate if (pci_command_default & PCI_COMM_SERR_ENABLE) 5750Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE; 5760Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 5770Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate /* 5810Sstevel@tonic-gate * Initialize cache-line-size configuration register if needed. 5820Sstevel@tonic-gate */ 5830Sstevel@tonic-gate if (pci_set_cache_line_size_register && 5840Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 5850Sstevel@tonic-gate "cache-line-size", 0) == 0) { 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ, 5880Sstevel@tonic-gate PCI_CACHE_LINE_SIZE); 5890Sstevel@tonic-gate n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ); 5900Sstevel@tonic-gate if (n != 0) 5910Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, 5920Sstevel@tonic-gate "cache-line-size", n); 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate /* 5960Sstevel@tonic-gate * Initialize latency timer registers if needed. 5970Sstevel@tonic-gate */ 5980Sstevel@tonic-gate if (pci_set_latency_timer_register && 5990Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 6000Sstevel@tonic-gate "latency-timer", 0) == 0) { 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate latency_timer = pci_latency_timer; 6030Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 6040Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER, 6050Sstevel@tonic-gate latency_timer); 6060Sstevel@tonic-gate } else { 6070Sstevel@tonic-gate min_gnt = pci_config_get8(config_handle, 6080Sstevel@tonic-gate PCI_CONF_MIN_G); 6090Sstevel@tonic-gate DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: min_gnt=%x\n", 6100Sstevel@tonic-gate ddi_driver_name(child), min_gnt); 6110Sstevel@tonic-gate if (min_gnt != 0) { 6120Sstevel@tonic-gate switch (pci_p->pci_pbm_p->pbm_speed) { 6130Sstevel@tonic-gate case PBM_SPEED_33MHZ: 6140Sstevel@tonic-gate latency_timer = min_gnt * 8; 6150Sstevel@tonic-gate break; 6160Sstevel@tonic-gate case PBM_SPEED_66MHZ: 6170Sstevel@tonic-gate latency_timer = min_gnt * 4; 6180Sstevel@tonic-gate break; 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate latency_timer = MIN(latency_timer, 0xff); 6230Sstevel@tonic-gate pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER, 6240Sstevel@tonic-gate latency_timer); 6250Sstevel@tonic-gate n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER); 6260Sstevel@tonic-gate if (n != 0) 6270Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, 6280Sstevel@tonic-gate "latency-timer", n); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate pci_config_teardown(&config_handle); 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate /* 6340Sstevel@tonic-gate * Handle chip specific init-child tasks. 6350Sstevel@tonic-gate */ 6360Sstevel@tonic-gate pci_post_init_child(pci_p, child); 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate return (DDI_SUCCESS); 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate /* 6420Sstevel@tonic-gate * get_nreg_set 6430Sstevel@tonic-gate * 6440Sstevel@tonic-gate * Given a dev info pointer to a pci child, this routine returns the 6450Sstevel@tonic-gate * number of sets in its "reg" property. 6460Sstevel@tonic-gate * 6470Sstevel@tonic-gate * used by: pci_ctlops() - DDI_CTLOPS_NREGS 6480Sstevel@tonic-gate * 6490Sstevel@tonic-gate * return value: # of reg sets on success, zero on error 6500Sstevel@tonic-gate */ 6510Sstevel@tonic-gate uint_t 6520Sstevel@tonic-gate get_nreg_set(dev_info_t *child) 6530Sstevel@tonic-gate { 6540Sstevel@tonic-gate pci_regspec_t *pci_rp; 6550Sstevel@tonic-gate int i, n; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate /* 6580Sstevel@tonic-gate * Get the reg property for the device. 6590Sstevel@tonic-gate */ 6600Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 6610Sstevel@tonic-gate (caddr_t)&pci_rp, &i) != DDI_SUCCESS) 6620Sstevel@tonic-gate return (0); 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate n = i / (int)sizeof (pci_regspec_t); 6650Sstevel@tonic-gate kmem_free(pci_rp, i); 6660Sstevel@tonic-gate return (n); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * get_nintr 6720Sstevel@tonic-gate * 6730Sstevel@tonic-gate * Given a dev info pointer to a pci child, this routine returns the 6740Sstevel@tonic-gate * number of items in its "interrupts" property. 6750Sstevel@tonic-gate * 6760Sstevel@tonic-gate * used by: pci_ctlops() - DDI_CTLOPS_NREGS 6770Sstevel@tonic-gate * 6780Sstevel@tonic-gate * return value: # of interrupts on success, zero on error 6790Sstevel@tonic-gate */ 6800Sstevel@tonic-gate uint_t 6810Sstevel@tonic-gate get_nintr(dev_info_t *child) 6820Sstevel@tonic-gate { 6830Sstevel@tonic-gate int *pci_ip; 6840Sstevel@tonic-gate int i, n; 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 6870Sstevel@tonic-gate "interrupts", (caddr_t)&pci_ip, &i) != DDI_SUCCESS) 6880Sstevel@tonic-gate return (0); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate n = i / (int)sizeof (uint_t); 6910Sstevel@tonic-gate kmem_free(pci_ip, i); 6920Sstevel@tonic-gate return (n); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate uint64_t 6960Sstevel@tonic-gate pci_get_cfg_pabase(pci_t *pci_p) 6970Sstevel@tonic-gate { 6980Sstevel@tonic-gate int i; 6990Sstevel@tonic-gate pci_ranges_t *rangep = pci_p->pci_ranges; 7000Sstevel@tonic-gate int nrange = pci_p->pci_ranges_length / sizeof (pci_ranges_t); 7010Sstevel@tonic-gate uint32_t cfg_space_type = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate ASSERT(cfg_space_type == 0); 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate for (i = 0; i < nrange; i++, rangep++) { 7060Sstevel@tonic-gate if (PCI_REG_ADDR_G(rangep->child_high) == cfg_space_type) 7070Sstevel@tonic-gate break; 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate if (i >= nrange) 711*946Smathue cmn_err(CE_PANIC, "no cfg space in pci(%p) ranges prop.\n", 7120Sstevel@tonic-gate (void *)pci_p); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate return (((uint64_t)rangep->parent_high << 32) | rangep->parent_low); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate int 7180Sstevel@tonic-gate pci_cfg_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_errstate_t *pci_err_p, 7190Sstevel@tonic-gate int caller, uint32_t prierr) 7200Sstevel@tonic-gate { 7210Sstevel@tonic-gate int fatal = 0; 7220Sstevel@tonic-gate int nonfatal = 0; 7230Sstevel@tonic-gate int i; 7240Sstevel@tonic-gate pci_target_err_t tgt_err; 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate ASSERT(dip); 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate derr->fme_ena = derr->fme_ena ? derr->fme_ena : 7290Sstevel@tonic-gate fm_ena_generate(0, FM_ENA_FMT1); 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 7320Sstevel@tonic-gate if (pci_err_p->pci_cfg_stat & pci_err_tbl[i].reg_bit) { 7330Sstevel@tonic-gate char buf[FM_MAX_CLASS]; 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 7360Sstevel@tonic-gate PCI_ERROR_SUBCLASS, 7370Sstevel@tonic-gate pci_err_tbl[i].err_class); 7380Sstevel@tonic-gate ddi_fm_ereport_post(dip, buf, derr->fme_ena, 7390Sstevel@tonic-gate DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 7400Sstevel@tonic-gate PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 7410Sstevel@tonic-gate pci_err_p->pci_cfg_stat, 7420Sstevel@tonic-gate PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 7430Sstevel@tonic-gate pci_err_p->pci_cfg_comm, 7440Sstevel@tonic-gate PCI_PA, DATA_TYPE_UINT64, 7450Sstevel@tonic-gate pci_err_p->pci_pa, 7460Sstevel@tonic-gate NULL); 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate switch (pci_err_tbl[i].reg_bit) { 7490Sstevel@tonic-gate case PCI_STAT_S_SYSERR: 7500Sstevel@tonic-gate /* 7510Sstevel@tonic-gate * address parity error on dma - treat as fatal 7520Sstevel@tonic-gate */ 7530Sstevel@tonic-gate fatal++; 7540Sstevel@tonic-gate break; 7550Sstevel@tonic-gate case PCI_STAT_R_MAST_AB: 7560Sstevel@tonic-gate case PCI_STAT_R_TARG_AB: 7570Sstevel@tonic-gate case PCI_STAT_S_PERROR: 7580Sstevel@tonic-gate if (prierr) { 7590Sstevel@tonic-gate /* 7600Sstevel@tonic-gate * piow case are already handled in 7610Sstevel@tonic-gate * pbm_afsr_report() 7620Sstevel@tonic-gate */ 7630Sstevel@tonic-gate break; 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate if (caller != PCI_TRAP_CALL) { 7660Sstevel@tonic-gate /* 7670Sstevel@tonic-gate * if we haven't come from trap handler 7680Sstevel@tonic-gate * we won't have an address 7690Sstevel@tonic-gate */ 7700Sstevel@tonic-gate fatal++; 7710Sstevel@tonic-gate break; 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate /* 7750Sstevel@tonic-gate * queue target ereport - use return from 7760Sstevel@tonic-gate * pci_lookup_handle() to determine if sync 7770Sstevel@tonic-gate * or async 7780Sstevel@tonic-gate */ 7790Sstevel@tonic-gate tgt_err.tgt_err_ena = derr->fme_ena; 7800Sstevel@tonic-gate tgt_err.tgt_err_class = 7810Sstevel@tonic-gate pci_err_tbl[i].terr_class; 7820Sstevel@tonic-gate tgt_err.tgt_bridge_type = PCI_ERROR_SUBCLASS; 7830Sstevel@tonic-gate tgt_err.tgt_err_addr = 7840Sstevel@tonic-gate (uint64_t)derr->fme_bus_specific; 7850Sstevel@tonic-gate nonfatal++; 7860Sstevel@tonic-gate errorq_dispatch(pci_target_queue, 7870Sstevel@tonic-gate (void *)&tgt_err, 7880Sstevel@tonic-gate sizeof (pci_target_err_t), 7890Sstevel@tonic-gate ERRORQ_ASYNC); 7900Sstevel@tonic-gate break; 7910Sstevel@tonic-gate default: 7920Sstevel@tonic-gate /* 7930Sstevel@tonic-gate * dpe on dma write or ta on dma 7940Sstevel@tonic-gate */ 7950Sstevel@tonic-gate nonfatal++; 7960Sstevel@tonic-gate break; 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate if (fatal) 8020Sstevel@tonic-gate return (DDI_FM_FATAL); 8030Sstevel@tonic-gate else if (nonfatal) 8040Sstevel@tonic-gate return (DDI_FM_NONFATAL); 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate return (DDI_FM_OK); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate void 8100Sstevel@tonic-gate pci_child_cfg_save(dev_info_t *dip) 8110Sstevel@tonic-gate { 8120Sstevel@tonic-gate dev_info_t *cdip; 8130Sstevel@tonic-gate int ret = DDI_SUCCESS; 8140Sstevel@tonic-gate 8150Sstevel@tonic-gate /* 8160Sstevel@tonic-gate * Save the state of the configuration headers of child 8170Sstevel@tonic-gate * nodes. 8180Sstevel@tonic-gate */ 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip != NULL; 8210Sstevel@tonic-gate cdip = ddi_get_next_sibling(cdip)) { 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * Not interested in children who are not already 8250Sstevel@tonic-gate * init'ed. They will be set up in init_child(). 8260Sstevel@tonic-gate */ 8270Sstevel@tonic-gate if (i_ddi_node_state(cdip) < DS_INITIALIZED) { 8280Sstevel@tonic-gate DEBUG2(DBG_DETACH, dip, "DDI_SUSPEND: skipping " 8290Sstevel@tonic-gate "%s%d not in CF1\n", ddi_driver_name(cdip), 8300Sstevel@tonic-gate ddi_get_instance(cdip)); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate continue; 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* 8360Sstevel@tonic-gate * Only save config registers if not already saved by child. 8370Sstevel@tonic-gate */ 8380Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 8390Sstevel@tonic-gate SAVED_CONFIG_REGS) == 1) { 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate continue; 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate /* 8450Sstevel@tonic-gate * The nexus needs to save config registers. Create a property 8460Sstevel@tonic-gate * so it knows to restore on resume. 8470Sstevel@tonic-gate */ 8480Sstevel@tonic-gate ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, 8490Sstevel@tonic-gate "nexus-saved-config-regs"); 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) { 8520Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d can't update prop %s", 8530Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip), 8540Sstevel@tonic-gate "nexus-saved-config-regs"); 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate (void) pci_save_config_regs(cdip); 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate } 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate void 8620Sstevel@tonic-gate pci_child_cfg_restore(dev_info_t *dip) 8630Sstevel@tonic-gate { 8640Sstevel@tonic-gate dev_info_t *cdip; 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * Restore config registers for children that did not save 8680Sstevel@tonic-gate * their own registers. Children pwr states are UNKNOWN after 8690Sstevel@tonic-gate * a resume since it is possible for the PM framework to call 8700Sstevel@tonic-gate * resume without an actual power cycle. (ie if suspend fails). 8710Sstevel@tonic-gate */ 8720Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip != NULL; 8730Sstevel@tonic-gate cdip = ddi_get_next_sibling(cdip)) { 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /* 8760Sstevel@tonic-gate * Not interested in children who are not already 8770Sstevel@tonic-gate * init'ed. They will be set up by init_child(). 8780Sstevel@tonic-gate */ 8790Sstevel@tonic-gate if (i_ddi_node_state(cdip) < DS_INITIALIZED) { 8800Sstevel@tonic-gate DEBUG2(DBG_DETACH, dip, 8810Sstevel@tonic-gate "DDI_RESUME: skipping %s%d not in CF1\n", 8820Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip)); 8830Sstevel@tonic-gate continue; 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate /* 8870Sstevel@tonic-gate * Only restore config registers if saved by nexus. 8880Sstevel@tonic-gate */ 8890Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 8900Sstevel@tonic-gate "nexus-saved-config-regs") == 1) { 8910Sstevel@tonic-gate (void) pci_restore_config_regs(cdip); 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate DEBUG2(DBG_PWR, dip, 8940Sstevel@tonic-gate "DDI_RESUME: nexus restoring %s%d config regs\n", 8950Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip)); 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate if (ndi_prop_remove(DDI_DEV_T_NONE, cdip, 8980Sstevel@tonic-gate "nexus-saved-config-regs") != DDI_PROP_SUCCESS) { 8990Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d can't remove prop %s", 9000Sstevel@tonic-gate ddi_driver_name(cdip), 9010Sstevel@tonic-gate ddi_get_instance(cdip), 9020Sstevel@tonic-gate "nexus-saved-config-regs"); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate } 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate } 907