1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * CMU-CH nexus utility routines: 29 * property and config routines for attach() 30 * reg/intr/range/assigned-address property routines for bus_map() 31 * init_child() 32 * fault handling 33 * debug functions 34 */ 35 36 #include <sys/types.h> 37 #include <sys/kmem.h> 38 #include <sys/async.h> 39 #include <sys/sysmacros.h> 40 #include <sys/sunddi.h> 41 #include <sys/sunndi.h> 42 #include <sys/fm/protocol.h> 43 #include <sys/fm/io/pci.h> 44 #include <sys/fm/util.h> 45 #include <sys/ddi_impldefs.h> 46 #include <sys/pcicmu/pcicmu.h> 47 #include <sys/promif.h> 48 49 /* 50 * get_pcmu_properties 51 * 52 * This function is called from the attach routine to get the key 53 * properties of the pci nodes. 54 * 55 * used by: pcmu_attach() 56 * 57 * return value: DDI_FAILURE on failure 58 */ 59 int 60 get_pcmu_properties(pcmu_t *pcmu_p, dev_info_t *dip) 61 { 62 int i; 63 64 /* 65 * Get the device's port id. 66 */ 67 if ((pcmu_p->pcmu_id = (uint32_t)pcmu_get_portid(dip)) == -1u) { 68 cmn_err(CE_WARN, "%s%d: no portid property\n", 69 ddi_driver_name(dip), ddi_get_instance(dip)); 70 return (DDI_FAILURE); 71 } 72 73 /* 74 * Get the bus-ranges property. 75 */ 76 i = sizeof (pcmu_p->pcmu_bus_range); 77 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 78 "bus-range", (caddr_t)&pcmu_p->pcmu_bus_range, &i) != DDI_SUCCESS) { 79 cmn_err(CE_WARN, "%s%d: no bus-range property\n", 80 ddi_driver_name(dip), ddi_get_instance(dip)); 81 return (DDI_FAILURE); 82 } 83 PCMU_DBG2(PCMU_DBG_ATTACH, dip, 84 "get_pcmu_properties: bus-range (%x,%x)\n", 85 pcmu_p->pcmu_bus_range.lo, pcmu_p->pcmu_bus_range.hi); 86 87 /* 88 * Get the ranges property. 89 */ 90 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", 91 (caddr_t)&pcmu_p->pcmu_ranges, &pcmu_p->pcmu_ranges_length) != 92 DDI_SUCCESS) { 93 cmn_err(CE_WARN, "%s%d: no ranges property\n", 94 ddi_driver_name(dip), ddi_get_instance(dip)); 95 return (DDI_FAILURE); 96 } 97 pcmu_fix_ranges(pcmu_p->pcmu_ranges, 98 pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t)); 99 100 /* 101 * Determine the number upa slot interrupts. 102 */ 103 pcmu_p->pcmu_numproxy = pcmu_get_numproxy(pcmu_p->pcmu_dip); 104 PCMU_DBG1(PCMU_DBG_ATTACH, dip, "get_pcmu_properties: numproxy=%d\n", 105 pcmu_p->pcmu_numproxy); 106 return (DDI_SUCCESS); 107 } 108 109 /* 110 * free_pcmu_properties: 111 * 112 * This routine frees the memory used to cache the 113 * "ranges" properties of the pci bus device node. 114 * 115 * used by: pcmu_detach() 116 * 117 * return value: none 118 */ 119 void 120 free_pcmu_properties(pcmu_t *pcmu_p) 121 { 122 kmem_free(pcmu_p->pcmu_ranges, pcmu_p->pcmu_ranges_length); 123 } 124 125 /* 126 * pcmu_reloc_reg 127 * 128 * If the "reg" entry (*pcmu_rp) is relocatable, lookup "assigned-addresses" 129 * property to fetch corresponding relocated address. 130 * 131 * used by: pcmu_map() 132 * 133 * return value: 134 * 135 * DDI_SUCCESS - on success 136 * DDI_ME_INVAL - regspec is invalid 137 */ 138 int 139 pcmu_reloc_reg(dev_info_t *dip, dev_info_t *rdip, pcmu_t *pcmu_p, 140 pci_regspec_t *rp) 141 { 142 int assign_len, assign_entries, i; 143 pci_regspec_t *assign_p; 144 register uint32_t phys_hi = rp->pci_phys_hi; 145 register uint32_t mask = PCI_REG_ADDR_M | PCI_CONF_ADDR_MASK; 146 register uint32_t phys_addr = phys_hi & mask; 147 148 PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, 149 "\tpcmu_reloc_reg fr: %x.%x.%x %x.%x\n", 150 rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, 151 rp->pci_size_hi, rp->pci_size_low); 152 153 if ((phys_hi & PCI_RELOCAT_B) || !(phys_hi & PCI_ADDR_MASK)) { 154 return (DDI_SUCCESS); 155 } 156 157 /* phys_mid must be 0 regardless space type. XXX-64 bit mem space */ 158 if (rp->pci_phys_mid != 0 || rp->pci_size_hi != 0) { 159 PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip, 160 "phys_mid or size_hi not 0\n"); 161 return (DDI_ME_INVAL); 162 } 163 164 if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 165 "assigned-addresses", (caddr_t)&assign_p, &assign_len)) { 166 return (DDI_ME_INVAL); 167 } 168 169 assign_entries = assign_len / sizeof (pci_regspec_t); 170 for (i = 0; i < assign_entries; i++, assign_p++) { 171 if ((assign_p->pci_phys_hi & mask) == phys_addr) { 172 rp->pci_phys_low += assign_p->pci_phys_low; 173 break; 174 } 175 } 176 kmem_free(assign_p - i, assign_len); 177 PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, 178 "\tpcmu_reloc_reg to: %x.%x.%x %x.%x\n", 179 rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, 180 rp->pci_size_hi, rp->pci_size_low); 181 return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL); 182 } 183 184 /* 185 * use "ranges" to translate relocated pci regspec into parent space 186 */ 187 int 188 pcmu_xlate_reg(pcmu_t *pcmu_p, pci_regspec_t *pcmu_rp, struct regspec *new_rp) 189 { 190 int n; 191 pcmu_ranges_t *rng_p = pcmu_p->pcmu_ranges; 192 int rng_n = pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t); 193 194 uint32_t space_type = PCI_REG_ADDR_G(pcmu_rp->pci_phys_hi); 195 uint32_t reg_end, reg_begin = pcmu_rp->pci_phys_low; 196 uint32_t sz = pcmu_rp->pci_size_low; 197 198 uint32_t rng_begin, rng_end; 199 200 if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 201 if (reg_begin > PCI_CONF_HDR_SIZE) { 202 return (DDI_ME_INVAL); 203 } 204 sz = sz ? MIN(sz, PCI_CONF_HDR_SIZE) : PCI_CONF_HDR_SIZE; 205 reg_begin += pcmu_rp->pci_phys_hi; 206 } 207 reg_end = reg_begin + sz - 1; 208 209 for (n = 0; n < rng_n; n++, rng_p++) { 210 if (space_type != PCI_REG_ADDR_G(rng_p->child_high)) { 211 continue; /* not the same space type */ 212 } 213 214 rng_begin = rng_p->child_low; 215 if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { 216 rng_begin += rng_p->child_high; 217 } 218 rng_end = rng_begin + rng_p->size_low - 1; 219 if (reg_begin >= rng_begin && reg_end <= rng_end) { 220 break; 221 } 222 } 223 if (n >= rng_n) { 224 return (DDI_ME_REGSPEC_RANGE); 225 } 226 227 new_rp->regspec_addr = reg_begin - rng_begin + rng_p->parent_low; 228 new_rp->regspec_bustype = rng_p->parent_high; 229 new_rp->regspec_size = sz; 230 PCMU_DBG4(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip, 231 "\tpcmu_xlate_reg: entry %d new_rp %x.%x %x\n", 232 n, new_rp->regspec_bustype, new_rp->regspec_addr, sz); 233 return (DDI_SUCCESS); 234 } 235 236 237 /* 238 * pcmu_report_dev 239 * 240 * This function is called from our control ops routine on a 241 * DDI_CTLOPS_REPORTDEV request. 242 * 243 * The display format is 244 * 245 * <name><inst> at <pname><pinst> device <dev> function <func> 246 * 247 * where 248 * 249 * <name> this device's name property 250 * <inst> this device's instance number 251 * <name> parent device's name property 252 * <inst> parent device's instance number 253 * <dev> this device's device number 254 * <func> this device's function number 255 */ 256 int 257 pcmu_report_dev(dev_info_t *dip) 258 { 259 if (dip == (dev_info_t *)0) { 260 return (DDI_FAILURE); 261 } 262 cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", ddi_node_name(dip), 263 ddi_get_name_addr(dip), ddi_driver_name(dip), 264 ddi_get_instance(dip)); 265 return (DDI_SUCCESS); 266 } 267 268 /* 269 * name_child 270 * 271 * This function is called from pcmu_init_child to name a node. It is 272 * also passed as a callback for node merging functions. 273 * 274 * return value: DDI_SUCCESS, DDI_FAILURE 275 */ 276 static int 277 name_child(dev_info_t *child, char *name, int namelen) 278 { 279 pci_regspec_t *pcmu_rp; 280 int reglen; 281 uint_t func; 282 char **unit_addr; 283 uint_t n; 284 285 /* 286 * Set the address portion of the node name based on 287 * unit-address property, if it exists. 288 * The interpretation of the unit-address is DD[,F] 289 * where DD is the device id and F is the function. 290 */ 291 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 292 DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) == 293 DDI_PROP_SUCCESS) { 294 if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 295 cmn_err(CE_WARN, "unit-address property in %s.conf" 296 " not well-formed", ddi_driver_name(child)); 297 ddi_prop_free(unit_addr); 298 return (DDI_FAILURE); 299 } 300 (void) snprintf(name, namelen, "%s", *unit_addr); 301 ddi_prop_free(unit_addr); 302 return (DDI_SUCCESS); 303 } 304 305 /* 306 * The unit-address property is does not exist. Set the address 307 * portion of the node name based on the function and device number. 308 */ 309 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 310 "reg", (int **)&pcmu_rp, (uint_t *)®len) == DDI_SUCCESS) { 311 if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) { 312 cmn_err(CE_WARN, "reg property not well-formed"); 313 return (DDI_FAILURE); 314 } 315 316 func = PCI_REG_FUNC_G(pcmu_rp[0].pci_phys_hi); 317 if (func != 0) { 318 (void) snprintf(name, namelen, "%x,%x", 319 PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi), func); 320 } else { 321 (void) snprintf(name, namelen, "%x", 322 PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi)); 323 } 324 ddi_prop_free(pcmu_rp); 325 return (DDI_SUCCESS); 326 } 327 cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child)); 328 return (DDI_FAILURE); 329 } 330 331 int 332 pcmu_uninit_child(pcmu_t *pcmu_p, dev_info_t *child) 333 { 334 PCMU_DBG2(PCMU_DBG_CTLOPS, pcmu_p->pcmu_dip, 335 "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n", 336 ddi_driver_name(child), ddi_get_instance(child)); 337 338 ddi_set_name_addr(child, NULL); 339 ddi_remove_minor_node(child, NULL); 340 impl_rem_dev_props(child); 341 342 PCMU_DBG0(PCMU_DBG_PWR, ddi_get_parent(child), "\n\n"); 343 return (DDI_SUCCESS); 344 } 345 346 /* 347 * pcmu_init_child 348 * 349 * This function is called from our control ops routine on a 350 * DDI_CTLOPS_INITCHILD request. It builds and sets the device's 351 * parent private data area. 352 * 353 * used by: pcmu_ctlops() 354 * 355 * return value: none 356 */ 357 int 358 pcmu_init_child(pcmu_t *pcmu_p, dev_info_t *child) 359 { 360 char name[10]; 361 ddi_acc_handle_t config_handle; 362 uint8_t bcr; 363 uint8_t header_type; 364 365 if (name_child(child, name, 10) != DDI_SUCCESS) 366 return (DDI_FAILURE); 367 ddi_set_name_addr(child, name); 368 369 PCMU_DBG2(PCMU_DBG_PWR, ddi_get_parent(child), 370 "INITCHILD: config regs setup for %s@%s\n", 371 ddi_node_name(child), ddi_get_name_addr(child)); 372 373 /* 374 * Map the child configuration space to for initialization. 375 * We assume the obp will do the following in the devices 376 * config space: 377 * 378 * Set the latency-timer register to values appropriate 379 * for the devices on the bus (based on other devices 380 * MIN_GNT and MAX_LAT registers. 381 * 382 * Set the fast back-to-back enable bit in the command 383 * register if it's supported and all devices on the bus 384 * have the capability. 385 * 386 */ 387 if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { 388 ddi_set_name_addr(child, NULL); 389 return (DDI_FAILURE); 390 } 391 392 /* 393 * Determine the configuration header type. 394 */ 395 header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); 396 PCMU_DBG2(PCMU_DBG_INIT_CLD, pcmu_p->pcmu_dip, "%s: header_type=%x\n", 397 ddi_driver_name(child), header_type); 398 399 /* 400 * If the device has a bus control register then program it 401 * based on the settings in the command register. 402 */ 403 if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 404 bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL); 405 if (pcmu_command_default & PCI_COMM_PARITY_DETECT) 406 bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 407 if (pcmu_command_default & PCI_COMM_SERR_ENABLE) 408 bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE; 409 bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 410 pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr); 411 } 412 413 pci_config_teardown(&config_handle); 414 return (DDI_SUCCESS); 415 } 416 417 /* 418 * pcmu_get_reg_set_size 419 * 420 * Given a dev info pointer to a pci child and a register number, this 421 * routine returns the size element of that reg set property. 422 * 423 * used by: pcmu_ctlops() - DDI_CTLOPS_REGSIZE 424 * 425 * return value: size of reg set on success, zero on error 426 */ 427 off_t 428 pcmu_get_reg_set_size(dev_info_t *child, int rnumber) 429 { 430 pci_regspec_t *pcmu_rp; 431 off_t size; 432 int i; 433 434 if (rnumber < 0) { 435 return (0); 436 } 437 438 /* 439 * Get the reg property for the device. 440 */ 441 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 442 (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) { 443 return (0); 444 } 445 446 if (rnumber >= (i / (int)sizeof (pci_regspec_t))) { 447 kmem_free(pcmu_rp, i); 448 return (0); 449 } 450 451 size = pcmu_rp[rnumber].pci_size_low | 452 ((uint64_t)pcmu_rp[rnumber].pci_size_hi << 32); 453 kmem_free(pcmu_rp, i); 454 return (size); 455 } 456 457 458 /* 459 * pcmu_get_nreg_set 460 * 461 * Given a dev info pointer to a pci child, this routine returns the 462 * number of sets in its "reg" property. 463 * 464 * used by: pcmu_ctlops() - DDI_CTLOPS_NREGS 465 * 466 * return value: # of reg sets on success, zero on error 467 */ 468 uint_t 469 pcmu_get_nreg_set(dev_info_t *child) 470 { 471 pci_regspec_t *pcmu_rp; 472 int i, n; 473 474 /* 475 * Get the reg property for the device. 476 */ 477 if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", 478 (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) { 479 return (0); 480 } 481 n = i / (int)sizeof (pci_regspec_t); 482 kmem_free(pcmu_rp, i); 483 return (n); 484 } 485 486 int 487 pcmu_cfg_report(dev_info_t *dip, ddi_fm_error_t *derr, 488 pcmu_errstate_t *pcmu_err_p, int caller, uint32_t prierr) 489 { 490 int fatal = 0; 491 int nonfatal = 0; 492 int i; 493 pcmu_t *pcmu_p; 494 int instance = ddi_get_instance(dip); 495 496 ASSERT(dip); 497 498 pcmu_p = get_pcmu_soft_state(instance); 499 500 derr->fme_ena = derr->fme_ena ? derr->fme_ena : 501 fm_ena_generate(0, FM_ENA_FMT1); 502 503 for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { 504 if (pcmu_err_p->pcmu_cfg_stat & pci_err_tbl[i].reg_bit) { 505 char buf[FM_MAX_CLASS]; 506 char *aux_msg = NULL; 507 508 switch (pci_err_tbl[i].reg_bit) { 509 case PCI_STAT_R_MAST_AB: 510 aux_msg = "Receieved Master Abort"; 511 /* FALLTHROUGH */ 512 case PCI_STAT_R_TARG_AB: 513 if (aux_msg != NULL) 514 aux_msg = "Receieved Target Abort"; 515 if (prierr) { 516 /* 517 * piow case are already handled in 518 * pcmu_pbm_afsr_report() 519 */ 520 break; 521 } 522 if (caller != PCI_TRAP_CALL) { 523 /* 524 * if we haven't come from trap handler 525 * we won't have an address 526 */ 527 fatal++; 528 } 529 break; 530 default: 531 /* 532 * dpe on dma write or ta on dma 533 */ 534 nonfatal++; 535 break; 536 } 537 (void) snprintf(buf, FM_MAX_CLASS, "%s %s: %s %s", 538 (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str, 539 (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str, 540 "PCI config space:", aux_msg); 541 cmn_err(CE_WARN, "%s %s=0x%p", buf, "pbm-csr", 542 (void *)(pcmu_p->pcmu_pcbm_p)->pcbm_ctrl_reg); 543 } 544 } 545 546 if (fatal) 547 return (DDI_FM_FATAL); 548 else if (nonfatal) 549 return (DDI_FM_NONFATAL); 550 551 return (DDI_FM_OK); 552 } 553 554 void 555 pcmu_child_cfg_save(dev_info_t *dip) 556 { 557 dev_info_t *cdip; 558 int ret = DDI_SUCCESS; 559 560 /* 561 * Save the state of the configuration headers of child 562 * nodes. 563 */ 564 565 for (cdip = ddi_get_child(dip); cdip != NULL; 566 cdip = ddi_get_next_sibling(cdip)) { 567 568 /* 569 * Not interested in children who are not already 570 * init'ed. They will be set up in pcmu_init_child(). 571 */ 572 if (i_ddi_node_state(cdip) < DS_INITIALIZED) { 573 PCMU_DBG2(PCMU_DBG_DETACH, dip, "DDI_SUSPEND: skipping " 574 "%s%d not in CF1\n", ddi_driver_name(cdip), 575 ddi_get_instance(cdip)); 576 577 continue; 578 } 579 580 /* 581 * Only save config registers if not already saved by child. 582 */ 583 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 584 SAVED_CONFIG_REGS) == 1) { 585 586 continue; 587 } 588 589 /* 590 * The nexus needs to save config registers. Create a property 591 * so it knows to restore on resume. 592 */ 593 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, 594 "nexus-saved-config-regs"); 595 596 if (ret != DDI_PROP_SUCCESS) { 597 cmn_err(CE_WARN, "%s%d can't update prop %s", 598 ddi_driver_name(cdip), ddi_get_instance(cdip), 599 "nexus-saved-config-regs"); 600 } 601 602 (void) pci_save_config_regs(cdip); 603 } 604 } 605 606 void 607 pcmu_child_cfg_restore(dev_info_t *dip) 608 { 609 dev_info_t *cdip; 610 611 /* 612 * Restore config registers for children that did not save 613 * their own registers. Children pwr states are UNKNOWN after 614 * a resume since it is possible for the PM framework to call 615 * resume without an actual power cycle. (ie if suspend fails). 616 */ 617 for (cdip = ddi_get_child(dip); cdip != NULL; 618 cdip = ddi_get_next_sibling(cdip)) { 619 620 /* 621 * Not interested in children who are not already 622 * init'ed. They will be set up by pcmu_init_child(). 623 */ 624 if (i_ddi_node_state(cdip) < DS_INITIALIZED) { 625 PCMU_DBG2(PCMU_DBG_DETACH, dip, 626 "DDI_RESUME: skipping %s%d not in CF1\n", 627 ddi_driver_name(cdip), ddi_get_instance(cdip)); 628 continue; 629 } 630 631 /* 632 * Only restore config registers if saved by nexus. 633 */ 634 if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 635 "nexus-saved-config-regs") == 1) { 636 (void) pci_restore_config_regs(cdip); 637 638 PCMU_DBG2(PCMU_DBG_PWR, dip, 639 "DDI_RESUME: nexus restoring %s%d config regs\n", 640 ddi_driver_name(cdip), ddi_get_instance(cdip)); 641 642 if (ndi_prop_remove(DDI_DEV_T_NONE, cdip, 643 "nexus-saved-config-regs") != DDI_PROP_SUCCESS) { 644 cmn_err(CE_WARN, "%s%d can't remove prop %s", 645 ddi_driver_name(cdip), 646 ddi_get_instance(cdip), 647 "nexus-saved-config-regs"); 648 } 649 } 650 } 651 } 652 653 #ifdef DEBUG 654 extern uint64_t pcmu_debug_flags; 655 656 pcmu_dflag_to_str_t pcmu_dflag_strings [] = { 657 {PCMU_DBG_ATTACH, "pcmu_attach"}, 658 {PCMU_DBG_DETACH, "pcmu_detach"}, 659 {PCMU_DBG_MAP, "pcmu_map"}, 660 {PCMU_DBG_A_INTX, "pcmu_add_intx"}, 661 {PCMU_DBG_R_INTX, "pcmu_rem_intx"}, 662 {PCMU_DBG_INIT_CLD, "pcmu_init_child"}, 663 {PCMU_DBG_CTLOPS, "pcmu_ctlops"}, 664 {PCMU_DBG_INTR, "pcmu_intr_wrapper"}, 665 {PCMU_DBG_ERR_INTR, "pcmu_pbm_error_intr"}, 666 {PCMU_DBG_BUS_FAULT, "pcmu_fault"}, 667 {PCMU_DBG_IB, "pcmu_ib"}, 668 {PCMU_DBG_CB, "pcmu_cb"}, 669 {PCMU_DBG_PBM, "pcmu_pbm"}, 670 {PCMU_DBG_OPEN, "pcmu_open"}, 671 {PCMU_DBG_CLOSE, "pcmu_close"}, 672 {PCMU_DBG_IOCTL, "pcmu_ioctl"}, 673 {PCMU_DBG_PWR, "pcmu_pwr"} 674 }; 675 676 void 677 pcmu_debug(uint64_t flag, dev_info_t *dip, char *fmt, 678 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) 679 { 680 char *s = "pcmu unknown"; 681 uint_t cont = 0; 682 int i; 683 int no_rec = (sizeof (pcmu_dflag_strings) / 684 sizeof (pcmu_dflag_to_str_t)); 685 686 if (flag & PCMU_DBG_CONT) { 687 flag &= ~PCMU_DBG_CONT; 688 cont = 1; 689 } 690 if ((pcmu_debug_flags & flag) == flag) { 691 for (i = 0; i < no_rec; i++) { 692 if (pcmu_dflag_strings[i].flag == flag) { 693 s = pcmu_dflag_strings[i].string; 694 break; 695 } 696 } 697 if (s && cont == 0) { 698 prom_printf("%s(%d): %s: ", ddi_driver_name(dip), 699 ddi_get_instance(dip), s); 700 } 701 prom_printf(fmt, a1, a2, a3, a4, a5); 702 } 703 } 704 #endif 705