1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * PCI nexus utility routines: 31*0Sstevel@tonic-gate * property and config routines for attach() 32*0Sstevel@tonic-gate * reg/intr/range/assigned-address property routines for bus_map() 33*0Sstevel@tonic-gate * init_child() 34*0Sstevel@tonic-gate * fault handling 35*0Sstevel@tonic-gate */ 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #include <sys/types.h> 38*0Sstevel@tonic-gate #include <sys/kmem.h> 39*0Sstevel@tonic-gate #include <sys/async.h> 40*0Sstevel@tonic-gate #include <sys/sysmacros.h> 41*0Sstevel@tonic-gate #include <sys/sunddi.h> 42*0Sstevel@tonic-gate #include <sys/sunndi.h> 43*0Sstevel@tonic-gate #include <sys/fm/protocol.h> 44*0Sstevel@tonic-gate #include <sys/fm/io/pci.h> 45*0Sstevel@tonic-gate #include <sys/fm/util.h> 46*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 47*0Sstevel@tonic-gate #include <sys/pci/pci_obj.h> 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /*LINTLIBRARY*/ 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate /* 52*0Sstevel@tonic-gate * get_pci_properties 53*0Sstevel@tonic-gate * 54*0Sstevel@tonic-gate * This function is called from the attach routine to get the key 55*0Sstevel@tonic-gate * properties of the pci nodes. 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * used by: pci_attach() 58*0Sstevel@tonic-gate * 59*0Sstevel@tonic-gate * return value: DDI_FAILURE on failure 60*0Sstevel@tonic-gate */ 61*0Sstevel@tonic-gate int 62*0Sstevel@tonic-gate get_pci_properties(pci_t *pci_p, dev_info_t *dip) 63*0Sstevel@tonic-gate { 64*0Sstevel@tonic-gate int i; 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /* 67*0Sstevel@tonic-gate * Get the device's port id. 68*0Sstevel@tonic-gate */ 69*0Sstevel@tonic-gate if ((pci_p->pci_id = (uint32_t)pci_get_portid(dip)) == -1u) { 70*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no portid property\n", 71*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 72*0Sstevel@tonic-gate return (DDI_FAILURE); 73*0Sstevel@tonic-gate } 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate /* 76*0Sstevel@tonic-gate * Get the bus-ranges property. 77*0Sstevel@tonic-gate */ 78*0Sstevel@tonic-gate i = sizeof (pci_p->pci_bus_range); 79*0Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 80*0Sstevel@tonic-gate "bus-range", (caddr_t)&pci_p->pci_bus_range, &i) != DDI_SUCCESS) { 81*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no bus-range property\n", 82*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 83*0Sstevel@tonic-gate return (DDI_FAILURE); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate DEBUG2(DBG_ATTACH, dip, "get_pci_properties: bus-range (%x,%x)\n", 86*0Sstevel@tonic-gate pci_p->pci_bus_range.lo, pci_p->pci_bus_range.hi); 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * disable streaming cache if necessary, this must be done 90*0Sstevel@tonic-gate * before PBM is configured. 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 93*0Sstevel@tonic-gate "no-streaming-cache")) { 94*0Sstevel@tonic-gate pci_stream_buf_enable = 0; 95*0Sstevel@tonic-gate pci_stream_buf_exists = 0; 96*0Sstevel@tonic-gate } 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate /* 99*0Sstevel@tonic-gate * Get the ranges property. 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 102*0Sstevel@tonic-gate (caddr_t)&pci_p->pci_ranges, &pci_p->pci_ranges_length) != 103*0Sstevel@tonic-gate DDI_SUCCESS) { 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: no ranges property\n", 106*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 107*0Sstevel@tonic-gate return (DDI_FAILURE); 108*0Sstevel@tonic-gate } 109*0Sstevel@tonic-gate pci_fix_ranges(pci_p->pci_ranges, 110*0Sstevel@tonic-gate pci_p->pci_ranges_length / sizeof (pci_ranges_t)); 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate /* 113*0Sstevel@tonic-gate * Determine the number upa slot interrupts. 114*0Sstevel@tonic-gate */ 115*0Sstevel@tonic-gate pci_p->pci_numproxy = pci_get_numproxy(pci_p->pci_dip); 116*0Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "get_pci_properties: numproxy=%d\n", 117*0Sstevel@tonic-gate pci_p->pci_numproxy); 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate pci_p->pci_thermal_interrupt = 120*0Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 121*0Sstevel@tonic-gate "thermal-interrupt", -1); 122*0Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "get_pci_properties: thermal_interrupt=%d\n", 123*0Sstevel@tonic-gate pci_p->pci_thermal_interrupt); 124*0Sstevel@tonic-gate return (DDI_SUCCESS); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate /* 128*0Sstevel@tonic-gate * free_pci_properties: 129*0Sstevel@tonic-gate * 130*0Sstevel@tonic-gate * This routine frees the memory used to cache the 131*0Sstevel@tonic-gate * "ranges" properties of the pci bus device node. 132*0Sstevel@tonic-gate * 133*0Sstevel@tonic-gate * used by: pci_detach() 134*0Sstevel@tonic-gate * 135*0Sstevel@tonic-gate * return value: none 136*0Sstevel@tonic-gate */ 137*0Sstevel@tonic-gate void 138*0Sstevel@tonic-gate free_pci_properties(pci_t *pci_p) 139*0Sstevel@tonic-gate { 140*0Sstevel@tonic-gate kmem_free(pci_p->pci_ranges, pci_p->pci_ranges_length); 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate /* 144*0Sstevel@tonic-gate * pci_reloc_reg 145*0Sstevel@tonic-gate * 146*0Sstevel@tonic-gate * If the "reg" entry (*pci_rp) is relocatable, lookup "assigned-addresses" 147*0Sstevel@tonic-gate * property to fetch corresponding relocated address. 148*0Sstevel@tonic-gate * 149*0Sstevel@tonic-gate * used by: pci_map() 150*0Sstevel@tonic-gate * 151*0Sstevel@tonic-gate * return value: 152*0Sstevel@tonic-gate * 153*0Sstevel@tonic-gate * DDI_SUCCESS - on success 154*0Sstevel@tonic-gate * DDI_ME_INVAL - regspec is invalid 155*0Sstevel@tonic-gate */ 156*0Sstevel@tonic-gate int 157*0Sstevel@tonic-gate pci_reloc_reg(dev_info_t *dip, dev_info_t *rdip, pci_t *pci_p, 158*0Sstevel@tonic-gate pci_regspec_t *rp) 159*0Sstevel@tonic-gate { 160*0Sstevel@tonic-gate int assign_len, assign_entries, i; 161*0Sstevel@tonic-gate pci_regspec_t *assign_p; 162*0Sstevel@tonic-gate register uint32_t phys_hi = rp->pci_phys_hi; 163*0Sstevel@tonic-gate register uint32_t mask = PCI_REG_ADDR_M | PCI_CONF_ADDR_MASK; 164*0Sstevel@tonic-gate register uint32_t phys_addr = phys_hi & mask; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate DEBUG5(DBG_MAP | DBG_CONT, dip, "\tpci_reloc_reg fr: %x.%x.%x %x.%x\n", 167*0Sstevel@tonic-gate rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, 168*0Sstevel@tonic-gate rp->pci_size_hi, rp->pci_size_low); 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate if ((phys_hi & PCI_RELOCAT_B) || !(phys_hi & PCI_ADDR_MASK)) 171*0Sstevel@tonic-gate return (DDI_SUCCESS); 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate if (pci_p->hotplug_capable == B_FALSE) { /* validate bus # */ 174*0Sstevel@tonic-gate uint32_t bus = PCI_REG_BUS_G(phys_hi); 175*0Sstevel@tonic-gate if (bus < pci_p->pci_bus_range.lo || 176*0Sstevel@tonic-gate bus > pci_p->pci_bus_range.hi) { 177*0Sstevel@tonic-gate DEBUG1(DBG_MAP | DBG_CONT, dip, "bad bus# (%x)\n", bus); 178*0Sstevel@tonic-gate return (DDI_ME_INVAL); 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate /* phys_mid must be 0 regardless space type. */ 183*0Sstevel@tonic-gate if (rp->pci_phys_mid != 0 || rp->pci_size_hi != 0) { 184*0Sstevel@tonic-gate DEBUG0(DBG_MAP | DBG_CONT, pci_p->pci_dip, 185*0Sstevel@tonic-gate "phys_mid or size_hi not 0\n"); 186*0Sstevel@tonic-gate return (DDI_ME_INVAL); 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 190*0Sstevel@tonic-gate "assigned-addresses", (caddr_t)&assign_p, &assign_len)) 191*0Sstevel@tonic-gate return (DDI_ME_INVAL); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate assign_entries = assign_len / sizeof (pci_regspec_t); 194*0Sstevel@tonic-gate for (i = 0; i < assign_entries; i++, assign_p++) { 195*0Sstevel@tonic-gate if ((assign_p->pci_phys_hi & mask) == phys_addr) { 196*0Sstevel@tonic-gate rp->pci_phys_low += assign_p->pci_phys_low; 197*0Sstevel@tonic-gate break; 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate kmem_free(assign_p - i, assign_len); 201*0Sstevel@tonic-gate DEBUG5(DBG_MAP | DBG_CONT, dip, "\tpci_reloc_reg to: %x.%x.%x %x.%x\n", 202*0Sstevel@tonic-gate rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, 203*0Sstevel@tonic-gate rp->pci_size_hi, rp->pci_size_low); 204*0Sstevel@tonic-gate return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate /* 208*0Sstevel@tonic-gate * use "ranges" to translate relocated pci regspec into parent space 209*0Sstevel@tonic-gate */ 210*0Sstevel@tonic-gate int 211*0Sstevel@tonic-gate pci_xlate_reg(pci_t *pci_p, pci_regspec_t *pci_rp, struct regspec *new_rp) 212*0Sstevel@tonic-gate { 213*0Sstevel@tonic-gate int n; 214*0Sstevel@tonic-gate pci_ranges_t *rng_p = pci_p->pci_ranges; 215*0Sstevel@tonic-gate int rng_n = pci_p->pci_ranges_length / sizeof (pci_ranges_t); 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate uint32_t space_type = PCI_REG_ADDR_G(pci_rp->pci_phys_hi); 218*0Sstevel@tonic-gate uint32_t reg_end, reg_begin = pci_rp->pci_phys_low; 219*0Sstevel@tonic-gate uint32_t sz = pci_rp->pci_size_low; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate uint32_t rng_begin, rng_end; 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 224*0Sstevel@tonic-gate if (reg_begin > PCI_CONF_HDR_SIZE) 225*0Sstevel@tonic-gate return (DDI_ME_INVAL); 226*0Sstevel@tonic-gate sz = sz ? MIN(sz, PCI_CONF_HDR_SIZE) : PCI_CONF_HDR_SIZE; 227*0Sstevel@tonic-gate reg_begin += pci_rp->pci_phys_hi; 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate reg_end = reg_begin + sz - 1; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate for (n = 0; n < rng_n; n++, rng_p++) { 232*0Sstevel@tonic-gate if (space_type != PCI_REG_ADDR_G(rng_p->child_high)) 233*0Sstevel@tonic-gate continue; /* not the same space type */ 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate rng_begin = rng_p->child_low; 236*0Sstevel@tonic-gate if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) 237*0Sstevel@tonic-gate rng_begin += rng_p->child_high; 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate rng_end = rng_begin + rng_p->size_low - 1; 240*0Sstevel@tonic-gate if (reg_begin >= rng_begin && reg_end <= rng_end) 241*0Sstevel@tonic-gate break; 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate if (n >= rng_n) 244*0Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate new_rp->regspec_addr = reg_begin - rng_begin + rng_p->parent_low; 247*0Sstevel@tonic-gate new_rp->regspec_bustype = rng_p->parent_high; 248*0Sstevel@tonic-gate new_rp->regspec_size = sz; 249*0Sstevel@tonic-gate DEBUG4(DBG_MAP | DBG_CONT, pci_p->pci_dip, 250*0Sstevel@tonic-gate "\tpci_xlate_reg: entry %d new_rp %x.%x %x\n", 251*0Sstevel@tonic-gate n, new_rp->regspec_bustype, new_rp->regspec_addr, sz); 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate return (DDI_SUCCESS); 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * report_dev 259*0Sstevel@tonic-gate * 260*0Sstevel@tonic-gate * This function is called from our control ops routine on a 261*0Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV request. 262*0Sstevel@tonic-gate * 263*0Sstevel@tonic-gate * The display format is 264*0Sstevel@tonic-gate * 265*0Sstevel@tonic-gate * <name><inst> at <pname><pinst> device <dev> function <func> 266*0Sstevel@tonic-gate * 267*0Sstevel@tonic-gate * where 268*0Sstevel@tonic-gate * 269*0Sstevel@tonic-gate * <name> this device's name property 270*0Sstevel@tonic-gate * <inst> this device's instance number 271*0Sstevel@tonic-gate * <name> parent device's name property 272*0Sstevel@tonic-gate * <inst> parent device's instance number 273*0Sstevel@tonic-gate * <dev> this device's device number 274*0Sstevel@tonic-gate * <func> this device's function number 275*0Sstevel@tonic-gate */ 276*0Sstevel@tonic-gate int 277*0Sstevel@tonic-gate report_dev(dev_info_t *dip) 278*0Sstevel@tonic-gate { 279*0Sstevel@tonic-gate if (dip == (dev_info_t *)0) 280*0Sstevel@tonic-gate return (DDI_FAILURE); 281*0Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 282*0Sstevel@tonic-gate ddi_node_name(dip), ddi_get_name_addr(dip), 283*0Sstevel@tonic-gate ddi_driver_name(dip), 284*0Sstevel@tonic-gate ddi_get_instance(dip)); 285*0Sstevel@tonic-gate return (DDI_SUCCESS); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /* 290*0Sstevel@tonic-gate * reg property for pcimem nodes that covers the entire address 291*0Sstevel@tonic-gate * space for the node: config, io, or memory. 292*0Sstevel@tonic-gate */ 293*0Sstevel@tonic-gate pci_regspec_t pci_pcimem_reg[3] = 294*0Sstevel@tonic-gate { 295*0Sstevel@tonic-gate {PCI_ADDR_CONFIG, 0, 0, 0, 0x800000 }, 296*0Sstevel@tonic-gate {(uint_t)(PCI_ADDR_IO|PCI_RELOCAT_B), 0, 0, 0, PCI_IO_SIZE }, 297*0Sstevel@tonic-gate {(uint_t)(PCI_ADDR_MEM32|PCI_RELOCAT_B), 0, 0, 0, PCI_MEM_SIZE } 298*0Sstevel@tonic-gate }; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * name_child 302*0Sstevel@tonic-gate * 303*0Sstevel@tonic-gate * This function is called from init_child to name a node. It is 304*0Sstevel@tonic-gate * also passed as a callback for node merging functions. 305*0Sstevel@tonic-gate * 306*0Sstevel@tonic-gate * return value: DDI_SUCCESS, DDI_FAILURE 307*0Sstevel@tonic-gate */ 308*0Sstevel@tonic-gate static int 309*0Sstevel@tonic-gate name_child(dev_info_t *child, char *name, int namelen) 310*0Sstevel@tonic-gate { 311*0Sstevel@tonic-gate pci_regspec_t *pci_rp; 312*0Sstevel@tonic-gate int reglen; 313*0Sstevel@tonic-gate uint_t func; 314*0Sstevel@tonic-gate char **unit_addr; 315*0Sstevel@tonic-gate uint_t n; 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate /* 318*0Sstevel@tonic-gate * Set the address portion of the node name based on 319*0Sstevel@tonic-gate * unit-address property, if it exists. 320*0Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 321*0Sstevel@tonic-gate * where DD is the device id and F is the function. 322*0Sstevel@tonic-gate */ 323*0Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 324*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) == 325*0Sstevel@tonic-gate DDI_PROP_SUCCESS) { 326*0Sstevel@tonic-gate if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 327*0Sstevel@tonic-gate cmn_err(CE_WARN, "unit-address property in %s.conf" 328*0Sstevel@tonic-gate " not well-formed", ddi_driver_name(child)); 329*0Sstevel@tonic-gate ddi_prop_free(unit_addr); 330*0Sstevel@tonic-gate return (DDI_FAILURE); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%s", *unit_addr); 333*0Sstevel@tonic-gate ddi_prop_free(unit_addr); 334*0Sstevel@tonic-gate return (DDI_SUCCESS); 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate /* 338*0Sstevel@tonic-gate * The unit-address property is does not exist. Set the address 339*0Sstevel@tonic-gate * portion of the node name based on the function and device number. 340*0Sstevel@tonic-gate */ 341*0Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 342*0Sstevel@tonic-gate "reg", (int **)&pci_rp, (uint_t *)®len) == DDI_SUCCESS) { 343*0Sstevel@tonic-gate if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) { 344*0Sstevel@tonic-gate cmn_err(CE_WARN, "reg property not well-formed"); 345*0Sstevel@tonic-gate return (DDI_FAILURE); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi); 349*0Sstevel@tonic-gate if (func != 0) 350*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", 351*0Sstevel@tonic-gate PCI_REG_DEV_G(pci_rp[0].pci_phys_hi), func); 352*0Sstevel@tonic-gate else 353*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%x", 354*0Sstevel@tonic-gate PCI_REG_DEV_G(pci_rp[0].pci_phys_hi)); 355*0Sstevel@tonic-gate ddi_prop_free(pci_rp); 356*0Sstevel@tonic-gate return (DDI_SUCCESS); 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child)); 360*0Sstevel@tonic-gate return (DDI_FAILURE); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate int 364*0Sstevel@tonic-gate uninit_child(pci_t *pci_p, dev_info_t *child) 365*0Sstevel@tonic-gate { 366*0Sstevel@tonic-gate DEBUG2(DBG_CTLOPS, pci_p->pci_dip, 367*0Sstevel@tonic-gate "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n", 368*0Sstevel@tonic-gate ddi_driver_name(child), ddi_get_instance(child)); 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate (void) pm_uninit_child(child); 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 374*0Sstevel@tonic-gate ddi_remove_minor_node(child, NULL); 375*0Sstevel@tonic-gate impl_rem_dev_props(child); 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate DEBUG0(DBG_PWR, ddi_get_parent(child), "\n\n"); 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate /* 380*0Sstevel@tonic-gate * Handle chip specific post-uninit-child tasks. 381*0Sstevel@tonic-gate */ 382*0Sstevel@tonic-gate pci_post_uninit_child(pci_p); 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate return (DDI_SUCCESS); 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate /* 388*0Sstevel@tonic-gate * init_child 389*0Sstevel@tonic-gate * 390*0Sstevel@tonic-gate * This function is called from our control ops routine on a 391*0Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD request. It builds and sets the device's 392*0Sstevel@tonic-gate * parent private data area. 393*0Sstevel@tonic-gate * 394*0Sstevel@tonic-gate * used by: pci_ctlops() 395*0Sstevel@tonic-gate * 396*0Sstevel@tonic-gate * return value: none 397*0Sstevel@tonic-gate */ 398*0Sstevel@tonic-gate int 399*0Sstevel@tonic-gate init_child(pci_t *pci_p, dev_info_t *child) 400*0Sstevel@tonic-gate { 401*0Sstevel@tonic-gate pci_regspec_t *pci_rp; 402*0Sstevel@tonic-gate char name[10]; 403*0Sstevel@tonic-gate ddi_acc_handle_t config_handle; 404*0Sstevel@tonic-gate uint16_t command_preserve, command; 405*0Sstevel@tonic-gate uint8_t bcr; 406*0Sstevel@tonic-gate uint8_t header_type, min_gnt; 407*0Sstevel@tonic-gate uint16_t latency_timer; 408*0Sstevel@tonic-gate uint_t n; 409*0Sstevel@tonic-gate int i, no_config; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate /* 412*0Sstevel@tonic-gate * The following is a special case for pcimem nodes. 413*0Sstevel@tonic-gate * For these nodes we create a reg property with a 414*0Sstevel@tonic-gate * single entry that covers the entire address space 415*0Sstevel@tonic-gate * for the node (config, io or memory). 416*0Sstevel@tonic-gate */ 417*0Sstevel@tonic-gate if (strcmp(ddi_driver_name(child), "pcimem") == 0) { 418*0Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, child, 419*0Sstevel@tonic-gate DDI_PROP_CANSLEEP, "reg", (caddr_t)pci_pcimem_reg, 420*0Sstevel@tonic-gate sizeof (pci_pcimem_reg)); 421*0Sstevel@tonic-gate ddi_set_name_addr(child, "0"); 422*0Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 423*0Sstevel@tonic-gate return (DDI_SUCCESS); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate /* 427*0Sstevel@tonic-gate * Check whether the node has config space or is a hard decode 428*0Sstevel@tonic-gate * node (possibly created by a driver.conf file). 429*0Sstevel@tonic-gate */ 430*0Sstevel@tonic-gate no_config = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 431*0Sstevel@tonic-gate "no-config", 0); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate /* 434*0Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 435*0Sstevel@tonic-gate * properties to be merged into the real h/w device node. 436*0Sstevel@tonic-gate * However, do not merge if the no-config property is set 437*0Sstevel@tonic-gate * (see PSARC 2000/088). 438*0Sstevel@tonic-gate */ 439*0Sstevel@tonic-gate if ((ndi_dev_is_persistent_node(child) == 0) && (no_config == 0)) { 440*0Sstevel@tonic-gate extern int pci_allow_pseudo_children; 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, 443*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, &i) == 444*0Sstevel@tonic-gate DDI_SUCCESS) { 445*0Sstevel@tonic-gate cmn_err(CE_WARN, "cannot merge prototype from %s.conf", 446*0Sstevel@tonic-gate ddi_driver_name(child)); 447*0Sstevel@tonic-gate kmem_free(pci_rp, i); 448*0Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate /* 451*0Sstevel@tonic-gate * Name the child 452*0Sstevel@tonic-gate */ 453*0Sstevel@tonic-gate if (name_child(child, name, 10) != DDI_SUCCESS) 454*0Sstevel@tonic-gate return (DDI_FAILURE); 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate ddi_set_name_addr(child, name); 457*0Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate /* 460*0Sstevel@tonic-gate * Try to merge the properties from this prototype 461*0Sstevel@tonic-gate * node into real h/w nodes. 462*0Sstevel@tonic-gate */ 463*0Sstevel@tonic-gate if (ndi_merge_node(child, name_child) == DDI_SUCCESS) { 464*0Sstevel@tonic-gate /* 465*0Sstevel@tonic-gate * Merged ok - return failure to remove the node. 466*0Sstevel@tonic-gate */ 467*0Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 468*0Sstevel@tonic-gate return (DDI_FAILURE); 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 472*0Sstevel@tonic-gate if (pci_allow_pseudo_children) 473*0Sstevel@tonic-gate return (DDI_SUCCESS); 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 476*0Sstevel@tonic-gate ddi_driver_name(child), ddi_get_name_addr(child), 477*0Sstevel@tonic-gate ddi_driver_name(child)); 478*0Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 479*0Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate if (name_child(child, name, 10) != DDI_SUCCESS) 483*0Sstevel@tonic-gate return (DDI_FAILURE); 484*0Sstevel@tonic-gate ddi_set_name_addr(child, name); 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate if (no_config != 0) { 487*0Sstevel@tonic-gate /* 488*0Sstevel@tonic-gate * There is no config space so there's nothing more to do. 489*0Sstevel@tonic-gate */ 490*0Sstevel@tonic-gate return (DDI_SUCCESS); 491*0Sstevel@tonic-gate } 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate if (pm_init_child(child) != DDI_SUCCESS) 494*0Sstevel@tonic-gate return (DDI_FAILURE); 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate /* 498*0Sstevel@tonic-gate * If configuration registers were previously saved by 499*0Sstevel@tonic-gate * child (before it went to D3), then let the child do the 500*0Sstevel@tonic-gate * restore to set up the config regs as it'll first need to 501*0Sstevel@tonic-gate * power the device out of D3. 502*0Sstevel@tonic-gate */ 503*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 504*0Sstevel@tonic-gate "config-regs-saved-by-child") == 1) { 505*0Sstevel@tonic-gate DEBUG0(DBG_PWR, child, 506*0Sstevel@tonic-gate "INITCHILD: config regs to be restored by child\n"); 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate return (DDI_SUCCESS); 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate DEBUG2(DBG_PWR, ddi_get_parent(child), 512*0Sstevel@tonic-gate "INITCHILD: config regs setup for %s@%s\n", 513*0Sstevel@tonic-gate ddi_node_name(child), ddi_get_name_addr(child)); 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* 516*0Sstevel@tonic-gate * Map the child configuration space to for initialization. 517*0Sstevel@tonic-gate * We assume the obp will do the following in the devices 518*0Sstevel@tonic-gate * config space: 519*0Sstevel@tonic-gate * 520*0Sstevel@tonic-gate * Set the latency-timer register to values appropriate 521*0Sstevel@tonic-gate * for the devices on the bus (based on other devices 522*0Sstevel@tonic-gate * MIN_GNT and MAX_LAT registers. 523*0Sstevel@tonic-gate * 524*0Sstevel@tonic-gate * Set the fast back-to-back enable bit in the command 525*0Sstevel@tonic-gate * register if it's supported and all devices on the bus 526*0Sstevel@tonic-gate * have the capability. 527*0Sstevel@tonic-gate * 528*0Sstevel@tonic-gate */ 529*0Sstevel@tonic-gate if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { 530*0Sstevel@tonic-gate (void) pm_uninit_child(child); 531*0Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate return (DDI_FAILURE); 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate /* 537*0Sstevel@tonic-gate * Determine the configuration header type. 538*0Sstevel@tonic-gate */ 539*0Sstevel@tonic-gate header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); 540*0Sstevel@tonic-gate DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: header_type=%x\n", 541*0Sstevel@tonic-gate ddi_driver_name(child), header_type); 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate /* 544*0Sstevel@tonic-gate * Support for "command-preserve" property. Note that we 545*0Sstevel@tonic-gate * add PCI_COMM_BACK2BACK_ENAB to the bits to be preserved 546*0Sstevel@tonic-gate * since the obp will set this if the device supports and 547*0Sstevel@tonic-gate * all targets on the same bus support it. Since psycho 548*0Sstevel@tonic-gate * doesn't support PCI_COMM_BACK2BACK_ENAB, it will never 549*0Sstevel@tonic-gate * be set. This is just here in case future revs do support 550*0Sstevel@tonic-gate * PCI_COMM_BACK2BACK_ENAB. 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate command_preserve = 553*0Sstevel@tonic-gate ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 554*0Sstevel@tonic-gate "command-preserve", 0); 555*0Sstevel@tonic-gate DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: command-preserve=%x\n", 556*0Sstevel@tonic-gate ddi_driver_name(child), command_preserve); 557*0Sstevel@tonic-gate command = pci_config_get16(config_handle, PCI_CONF_COMM); 558*0Sstevel@tonic-gate command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 559*0Sstevel@tonic-gate command |= (pci_command_default & ~command_preserve); 560*0Sstevel@tonic-gate pci_config_put16(config_handle, PCI_CONF_COMM, command); 561*0Sstevel@tonic-gate command = pci_config_get16(config_handle, PCI_CONF_COMM); 562*0Sstevel@tonic-gate DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: command=%x\n", 563*0Sstevel@tonic-gate ddi_driver_name(child), 564*0Sstevel@tonic-gate pci_config_get16(config_handle, PCI_CONF_COMM)); 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate /* 567*0Sstevel@tonic-gate * If the device has a bus control register then program it 568*0Sstevel@tonic-gate * based on the settings in the command register. 569*0Sstevel@tonic-gate */ 570*0Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 571*0Sstevel@tonic-gate bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL); 572*0Sstevel@tonic-gate if (pci_command_default & PCI_COMM_PARITY_DETECT) 573*0Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 574*0Sstevel@tonic-gate if (pci_command_default & PCI_COMM_SERR_ENABLE) 575*0Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE; 576*0Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 577*0Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr); 578*0Sstevel@tonic-gate } 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate /* 581*0Sstevel@tonic-gate * Initialize cache-line-size configuration register if needed. 582*0Sstevel@tonic-gate */ 583*0Sstevel@tonic-gate if (pci_set_cache_line_size_register && 584*0Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 585*0Sstevel@tonic-gate "cache-line-size", 0) == 0) { 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ, 588*0Sstevel@tonic-gate PCI_CACHE_LINE_SIZE); 589*0Sstevel@tonic-gate n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ); 590*0Sstevel@tonic-gate if (n != 0) 591*0Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, 592*0Sstevel@tonic-gate "cache-line-size", n); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* 596*0Sstevel@tonic-gate * Initialize latency timer registers if needed. 597*0Sstevel@tonic-gate */ 598*0Sstevel@tonic-gate if (pci_set_latency_timer_register && 599*0Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 600*0Sstevel@tonic-gate "latency-timer", 0) == 0) { 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate latency_timer = pci_latency_timer; 603*0Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 604*0Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER, 605*0Sstevel@tonic-gate latency_timer); 606*0Sstevel@tonic-gate } else { 607*0Sstevel@tonic-gate min_gnt = pci_config_get8(config_handle, 608*0Sstevel@tonic-gate PCI_CONF_MIN_G); 609*0Sstevel@tonic-gate DEBUG2(DBG_INIT_CLD, pci_p->pci_dip, "%s: min_gnt=%x\n", 610*0Sstevel@tonic-gate ddi_driver_name(child), min_gnt); 611*0Sstevel@tonic-gate if (min_gnt != 0) { 612*0Sstevel@tonic-gate switch (pci_p->pci_pbm_p->pbm_speed) { 613*0Sstevel@tonic-gate case PBM_SPEED_33MHZ: 614*0Sstevel@tonic-gate latency_timer = min_gnt * 8; 615*0Sstevel@tonic-gate break; 616*0Sstevel@tonic-gate case PBM_SPEED_66MHZ: 617*0Sstevel@tonic-gate latency_timer = min_gnt * 4; 618*0Sstevel@tonic-gate break; 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate latency_timer = MIN(latency_timer, 0xff); 623*0Sstevel@tonic-gate pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER, 624*0Sstevel@tonic-gate latency_timer); 625*0Sstevel@tonic-gate n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER); 626*0Sstevel@tonic-gate if (n != 0) 627*0Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, 628*0Sstevel@tonic-gate "latency-timer", n); 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate pci_config_teardown(&config_handle); 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * Handle chip specific init-child tasks. 635*0Sstevel@tonic-gate */ 636*0Sstevel@tonic-gate pci_post_init_child(pci_p, child); 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate return (DDI_SUCCESS); 639*0Sstevel@tonic-gate } 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate /* 642*0Sstevel@tonic-gate * get_nreg_set 643*0Sstevel@tonic-gate * 644*0Sstevel@tonic-gate * Given a dev info pointer to a pci child, this routine returns the 645*0Sstevel@tonic-gate * number of sets in its "reg" property. 646*0Sstevel@tonic-gate * 647*0Sstevel@tonic-gate * used by: pci_ctlops() - DDI_CTLOPS_NREGS 648*0Sstevel@tonic-gate * 649*0Sstevel@tonic-gate * return value: # of reg sets on success, zero on error 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate uint_t 652*0Sstevel@tonic-gate get_nreg_set(dev_info_t *child) 653*0Sstevel@tonic-gate { 654*0Sstevel@tonic-gate pci_regspec_t *pci_rp; 655*0Sstevel@tonic-gate int i, n; 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate /* 658*0Sstevel@tonic-gate * Get the reg property for the device. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 661*0Sstevel@tonic-gate (caddr_t)&pci_rp, &i) != DDI_SUCCESS) 662*0Sstevel@tonic-gate return (0); 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate n = i / (int)sizeof (pci_regspec_t); 665*0Sstevel@tonic-gate kmem_free(pci_rp, i); 666*0Sstevel@tonic-gate return (n); 667*0Sstevel@tonic-gate } 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate /* 671*0Sstevel@tonic-gate * get_nintr 672*0Sstevel@tonic-gate * 673*0Sstevel@tonic-gate * Given a dev info pointer to a pci child, this routine returns the 674*0Sstevel@tonic-gate * number of items in its "interrupts" property. 675*0Sstevel@tonic-gate * 676*0Sstevel@tonic-gate * used by: pci_ctlops() - DDI_CTLOPS_NREGS 677*0Sstevel@tonic-gate * 678*0Sstevel@tonic-gate * return value: # of interrupts on success, zero on error 679*0Sstevel@tonic-gate */ 680*0Sstevel@tonic-gate uint_t 681*0Sstevel@tonic-gate get_nintr(dev_info_t *child) 682*0Sstevel@tonic-gate { 683*0Sstevel@tonic-gate int *pci_ip; 684*0Sstevel@tonic-gate int i, n; 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 687*0Sstevel@tonic-gate "interrupts", (caddr_t)&pci_ip, &i) != DDI_SUCCESS) 688*0Sstevel@tonic-gate return (0); 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate n = i / (int)sizeof (uint_t); 691*0Sstevel@tonic-gate kmem_free(pci_ip, i); 692*0Sstevel@tonic-gate return (n); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate uint64_t 696*0Sstevel@tonic-gate pci_get_cfg_pabase(pci_t *pci_p) 697*0Sstevel@tonic-gate { 698*0Sstevel@tonic-gate int i; 699*0Sstevel@tonic-gate pci_ranges_t *rangep = pci_p->pci_ranges; 700*0Sstevel@tonic-gate int nrange = pci_p->pci_ranges_length / sizeof (pci_ranges_t); 701*0Sstevel@tonic-gate uint32_t cfg_space_type = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate ASSERT(cfg_space_type == 0); 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate for (i = 0; i < nrange; i++, rangep++) { 706*0Sstevel@tonic-gate if (PCI_REG_ADDR_G(rangep->child_high) == cfg_space_type) 707*0Sstevel@tonic-gate break; 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate if (i >= nrange) 711*0Sstevel@tonic-gate cmn_err(CE_PANIC, "no cfg space in pci(%x) ranges prop.\n", 712*0Sstevel@tonic-gate (void *)pci_p); 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate return (((uint64_t)rangep->parent_high << 32) | rangep->parent_low); 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate int 718*0Sstevel@tonic-gate pci_cfg_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_errstate_t *pci_err_p, 719*0Sstevel@tonic-gate int caller, uint32_t prierr) 720*0Sstevel@tonic-gate { 721*0Sstevel@tonic-gate int fatal = 0; 722*0Sstevel@tonic-gate int nonfatal = 0; 723*0Sstevel@tonic-gate int i; 724*0Sstevel@tonic-gate pci_target_err_t tgt_err; 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate ASSERT(dip); 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate derr->fme_ena = derr->fme_ena ? derr->fme_ena : 729*0Sstevel@tonic-gate fm_ena_generate(0, FM_ENA_FMT1); 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 732*0Sstevel@tonic-gate if (pci_err_p->pci_cfg_stat & pci_err_tbl[i].reg_bit) { 733*0Sstevel@tonic-gate char buf[FM_MAX_CLASS]; 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 736*0Sstevel@tonic-gate PCI_ERROR_SUBCLASS, 737*0Sstevel@tonic-gate pci_err_tbl[i].err_class); 738*0Sstevel@tonic-gate ddi_fm_ereport_post(dip, buf, derr->fme_ena, 739*0Sstevel@tonic-gate DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 740*0Sstevel@tonic-gate PCI_CONFIG_STATUS, DATA_TYPE_UINT16, 741*0Sstevel@tonic-gate pci_err_p->pci_cfg_stat, 742*0Sstevel@tonic-gate PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 743*0Sstevel@tonic-gate pci_err_p->pci_cfg_comm, 744*0Sstevel@tonic-gate PCI_PA, DATA_TYPE_UINT64, 745*0Sstevel@tonic-gate pci_err_p->pci_pa, 746*0Sstevel@tonic-gate NULL); 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate switch (pci_err_tbl[i].reg_bit) { 749*0Sstevel@tonic-gate case PCI_STAT_S_SYSERR: 750*0Sstevel@tonic-gate /* 751*0Sstevel@tonic-gate * address parity error on dma - treat as fatal 752*0Sstevel@tonic-gate */ 753*0Sstevel@tonic-gate fatal++; 754*0Sstevel@tonic-gate break; 755*0Sstevel@tonic-gate case PCI_STAT_R_MAST_AB: 756*0Sstevel@tonic-gate case PCI_STAT_R_TARG_AB: 757*0Sstevel@tonic-gate case PCI_STAT_S_PERROR: 758*0Sstevel@tonic-gate if (prierr) { 759*0Sstevel@tonic-gate /* 760*0Sstevel@tonic-gate * piow case are already handled in 761*0Sstevel@tonic-gate * pbm_afsr_report() 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate break; 764*0Sstevel@tonic-gate } 765*0Sstevel@tonic-gate if (caller != PCI_TRAP_CALL) { 766*0Sstevel@tonic-gate /* 767*0Sstevel@tonic-gate * if we haven't come from trap handler 768*0Sstevel@tonic-gate * we won't have an address 769*0Sstevel@tonic-gate */ 770*0Sstevel@tonic-gate fatal++; 771*0Sstevel@tonic-gate break; 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate /* 775*0Sstevel@tonic-gate * queue target ereport - use return from 776*0Sstevel@tonic-gate * pci_lookup_handle() to determine if sync 777*0Sstevel@tonic-gate * or async 778*0Sstevel@tonic-gate */ 779*0Sstevel@tonic-gate tgt_err.tgt_err_ena = derr->fme_ena; 780*0Sstevel@tonic-gate tgt_err.tgt_err_class = 781*0Sstevel@tonic-gate pci_err_tbl[i].terr_class; 782*0Sstevel@tonic-gate tgt_err.tgt_bridge_type = PCI_ERROR_SUBCLASS; 783*0Sstevel@tonic-gate tgt_err.tgt_err_addr = 784*0Sstevel@tonic-gate (uint64_t)derr->fme_bus_specific; 785*0Sstevel@tonic-gate nonfatal++; 786*0Sstevel@tonic-gate errorq_dispatch(pci_target_queue, 787*0Sstevel@tonic-gate (void *)&tgt_err, 788*0Sstevel@tonic-gate sizeof (pci_target_err_t), 789*0Sstevel@tonic-gate ERRORQ_ASYNC); 790*0Sstevel@tonic-gate break; 791*0Sstevel@tonic-gate default: 792*0Sstevel@tonic-gate /* 793*0Sstevel@tonic-gate * dpe on dma write or ta on dma 794*0Sstevel@tonic-gate */ 795*0Sstevel@tonic-gate nonfatal++; 796*0Sstevel@tonic-gate break; 797*0Sstevel@tonic-gate } 798*0Sstevel@tonic-gate } 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate if (fatal) 802*0Sstevel@tonic-gate return (DDI_FM_FATAL); 803*0Sstevel@tonic-gate else if (nonfatal) 804*0Sstevel@tonic-gate return (DDI_FM_NONFATAL); 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate return (DDI_FM_OK); 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate void 810*0Sstevel@tonic-gate pci_child_cfg_save(dev_info_t *dip) 811*0Sstevel@tonic-gate { 812*0Sstevel@tonic-gate dev_info_t *cdip; 813*0Sstevel@tonic-gate int ret = DDI_SUCCESS; 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate /* 816*0Sstevel@tonic-gate * Save the state of the configuration headers of child 817*0Sstevel@tonic-gate * nodes. 818*0Sstevel@tonic-gate */ 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip != NULL; 821*0Sstevel@tonic-gate cdip = ddi_get_next_sibling(cdip)) { 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate /* 824*0Sstevel@tonic-gate * Not interested in children who are not already 825*0Sstevel@tonic-gate * init'ed. They will be set up in init_child(). 826*0Sstevel@tonic-gate */ 827*0Sstevel@tonic-gate if (i_ddi_node_state(cdip) < DS_INITIALIZED) { 828*0Sstevel@tonic-gate DEBUG2(DBG_DETACH, dip, "DDI_SUSPEND: skipping " 829*0Sstevel@tonic-gate "%s%d not in CF1\n", ddi_driver_name(cdip), 830*0Sstevel@tonic-gate ddi_get_instance(cdip)); 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate continue; 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate /* 836*0Sstevel@tonic-gate * Only save config registers if not already saved by child. 837*0Sstevel@tonic-gate */ 838*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 839*0Sstevel@tonic-gate SAVED_CONFIG_REGS) == 1) { 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate continue; 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate /* 845*0Sstevel@tonic-gate * The nexus needs to save config registers. Create a property 846*0Sstevel@tonic-gate * so it knows to restore on resume. 847*0Sstevel@tonic-gate */ 848*0Sstevel@tonic-gate ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, 849*0Sstevel@tonic-gate "nexus-saved-config-regs"); 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) { 852*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d can't update prop %s", 853*0Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip), 854*0Sstevel@tonic-gate "nexus-saved-config-regs"); 855*0Sstevel@tonic-gate } 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate (void) pci_save_config_regs(cdip); 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate } 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate void 862*0Sstevel@tonic-gate pci_child_cfg_restore(dev_info_t *dip) 863*0Sstevel@tonic-gate { 864*0Sstevel@tonic-gate dev_info_t *cdip; 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate /* 867*0Sstevel@tonic-gate * Restore config registers for children that did not save 868*0Sstevel@tonic-gate * their own registers. Children pwr states are UNKNOWN after 869*0Sstevel@tonic-gate * a resume since it is possible for the PM framework to call 870*0Sstevel@tonic-gate * resume without an actual power cycle. (ie if suspend fails). 871*0Sstevel@tonic-gate */ 872*0Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip != NULL; 873*0Sstevel@tonic-gate cdip = ddi_get_next_sibling(cdip)) { 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate /* 876*0Sstevel@tonic-gate * Not interested in children who are not already 877*0Sstevel@tonic-gate * init'ed. They will be set up by init_child(). 878*0Sstevel@tonic-gate */ 879*0Sstevel@tonic-gate if (i_ddi_node_state(cdip) < DS_INITIALIZED) { 880*0Sstevel@tonic-gate DEBUG2(DBG_DETACH, dip, 881*0Sstevel@tonic-gate "DDI_RESUME: skipping %s%d not in CF1\n", 882*0Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip)); 883*0Sstevel@tonic-gate continue; 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate /* 887*0Sstevel@tonic-gate * Only restore config registers if saved by nexus. 888*0Sstevel@tonic-gate */ 889*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 890*0Sstevel@tonic-gate "nexus-saved-config-regs") == 1) { 891*0Sstevel@tonic-gate (void) pci_restore_config_regs(cdip); 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate DEBUG2(DBG_PWR, dip, 894*0Sstevel@tonic-gate "DDI_RESUME: nexus restoring %s%d config regs\n", 895*0Sstevel@tonic-gate ddi_driver_name(cdip), ddi_get_instance(cdip)); 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate if (ndi_prop_remove(DDI_DEV_T_NONE, cdip, 898*0Sstevel@tonic-gate "nexus-saved-config-regs") != DDI_PROP_SUCCESS) { 899*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d can't remove prop %s", 900*0Sstevel@tonic-gate ddi_driver_name(cdip), 901*0Sstevel@tonic-gate ddi_get_instance(cdip), 902*0Sstevel@tonic-gate "nexus-saved-config-regs"); 903*0Sstevel@tonic-gate } 904*0Sstevel@tonic-gate } 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate } 907