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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/conf.h> 29 #include <sys/kmem.h> 30 #include <sys/debug.h> 31 #include <sys/modctl.h> 32 #include <sys/autoconf.h> 33 #include <sys/hwconf.h> 34 #include <sys/ddi_impldefs.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/sunndi.h> 38 #include <sys/ndi_impldefs.h> 39 #include <sys/machsystm.h> 40 #include <sys/fcode.h> 41 #include <sys/promif.h> 42 #include <sys/promimpl.h> 43 #include <sys/opl_cfg.h> 44 #include <sys/scfd/scfostoescf.h> 45 46 static unsigned int opl_cfg_inited; 47 static opl_board_cfg_t opl_boards[HWD_SBS_PER_DOMAIN]; 48 49 /* 50 * Module control operations 51 */ 52 53 extern struct mod_ops mod_miscops; 54 55 static struct modlmisc modlmisc = { 56 &mod_miscops, /* Type of module */ 57 "OPL opl_cfg %I%" 58 }; 59 60 static struct modlinkage modlinkage = { 61 MODREV_1, (void *)&modlmisc, NULL 62 }; 63 64 static int opl_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); 65 static int opl_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); 66 static int opl_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); 67 static int opl_register_store(dev_info_t *, fco_handle_t, fc_ci_t *); 68 69 static int opl_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 70 static int opl_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *); 71 static int opl_vtop(dev_info_t *, fco_handle_t, fc_ci_t *); 72 73 static int opl_config_child(dev_info_t *, fco_handle_t, fc_ci_t *); 74 75 static int opl_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *); 76 static int opl_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *); 77 78 static int opl_map_phys(dev_info_t *, struct regspec *, caddr_t *, 79 ddi_device_acc_attr_t *, ddi_acc_handle_t *); 80 static void opl_unmap_phys(ddi_acc_handle_t *); 81 static int opl_get_hwd_va(dev_info_t *, fco_handle_t, fc_ci_t *); 82 static int opl_master_interrupt(dev_info_t *, fco_handle_t, fc_ci_t *); 83 84 extern int prom_get_fcode_size(char *); 85 extern int prom_get_fcode(char *, char *); 86 87 static int master_interrupt_init(uint32_t, uint32_t); 88 89 #define PROBE_STR_SIZE 64 90 #define UNIT_ADDR_SIZE 64 91 92 opl_fc_ops_t opl_fc_ops[] = { 93 94 { FC_MAP_IN, opl_map_in}, 95 { FC_MAP_OUT, opl_map_out}, 96 { "rx@", opl_register_fetch}, 97 { FC_RL_FETCH, opl_register_fetch}, 98 { FC_RW_FETCH, opl_register_fetch}, 99 { FC_RB_FETCH, opl_register_fetch}, 100 { "rx!", opl_register_store}, 101 { FC_RL_STORE, opl_register_store}, 102 { FC_RW_STORE, opl_register_store}, 103 { FC_RB_STORE, opl_register_store}, 104 { "claim-memory", opl_claim_memory}, 105 { "release-memory", opl_release_memory}, 106 { "vtop", opl_vtop}, 107 { FC_CONFIG_CHILD, opl_config_child}, 108 { FC_GET_FCODE_SIZE, opl_get_fcode_size}, 109 { FC_GET_FCODE, opl_get_fcode}, 110 { "get-hwd-va", opl_get_hwd_va}, 111 { "master-interrupt", opl_master_interrupt}, 112 { NULL, NULL} 113 114 }; 115 116 extern caddr_t efcode_vaddr; 117 extern int efcode_size; 118 119 #ifdef DEBUG 120 #define HWDDUMP_OFFSETS 1 121 #define HWDDUMP_ALL_STATUS 2 122 #define HWDDUMP_CHUNKS 3 123 #define HWDDUMP_SBP 4 124 125 int hwddump_flags = HWDDUMP_SBP | HWDDUMP_CHUNKS; 126 #endif 127 128 static int master_interrupt_inited = 0; 129 130 int 131 _init() 132 { 133 int err = 0; 134 135 /* 136 * Create a resource map for the contiguous memory allocated 137 * at start-of-day in startup.c 138 */ 139 err = ndi_ra_map_setup(ddi_root_node(), "opl-fcodemem"); 140 if (err == NDI_FAILURE) { 141 cmn_err(CE_WARN, "Cannot setup resource map opl-fcodemem\n"); 142 return (1); 143 } 144 145 /* 146 * Put the allocated memory into the pool. 147 */ 148 (void) ndi_ra_free(ddi_root_node(), (uint64_t)efcode_vaddr, 149 (uint64_t)efcode_size, "opl-fcodemem", 0); 150 151 if ((err = mod_install(&modlinkage)) != 0) { 152 cmn_err(CE_WARN, "opl_cfg failed to load, error=%d", err); 153 (void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem"); 154 } 155 156 return (err); 157 } 158 159 int 160 _fini(void) 161 { 162 int ret; 163 164 ret = (mod_remove(&modlinkage)); 165 if (ret != 0) 166 return (ret); 167 168 (void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem"); 169 170 return (ret); 171 } 172 173 int 174 _info(modinfop) 175 struct modinfo *modinfop; 176 { 177 return (mod_info(&modlinkage, modinfop)); 178 } 179 180 #ifdef DEBUG 181 static void 182 opl_dump_hwd(opl_probe_t *probe) 183 { 184 hwd_header_t *hdrp; 185 hwd_sb_status_t *statp; 186 hwd_domain_info_t *dinfop; 187 hwd_sb_t *sbp; 188 hwd_cpu_chip_t *chips; 189 hwd_pci_ch_t *channels; 190 int board, i, status; 191 192 board = probe->pr_board; 193 194 hdrp = probe->pr_hdr; 195 statp = probe->pr_sb_status; 196 dinfop = probe->pr_dinfo; 197 sbp = probe->pr_sb; 198 199 printf("HWD: board %d\n", board); 200 printf("HWD:magic = 0x%x\n", hdrp->hdr_magic); 201 printf("HWD:version = 0x%x.%x\n", hdrp->hdr_version.major, 202 hdrp->hdr_version.minor); 203 204 if (hwddump_flags & HWDDUMP_OFFSETS) { 205 printf("HWD:status offset = 0x%x\n", 206 hdrp->hdr_sb_status_offset); 207 printf("HWD:domain offset = 0x%x\n", 208 hdrp->hdr_domain_info_offset); 209 printf("HWD:board offset = 0x%x\n", hdrp->hdr_sb_info_offset); 210 } 211 212 if (hwddump_flags & HWDDUMP_SBP) 213 printf("HWD:sb_t ptr = 0x%p\n", (void *)probe->pr_sb); 214 215 if (hwddump_flags & HWDDUMP_ALL_STATUS) { 216 int bd; 217 printf("HWD:board status ="); 218 for (bd = 0; bd < HWD_SBS_PER_DOMAIN; bd++) 219 printf("%x ", statp->sb_status[bd]); 220 printf("\n"); 221 } else { 222 printf("HWD:board status = %d\n", statp->sb_status[board]); 223 } 224 225 printf("HWD:banner name = %s\n", dinfop->dinf_banner_name); 226 printf("HWD:platform = %s\n", dinfop->dinf_platform_token); 227 228 printf("HWD:chip status:\n"); 229 chips = &sbp->sb_cmu.cmu_cpu_chips[0]; 230 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 231 232 status = chips[i].chip_status; 233 printf("chip[%d] = ", i); 234 if (HWD_STATUS_NONE(status)) 235 printf("none"); 236 else if (HWD_STATUS_FAILED(status)) 237 printf("fail"); 238 else if (HWD_STATUS_OK(status)) 239 printf("ok"); 240 printf("\n"); 241 } 242 243 if (hwddump_flags & HWDDUMP_CHUNKS) { 244 int chunk; 245 hwd_memory_t *mem = &sbp->sb_cmu.cmu_memory; 246 printf("HWD:chunks:\n"); 247 for (chunk = 0; chunk < HWD_MAX_MEM_CHUNKS; chunk++) 248 printf("\t%d 0x%lx 0x%lx\n", chunk, 249 mem->mem_chunks[chunk].chnk_start_address, 250 mem->mem_chunks[chunk].chnk_size); 251 } 252 253 printf("HWD:channel status:\n"); 254 channels = &sbp->sb_pci_ch[0]; 255 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 256 257 status = channels[i].pci_status; 258 printf("channels[%d] = ", i); 259 if (HWD_STATUS_NONE(status)) 260 printf("none"); 261 else if (HWD_STATUS_FAILED(status)) 262 printf("fail"); 263 else if (HWD_STATUS_OK(status)) 264 printf("ok"); 265 printf("\n"); 266 } 267 printf("channels[%d] = ", i); 268 status = sbp->sb_cmu.cmu_ch.chan_status; 269 if (HWD_STATUS_NONE(status)) 270 printf("none"); 271 else if (HWD_STATUS_FAILED(status)) 272 printf("fail"); 273 else if (HWD_STATUS_OK(status)) 274 printf("ok"); 275 printf("\n"); 276 } 277 #endif /* DEBUG */ 278 279 #ifdef UCTEST 280 /* 281 * For SesamI debugging, just map the SRAM directly to a kernel 282 * VA and read it out from there 283 */ 284 285 #include <sys/vmem.h> 286 #include <vm/seg_kmem.h> 287 288 /* 289 * 0x4081F1323000LL is the HWD base address for LSB 0. But we need to map 290 * at page boundaries. So, we use a base address of 0x4081F1322000LL. 291 * Note that this has to match the HWD base pa set in .sesami-common-defs. 292 * 293 * The size specified for the HWD in the SCF spec is 36K. But since 294 * we adjusted the base address by 4K, we need to use 40K for the 295 * mapping size to cover the HWD. And 40K is also a multiple of the 296 * base page size. 297 */ 298 #define OPL_HWD_BASE(lsb) \ 299 (0x4081F1322000LL | (((uint64_t)(lsb)) << 40)) 300 301 void *opl_hwd_vaddr; 302 #endif /* UCTEST */ 303 304 /* 305 * Get the hardware descriptor from SCF. 306 */ 307 308 /*ARGSUSED*/ 309 int 310 opl_read_hwd(int board, hwd_header_t **hdrp, hwd_sb_status_t **statp, 311 hwd_domain_info_t **dinfop, hwd_sb_t **sbp) 312 { 313 static int (*getinfop)(uint32_t, uint8_t, uint32_t, uint32_t *, 314 void *) = NULL; 315 void *hwdp; 316 317 uint32_t key = KEY_ESCF; /* required value */ 318 uint8_t type = 0x40; /* SUB_OS_RECEIVE_HWD */ 319 uint32_t transid = board; 320 uint32_t datasize = HWD_DATA_SIZE; 321 322 hwd_header_t *hd; 323 hwd_sb_status_t *st; 324 hwd_domain_info_t *di; 325 hwd_sb_t *sb; 326 327 int ret; 328 329 if (opl_boards[board].cfg_hwd == NULL) { 330 #ifdef UCTEST 331 /* 332 * Just map the HWD in SRAM to a kernel VA 333 */ 334 335 size_t size; 336 pfn_t pfn; 337 338 size = 0xA000; 339 340 opl_hwd_vaddr = vmem_alloc(heap_arena, size, VM_SLEEP); 341 if (opl_hwd_vaddr == NULL) { 342 cmn_err(CE_NOTE, "No space for HWD"); 343 return (-1); 344 } 345 346 pfn = btop(OPL_HWD_BASE(board)); 347 hat_devload(kas.a_hat, opl_hwd_vaddr, size, pfn, PROT_READ, 348 HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); 349 350 hwdp = (void *)((char *)opl_hwd_vaddr + 0x1000); 351 opl_boards[board].cfg_hwd = hwdp; 352 ret = 0; 353 #else 354 355 /* find the scf_service_getinfo() function */ 356 if (getinfop == NULL) 357 getinfop = (int (*)(uint32_t, uint8_t, uint32_t, 358 uint32_t *, 359 void *))modgetsymvalue("scf_service_getinfo", 0); 360 361 if (getinfop == NULL) 362 return (-1); 363 364 /* allocate memory to receive the data */ 365 hwdp = kmem_alloc(HWD_DATA_SIZE, KM_SLEEP); 366 367 /* get the HWD */ 368 ret = (*getinfop)(key, type, transid, &datasize, hwdp); 369 if (ret == 0) 370 opl_boards[board].cfg_hwd = hwdp; 371 else 372 kmem_free(hwdp, HWD_DATA_SIZE); 373 #endif 374 } else { 375 hwdp = opl_boards[board].cfg_hwd; 376 ret = 0; 377 } 378 379 /* copy the data to the destination */ 380 if (ret == 0) { 381 hd = (hwd_header_t *)hwdp; 382 st = (hwd_sb_status_t *) 383 ((char *)hwdp + hd->hdr_sb_status_offset); 384 di = (hwd_domain_info_t *) 385 ((char *)hwdp + hd->hdr_domain_info_offset); 386 sb = (hwd_sb_t *) 387 ((char *)hwdp + hd->hdr_sb_info_offset); 388 if (hdrp != NULL) 389 *hdrp = hd; 390 if (statp != NULL) 391 *statp = st; 392 if (dinfop != NULL) 393 *dinfop = di; 394 if (sbp != NULL) 395 *sbp = sb; 396 } 397 398 return (ret); 399 } 400 401 /* 402 * The opl_probe_t probe structure is used to pass all sorts of parameters 403 * to callback functions during probing. It also contains a snapshot of 404 * the hardware descriptor that is taken at the beginning of a probe. 405 */ 406 static int 407 opl_probe_init(opl_probe_t *probe) 408 { 409 hwd_header_t **hdrp; 410 hwd_sb_status_t **statp; 411 hwd_domain_info_t **dinfop; 412 hwd_sb_t **sbp; 413 int board, ret; 414 415 board = probe->pr_board; 416 417 hdrp = &probe->pr_hdr; 418 statp = &probe->pr_sb_status; 419 dinfop = &probe->pr_dinfo; 420 sbp = &probe->pr_sb; 421 422 /* 423 * Read the hardware descriptor. 424 */ 425 ret = opl_read_hwd(board, hdrp, statp, dinfop, sbp); 426 if (ret != 0) { 427 428 cmn_err(CE_WARN, "IKP: failed to read HWD header"); 429 return (-1); 430 } 431 432 #ifdef DEBUG 433 opl_dump_hwd(probe); 434 #endif 435 return (0); 436 } 437 438 /* 439 * This function is used to obtain pointers to relevant device nodes 440 * which are created by Solaris at boot time. 441 * 442 * This function walks the child nodes of a given node, extracts 443 * the "name" property, if it exists, and passes the node to a 444 * callback init function. The callback determines if this node is 445 * interesting or not. If it is, then a pointer to the node is 446 * stored away by the callback for use during unprobe. 447 * 448 * The DDI get property function allocates storage for the name 449 * property. That needs to be freed within this function. 450 */ 451 static int 452 opl_init_nodes(dev_info_t *parent, opl_init_func_t init) 453 { 454 dev_info_t *node; 455 char *name; 456 int circ, ret; 457 int len; 458 459 ASSERT(parent != NULL); 460 461 /* 462 * Hold parent node busy to walk its child list 463 */ 464 ndi_devi_enter(parent, &circ); 465 node = ddi_get_child(parent); 466 467 while (node != NULL) { 468 469 ret = OPL_GET_PROP(string, node, "name", &name, &len); 470 if (ret != DDI_PROP_SUCCESS) { 471 /* 472 * The property does not exist for this node. 473 */ 474 node = ddi_get_next_sibling(node); 475 continue; 476 } 477 478 ret = init(node, name, len); 479 kmem_free(name, len); 480 if (ret != 0) { 481 482 ndi_devi_exit(parent, circ); 483 return (-1); 484 } 485 486 node = ddi_get_next_sibling(node); 487 } 488 489 ndi_devi_exit(parent, circ); 490 491 return (0); 492 } 493 494 /* 495 * This init function finds all the interesting nodes under the 496 * root node and stores pointers to them. The following nodes 497 * are considered interesting by this implementation: 498 * 499 * "cmp" 500 * These are nodes that represent processor chips. 501 * 502 * "pci" 503 * These are nodes that represent PCI leaves. 504 * 505 * "pseudo-mc" 506 * These are nodes that contain memory information. 507 */ 508 static int 509 opl_init_root_nodes(dev_info_t *node, char *name, int len) 510 { 511 int portid, board, chip, channel, leaf; 512 int ret; 513 514 if (strncmp(name, OPL_CPU_CHIP_NODE, len) == 0) { 515 516 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 517 if (ret != DDI_PROP_SUCCESS) 518 return (-1); 519 520 ret = OPL_GET_PROP(int, node, "board#", &board, -1); 521 if (ret != DDI_PROP_SUCCESS) 522 return (-1); 523 524 chip = OPL_CPU_CHIP(portid); 525 opl_boards[board].cfg_cpu_chips[chip] = node; 526 527 } else if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { 528 529 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 530 if (ret != DDI_PROP_SUCCESS) 531 return (-1); 532 533 board = OPL_IO_PORTID_TO_LSB(portid); 534 channel = OPL_PORTID_TO_CHANNEL(portid); 535 536 if (channel == OPL_CMU_CHANNEL) { 537 538 opl_boards[board].cfg_cmuch_leaf = node; 539 540 } else { 541 542 leaf = OPL_PORTID_TO_LEAF(portid); 543 opl_boards[board].cfg_pcich_leaf[channel][leaf] = node; 544 } 545 } else if (strncmp(name, OPL_PSEUDO_MC_NODE, len) == 0) { 546 547 ret = OPL_GET_PROP(int, node, "board#", &board, -1); 548 if (ret != DDI_PROP_SUCCESS) 549 return (-1); 550 551 ASSERT((board >= 0) && (board < HWD_SBS_PER_DOMAIN)); 552 553 opl_boards[board].cfg_pseudo_mc = node; 554 } 555 556 return (0); 557 } 558 559 /* 560 * This function initializes the OPL IKP feature. Currently, all it does 561 * is find the interesting nodes that Solaris has created at boot time 562 * for boards present at boot time and store pointers to them. This 563 * is useful if those boards are unprobed by DR. 564 */ 565 int 566 opl_init_cfg() 567 { 568 dev_info_t *root; 569 570 if (opl_cfg_inited == 0) { 571 572 root = ddi_root_node(); 573 if ((opl_init_nodes(root, opl_init_root_nodes) != 0)) { 574 cmn_err(CE_WARN, "IKP: init failed"); 575 return (1); 576 } 577 578 opl_cfg_inited = 1; 579 } 580 581 return (0); 582 } 583 584 /* 585 * When DR is initialized, we walk the device tree and acquire a hold on 586 * all the nodes that are interesting to IKP. This is so that the corresponding 587 * branches cannot be deleted. 588 * 589 * The following function informs the walk about which nodes are interesting 590 * so that it can hold the corresponding branches. 591 */ 592 static int 593 opl_hold_node(char *name) 594 { 595 /* 596 * We only need to hold/release the following nodes which 597 * represent separate branches that must be managed. 598 */ 599 return ((strcmp(name, OPL_CPU_CHIP_NODE) == 0) || 600 (strcmp(name, OPL_PSEUDO_MC_NODE) == 0) || 601 (strcmp(name, OPL_PCI_LEAF_NODE) == 0)); 602 } 603 604 static int 605 opl_hold_rele_devtree(dev_info_t *rdip, void *arg) 606 { 607 608 int *holdp = (int *)arg; 609 char *name = ddi_node_name(rdip); 610 611 /* 612 * We only need to hold/release the following nodes which 613 * represent separate branches that must be managed. 614 */ 615 if (opl_hold_node(name) == 0) { 616 /* Not of interest to us */ 617 return (DDI_WALK_PRUNECHILD); 618 } 619 if (*holdp) { 620 ASSERT(!e_ddi_branch_held(rdip)); 621 e_ddi_branch_hold(rdip); 622 } else { 623 ASSERT(e_ddi_branch_held(rdip)); 624 e_ddi_branch_rele(rdip); 625 } 626 627 return (DDI_WALK_PRUNECHILD); 628 } 629 630 void 631 opl_hold_devtree() 632 { 633 dev_info_t *dip; 634 int circ; 635 int hold = 1; 636 637 dip = ddi_root_node(); 638 ndi_devi_enter(dip, &circ); 639 ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold); 640 ndi_devi_exit(dip, circ); 641 } 642 643 void 644 opl_release_devtree() 645 { 646 dev_info_t *dip; 647 int circ; 648 int hold = 0; 649 650 dip = ddi_root_node(); 651 ndi_devi_enter(dip, &circ); 652 ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold); 653 ndi_devi_exit(dip, circ); 654 } 655 656 /* 657 * This is a helper function that allows opl_create_node() to return a 658 * pointer to a newly created node to its caller. 659 */ 660 /*ARGSUSED*/ 661 static void 662 opl_set_node(dev_info_t *node, void *arg, uint_t flags) 663 { 664 opl_probe_t *probe; 665 666 probe = arg; 667 probe->pr_node = node; 668 } 669 670 /* 671 * Function to create a node in the device tree under a specified parent. 672 * 673 * e_ddi_branch_create() allows the creation of a whole branch with a 674 * single call of the function. However, we only use it to create one node 675 * at a time in the case of non-I/O device nodes. In other words, we 676 * create branches by repeatedly using this function. This makes the 677 * code more readable. 678 * 679 * The branch descriptor passed to e_ddi_branch_create() takes two 680 * callbacks. The create() callback is used to set the properties of a 681 * newly created node. The other callback is used to return a pointer 682 * to the newly created node. The create() callback is passed by the 683 * caller of this function based on the kind of node he wishes to 684 * create. 685 * 686 * e_ddi_branch_create() returns with the newly created node held. We 687 * only need to hold the top nodes of the branches we create. We release 688 * the hold for the others. E.g., the "cmp" node needs to be held. Since 689 * we hold the "cmp" node, there is no need to hold the "core" and "cpu" 690 * nodes below it. 691 */ 692 static dev_info_t * 693 opl_create_node(opl_probe_t *probe) 694 { 695 devi_branch_t branch; 696 697 probe->pr_node = NULL; 698 699 branch.arg = probe; 700 branch.type = DEVI_BRANCH_SID; 701 branch.create.sid_branch_create = probe->pr_create; 702 branch.devi_branch_callback = opl_set_node; 703 704 if (e_ddi_branch_create(probe->pr_parent, &branch, NULL, 0) != 0) 705 return (NULL); 706 707 ASSERT(probe->pr_node != NULL); 708 709 if (probe->pr_hold == 0) 710 e_ddi_branch_rele(probe->pr_node); 711 712 return (probe->pr_node); 713 } 714 715 /* 716 * Function to tear down a whole branch rooted at the specified node. 717 * 718 * Although we create each node of a branch individually, we destroy 719 * a whole branch in one call. This is more efficient. 720 */ 721 static int 722 opl_destroy_node(dev_info_t *node) 723 { 724 if (e_ddi_branch_destroy(node, NULL, 0) != 0) { 725 char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 726 (void) ddi_pathname(node, path); 727 cmn_err(CE_WARN, "OPL node removal failed: %s (%p)", path, 728 (void *)node); 729 kmem_free(path, MAXPATHLEN); 730 return (-1); 731 } 732 733 return (0); 734 } 735 736 /* 737 * Set the properties for a "cpu" node. 738 */ 739 /*ARGSUSED*/ 740 static int 741 opl_create_cpu(dev_info_t *node, void *arg, uint_t flags) 742 { 743 opl_probe_t *probe; 744 hwd_cpu_chip_t *chip; 745 hwd_core_t *core; 746 hwd_cpu_t *cpu; 747 int ret; 748 749 probe = arg; 750 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 751 core = &chip->chip_cores[probe->pr_core]; 752 cpu = &core->core_cpus[probe->pr_cpu]; 753 OPL_UPDATE_PROP(string, node, "name", OPL_CPU_NODE); 754 OPL_UPDATE_PROP(string, node, "device_type", OPL_CPU_NODE); 755 756 OPL_UPDATE_PROP(int, node, "cpuid", cpu->cpu_cpuid); 757 OPL_UPDATE_PROP(int, node, "reg", probe->pr_cpu); 758 759 OPL_UPDATE_PROP(string, node, "status", "okay"); 760 761 return (DDI_WALK_TERMINATE); 762 } 763 764 /* 765 * Create "cpu" nodes as child nodes of a given "core" node. 766 */ 767 static int 768 opl_probe_cpus(opl_probe_t *probe) 769 { 770 int i; 771 hwd_cpu_chip_t *chip; 772 hwd_core_t *core; 773 hwd_cpu_t *cpus; 774 775 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 776 core = &chip->chip_cores[probe->pr_core]; 777 cpus = &core->core_cpus[0]; 778 779 for (i = 0; i < HWD_CPUS_PER_CORE; i++) { 780 781 /* 782 * Olympus-C has 2 cpus per core. 783 * Jupiter has 4 cpus per core. 784 * For the Olympus-C based platform, we expect the cpu_status 785 * of the non-existent cpus to be set to missing. 786 */ 787 if (!HWD_STATUS_OK(cpus[i].cpu_status)) 788 continue; 789 790 probe->pr_create = opl_create_cpu; 791 probe->pr_cpu = i; 792 if (opl_create_node(probe) == NULL) { 793 794 cmn_err(CE_WARN, "IKP: create cpu (%d-%d-%d-%d) failed", 795 probe->pr_board, probe->pr_cpu_chip, probe->pr_core, 796 probe->pr_cpu); 797 return (-1); 798 } 799 } 800 801 return (0); 802 } 803 804 /* 805 * Set the properties for a "core" node. 806 */ 807 /*ARGSUSED*/ 808 static int 809 opl_create_core(dev_info_t *node, void *arg, uint_t flags) 810 { 811 opl_probe_t *probe; 812 hwd_cpu_chip_t *chip; 813 hwd_core_t *core; 814 int sharing[2]; 815 int ret; 816 817 probe = arg; 818 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 819 core = &chip->chip_cores[probe->pr_core]; 820 821 OPL_UPDATE_PROP(string, node, "name", OPL_CORE_NODE); 822 OPL_UPDATE_PROP(string, node, "device_type", OPL_CORE_NODE); 823 OPL_UPDATE_PROP(string, node, "compatible", chip->chip_compatible); 824 825 OPL_UPDATE_PROP(int, node, "reg", probe->pr_core); 826 OPL_UPDATE_PROP(int, node, "manufacturer#", core->core_manufacturer); 827 OPL_UPDATE_PROP(int, node, "implementation#", 828 core->core_implementation); 829 OPL_UPDATE_PROP(int, node, "mask#", core->core_mask); 830 831 OPL_UPDATE_PROP(int, node, "sparc-version", 9); 832 OPL_UPDATE_PROP(int, node, "clock-frequency", core->core_frequency); 833 834 OPL_UPDATE_PROP(int, node, "l1-icache-size", core->core_l1_icache_size); 835 OPL_UPDATE_PROP(int, node, "l1-icache-line-size", 836 core->core_l1_icache_line_size); 837 OPL_UPDATE_PROP(int, node, "l1-icache-associativity", 838 core->core_l1_icache_associativity); 839 OPL_UPDATE_PROP(int, node, "#itlb-entries", 840 core->core_num_itlb_entries); 841 842 OPL_UPDATE_PROP(int, node, "l1-dcache-size", core->core_l1_dcache_size); 843 OPL_UPDATE_PROP(int, node, "l1-dcache-line-size", 844 core->core_l1_dcache_line_size); 845 OPL_UPDATE_PROP(int, node, "l1-dcache-associativity", 846 core->core_l1_dcache_associativity); 847 OPL_UPDATE_PROP(int, node, "#dtlb-entries", 848 core->core_num_dtlb_entries); 849 850 OPL_UPDATE_PROP(int, node, "l2-cache-size", core->core_l2_cache_size); 851 OPL_UPDATE_PROP(int, node, "l2-cache-line-size", 852 core->core_l2_cache_line_size); 853 OPL_UPDATE_PROP(int, node, "l2-cache-associativity", 854 core->core_l2_cache_associativity); 855 sharing[0] = 0; 856 sharing[1] = core->core_l2_cache_sharing; 857 OPL_UPDATE_PROP_ARRAY(int, node, "l2-cache-sharing", sharing, 2); 858 859 OPL_UPDATE_PROP(string, node, "status", "okay"); 860 861 return (DDI_WALK_TERMINATE); 862 } 863 864 /* 865 * Create "core" nodes as child nodes of a given "cmp" node. 866 * 867 * Create the branch below each "core" node". 868 */ 869 static int 870 opl_probe_cores(opl_probe_t *probe) 871 { 872 int i; 873 hwd_cpu_chip_t *chip; 874 hwd_core_t *cores; 875 dev_info_t *parent, *node; 876 877 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 878 cores = &chip->chip_cores[0]; 879 parent = probe->pr_parent; 880 881 for (i = 0; i < HWD_CORES_PER_CPU_CHIP; i++) { 882 883 if (!HWD_STATUS_OK(cores[i].core_status)) 884 continue; 885 886 probe->pr_parent = parent; 887 probe->pr_create = opl_create_core; 888 probe->pr_core = i; 889 node = opl_create_node(probe); 890 if (node == NULL) { 891 892 cmn_err(CE_WARN, "IKP: create core (%d-%d-%d) failed", 893 probe->pr_board, probe->pr_cpu_chip, 894 probe->pr_core); 895 return (-1); 896 } 897 898 /* 899 * Create "cpu" nodes below "core". 900 */ 901 probe->pr_parent = node; 902 if (opl_probe_cpus(probe) != 0) 903 return (-1); 904 probe->pr_cpu_impl |= (1 << cores[i].core_implementation); 905 } 906 907 return (0); 908 } 909 910 /* 911 * Set the properties for a "cmp" node. 912 */ 913 /*ARGSUSED*/ 914 static int 915 opl_create_cpu_chip(dev_info_t *node, void *arg, uint_t flags) 916 { 917 opl_probe_t *probe; 918 hwd_cpu_chip_t *chip; 919 opl_range_t range; 920 uint64_t dummy_addr; 921 int ret; 922 923 probe = arg; 924 chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; 925 926 OPL_UPDATE_PROP(string, node, "name", OPL_CPU_CHIP_NODE); 927 928 OPL_UPDATE_PROP(int, node, "portid", chip->chip_portid); 929 OPL_UPDATE_PROP(int, node, "board#", probe->pr_board); 930 931 dummy_addr = OPL_PROC_AS(probe->pr_board, probe->pr_cpu_chip); 932 range.rg_addr_hi = OPL_HI(dummy_addr); 933 range.rg_addr_lo = OPL_LO(dummy_addr); 934 range.rg_size_hi = 0; 935 range.rg_size_lo = 0; 936 OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); 937 938 OPL_UPDATE_PROP(int, node, "#address-cells", 1); 939 OPL_UPDATE_PROP(int, node, "#size-cells", 0); 940 941 OPL_UPDATE_PROP(string, node, "status", "okay"); 942 943 return (DDI_WALK_TERMINATE); 944 } 945 946 /* 947 * Create "cmp" nodes as child nodes of the root node. 948 * 949 * Create the branch below each "cmp" node. 950 */ 951 static int 952 opl_probe_cpu_chips(opl_probe_t *probe) 953 { 954 int i; 955 dev_info_t **cfg_cpu_chips; 956 hwd_cpu_chip_t *chips; 957 dev_info_t *node; 958 959 cfg_cpu_chips = opl_boards[probe->pr_board].cfg_cpu_chips; 960 chips = &probe->pr_sb->sb_cmu.cmu_cpu_chips[0]; 961 962 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 963 964 ASSERT(cfg_cpu_chips[i] == NULL); 965 966 if (!HWD_STATUS_OK(chips[i].chip_status)) 967 continue; 968 969 probe->pr_parent = ddi_root_node(); 970 probe->pr_create = opl_create_cpu_chip; 971 probe->pr_cpu_chip = i; 972 probe->pr_hold = 1; 973 node = opl_create_node(probe); 974 if (node == NULL) { 975 976 cmn_err(CE_WARN, "IKP: create chip (%d-%d) failed", 977 probe->pr_board, probe->pr_cpu_chip); 978 return (-1); 979 } 980 981 cfg_cpu_chips[i] = node; 982 983 /* 984 * Create "core" nodes below "cmp". 985 * We hold the "cmp" node. So, there is no need to hold 986 * the "core" and "cpu" nodes below it. 987 */ 988 probe->pr_parent = node; 989 probe->pr_hold = 0; 990 if (opl_probe_cores(probe) != 0) 991 return (-1); 992 } 993 994 return (0); 995 } 996 997 /* 998 * Set the properties for a "pseudo-mc" node. 999 */ 1000 /*ARGSUSED*/ 1001 static int 1002 opl_create_pseudo_mc(dev_info_t *node, void *arg, uint_t flags) 1003 { 1004 opl_probe_t *probe; 1005 int board, portid; 1006 hwd_bank_t *bank; 1007 hwd_memory_t *mem; 1008 opl_range_t range; 1009 opl_mc_addr_t mc[HWD_BANKS_PER_CMU]; 1010 int status[2][7]; 1011 int i, j; 1012 int ret; 1013 1014 probe = arg; 1015 board = probe->pr_board; 1016 1017 OPL_UPDATE_PROP(string, node, "name", OPL_PSEUDO_MC_NODE); 1018 OPL_UPDATE_PROP(string, node, "device_type", "memory-controller"); 1019 OPL_UPDATE_PROP(string, node, "compatible", "FJSV,oplmc"); 1020 1021 portid = OPL_LSB_TO_PSEUDOMC_PORTID(board); 1022 OPL_UPDATE_PROP(int, node, "portid", portid); 1023 1024 range.rg_addr_hi = OPL_HI(OPL_MC_AS(board)); 1025 range.rg_addr_lo = 0x200; 1026 range.rg_size_hi = 0; 1027 range.rg_size_lo = 0; 1028 OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); 1029 1030 OPL_UPDATE_PROP(int, node, "board#", board); 1031 OPL_UPDATE_PROP(int, node, "physical-board#", 1032 probe->pr_sb->sb_psb_number); 1033 1034 OPL_UPDATE_PROP(int, node, "#address-cells", 1); 1035 OPL_UPDATE_PROP(int, node, "#size-cells", 2); 1036 1037 mem = &probe->pr_sb->sb_cmu.cmu_memory; 1038 1039 range.rg_addr_hi = OPL_HI(mem->mem_start_address); 1040 range.rg_addr_lo = OPL_LO(mem->mem_start_address); 1041 range.rg_size_hi = OPL_HI(mem->mem_size); 1042 range.rg_size_lo = OPL_LO(mem->mem_size); 1043 OPL_UPDATE_PROP_ARRAY(int, node, "sb-mem-ranges", (int *)&range, 4); 1044 1045 bank = probe->pr_sb->sb_cmu.cmu_memory.mem_banks; 1046 for (i = 0, j = 0; i < HWD_BANKS_PER_CMU; i++) { 1047 1048 if (!HWD_STATUS_OK(bank[i].bank_status)) 1049 continue; 1050 1051 mc[j].mc_bank = i; 1052 mc[j].mc_hi = OPL_HI(bank[i].bank_register_address); 1053 mc[j].mc_lo = OPL_LO(bank[i].bank_register_address); 1054 j++; 1055 } 1056 1057 if (j > 0) { 1058 OPL_UPDATE_PROP_ARRAY(int, node, "mc-addr", (int *)mc, j*3); 1059 } else { 1060 /* 1061 * If there is no memory, we need the mc-addr property, but 1062 * it is length 0. The only way to do this using ndi seems 1063 * to be by creating a boolean property. 1064 */ 1065 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node, "mc-addr"); 1066 OPL_UPDATE_PROP_ERR(ret, "mc-addr"); 1067 } 1068 1069 OPL_UPDATE_PROP_ARRAY(byte, node, "cs0-mc-pa-trans-table", 1070 mem->mem_cs[0].cs_pa_mac_table, 64); 1071 OPL_UPDATE_PROP_ARRAY(byte, node, "cs1-mc-pa-trans-table", 1072 mem->mem_cs[1].cs_pa_mac_table, 64); 1073 1074 #define CS_PER_MEM 2 1075 1076 for (i = 0, j = 0; i < CS_PER_MEM; i++) { 1077 if (HWD_STATUS_OK(mem->mem_cs[i].cs_status) || 1078 HWD_STATUS_FAILED(mem->mem_cs[i].cs_status)) { 1079 status[j][0] = i; 1080 if (HWD_STATUS_OK(mem->mem_cs[i].cs_status)) 1081 status[j][1] = 0; 1082 else 1083 status[j][1] = 1; 1084 status[j][2] = 1085 OPL_HI(mem->mem_cs[i].cs_available_capacity); 1086 status[j][3] = 1087 OPL_LO(mem->mem_cs[i].cs_available_capacity); 1088 status[j][4] = OPL_HI(mem->mem_cs[i].cs_dimm_capacity); 1089 status[j][5] = OPL_LO(mem->mem_cs[i].cs_dimm_capacity); 1090 status[j][6] = mem->mem_cs[i].cs_number_of_dimms; 1091 j++; 1092 } 1093 } 1094 1095 if (j > 0) { 1096 OPL_UPDATE_PROP_ARRAY(int, node, "cs-status", (int *)status, 1097 j*7); 1098 } else { 1099 /* 1100 * If there is no memory, we need the cs-status property, but 1101 * it is length 0. The only way to do this using ndi seems 1102 * to be by creating a boolean property. 1103 */ 1104 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, node, 1105 "cs-status"); 1106 OPL_UPDATE_PROP_ERR(ret, "cs-status"); 1107 } 1108 1109 return (DDI_WALK_TERMINATE); 1110 } 1111 1112 /* 1113 * Create "pseudo-mc" nodes 1114 */ 1115 static int 1116 opl_probe_memory(opl_probe_t *probe) 1117 { 1118 int board; 1119 opl_board_cfg_t *board_cfg; 1120 dev_info_t *node; 1121 1122 board = probe->pr_board; 1123 board_cfg = &opl_boards[board]; 1124 1125 ASSERT(board_cfg->cfg_pseudo_mc == NULL); 1126 1127 probe->pr_parent = ddi_root_node(); 1128 probe->pr_create = opl_create_pseudo_mc; 1129 probe->pr_hold = 1; 1130 node = opl_create_node(probe); 1131 if (node == NULL) { 1132 1133 cmn_err(CE_WARN, "IKP: create pseudo-mc (%d) failed", board); 1134 return (-1); 1135 } 1136 1137 board_cfg->cfg_pseudo_mc = node; 1138 1139 return (0); 1140 } 1141 1142 /* 1143 * Allocate the fcode ops handle. 1144 */ 1145 /*ARGSUSED*/ 1146 static 1147 fco_handle_t 1148 opl_fc_ops_alloc_handle(dev_info_t *parent, dev_info_t *child, 1149 void *fcode, size_t fcode_size, char *unit_address, 1150 char *my_args) 1151 { 1152 fco_handle_t rp; 1153 phandle_t h; 1154 char *buf; 1155 1156 rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); 1157 rp->next_handle = fc_ops_alloc_handle(parent, child, fcode, fcode_size, 1158 unit_address, NULL); 1159 rp->ap = parent; 1160 rp->child = child; 1161 rp->fcode = fcode; 1162 rp->fcode_size = fcode_size; 1163 rp->my_args = my_args; 1164 1165 if (unit_address) { 1166 buf = kmem_zalloc(UNIT_ADDR_SIZE, KM_SLEEP); 1167 (void) strcpy(buf, unit_address); 1168 rp->unit_address = buf; 1169 } 1170 1171 /* 1172 * Add the child's nodeid to our table... 1173 */ 1174 h = ddi_get_nodeid(rp->child); 1175 fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); 1176 1177 return (rp); 1178 } 1179 1180 1181 static void 1182 opl_fc_ops_free_handle(fco_handle_t rp) 1183 { 1184 struct fc_resource *resp, *nresp; 1185 1186 ASSERT(rp); 1187 1188 if (rp->next_handle) 1189 fc_ops_free_handle(rp->next_handle); 1190 if (rp->unit_address) 1191 kmem_free(rp->unit_address, UNIT_ADDR_SIZE); 1192 1193 /* 1194 * Release all the resources from the resource list 1195 */ 1196 for (resp = rp->head; resp != NULL; resp = nresp) { 1197 nresp = resp->next; 1198 switch (resp->type) { 1199 1200 case RT_MAP: 1201 /* 1202 * If this is still mapped, we'd better unmap it now, 1203 * or all our structures that are tracking it will 1204 * be leaked. 1205 */ 1206 if (resp->fc_map_handle != NULL) 1207 opl_unmap_phys(&resp->fc_map_handle); 1208 break; 1209 1210 case RT_DMA: 1211 /* 1212 * DMA has to be freed up at exit time. 1213 */ 1214 cmn_err(CE_CONT, 1215 "opl_fc_ops_free_handle: Unexpected DMA seen!"); 1216 break; 1217 1218 case RT_CONTIGIOUS: 1219 FC_DEBUG2(1, CE_CONT, "opl_fc_ops_free: " 1220 "Free claim-memory resource 0x%lx size 0x%x\n", 1221 resp->fc_contig_virt, resp->fc_contig_len); 1222 1223 (void) ndi_ra_free(ddi_root_node(), 1224 (uint64_t)resp->fc_contig_virt, 1225 resp->fc_contig_len, "opl-fcodemem", 1226 NDI_RA_PASS); 1227 1228 break; 1229 1230 default: 1231 cmn_err(CE_CONT, "opl_fc_ops_free: " 1232 "unknown resource type %d", resp->type); 1233 break; 1234 } 1235 fc_rem_resource(rp, resp); 1236 kmem_free(resp, sizeof (struct fc_resource)); 1237 } 1238 1239 kmem_free(rp, sizeof (struct fc_resource_list)); 1240 } 1241 1242 int 1243 opl_fc_do_op(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1244 { 1245 opl_fc_ops_t *op; 1246 char *service = fc_cell2ptr(cp->svc_name); 1247 1248 ASSERT(rp); 1249 1250 FC_DEBUG1(1, CE_CONT, "opl_fc_do_op: <%s>\n", service); 1251 1252 /* 1253 * First try the generic fc_ops. 1254 */ 1255 if (fc_ops(ap, rp->next_handle, cp) == 0) 1256 return (0); 1257 1258 /* 1259 * Now try the Jupiter-specific ops. 1260 */ 1261 for (op = opl_fc_ops; op->fc_service != NULL; ++op) 1262 if (strcmp(op->fc_service, service) == 0) 1263 return (op->fc_op(ap, rp, cp)); 1264 1265 FC_DEBUG1(9, CE_CONT, "opl_fc_do_op: <%s> not serviced\n", service); 1266 1267 return (-1); 1268 } 1269 1270 /* 1271 * map-in (phys.lo phys.hi size -- virt) 1272 */ 1273 static int 1274 opl_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1275 { 1276 size_t len; 1277 int error; 1278 caddr_t virt; 1279 struct fc_resource *resp; 1280 struct regspec rspec; 1281 ddi_device_acc_attr_t acc; 1282 ddi_acc_handle_t h; 1283 1284 if (fc_cell2int(cp->nargs) != 3) 1285 return (fc_syntax_error(cp, "nargs must be 3")); 1286 1287 if (fc_cell2int(cp->nresults) < 1) 1288 return (fc_syntax_error(cp, "nresults must be >= 1")); 1289 1290 rspec.regspec_size = len = fc_cell2size(fc_arg(cp, 0)); 1291 rspec.regspec_bustype = fc_cell2uint(fc_arg(cp, 1)); 1292 rspec.regspec_addr = fc_cell2uint(fc_arg(cp, 2)); 1293 1294 acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1295 acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; 1296 acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1297 1298 FC_DEBUG3(1, CE_CONT, "opl_map_in: attempting map in " 1299 "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, 1300 rspec.regspec_addr, rspec.regspec_size); 1301 1302 error = opl_map_phys(rp->child, &rspec, &virt, &acc, &h); 1303 1304 if (error) { 1305 FC_DEBUG3(1, CE_CONT, "opl_map_in: map in failed - " 1306 "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, 1307 rspec.regspec_addr, rspec.regspec_size); 1308 1309 return (fc_priv_error(cp, "opl map-in failed")); 1310 } 1311 1312 FC_DEBUG1(3, CE_CONT, "opl_map_in: returning virt %p\n", virt); 1313 1314 cp->nresults = fc_int2cell(1); 1315 fc_result(cp, 0) = fc_ptr2cell(virt); 1316 1317 /* 1318 * Log this resource ... 1319 */ 1320 resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 1321 resp->type = RT_MAP; 1322 resp->fc_map_virt = virt; 1323 resp->fc_map_len = len; 1324 resp->fc_map_handle = h; 1325 fc_add_resource(rp, resp); 1326 1327 return (fc_success_op(ap, rp, cp)); 1328 } 1329 1330 /* 1331 * map-out (virt size -- ) 1332 */ 1333 static int 1334 opl_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1335 { 1336 caddr_t virt; 1337 size_t len; 1338 struct fc_resource *resp; 1339 1340 if (fc_cell2int(cp->nargs) != 2) 1341 return (fc_syntax_error(cp, "nargs must be 2")); 1342 1343 virt = fc_cell2ptr(fc_arg(cp, 1)); 1344 1345 len = fc_cell2size(fc_arg(cp, 0)); 1346 1347 FC_DEBUG2(1, CE_CONT, "opl_map_out: attempting map out %p %x\n", 1348 virt, len); 1349 1350 /* 1351 * Find if this request matches a mapping resource we set up. 1352 */ 1353 fc_lock_resource_list(rp); 1354 for (resp = rp->head; resp != NULL; resp = resp->next) { 1355 if (resp->type != RT_MAP) 1356 continue; 1357 if (resp->fc_map_virt != virt) 1358 continue; 1359 if (resp->fc_map_len == len) 1360 break; 1361 } 1362 fc_unlock_resource_list(rp); 1363 1364 if (resp == NULL) 1365 return (fc_priv_error(cp, "request doesn't match a " 1366 "known mapping")); 1367 1368 opl_unmap_phys(&resp->fc_map_handle); 1369 1370 /* 1371 * remove the resource from the list and release it. 1372 */ 1373 fc_rem_resource(rp, resp); 1374 kmem_free(resp, sizeof (struct fc_resource)); 1375 1376 cp->nresults = fc_int2cell(0); 1377 return (fc_success_op(ap, rp, cp)); 1378 } 1379 1380 static int 1381 opl_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1382 { 1383 size_t len; 1384 caddr_t virt; 1385 int error = 0; 1386 uint64_t v; 1387 uint64_t x; 1388 uint32_t l; 1389 uint16_t w; 1390 uint8_t b; 1391 char *service = fc_cell2ptr(cp->svc_name); 1392 struct fc_resource *resp; 1393 1394 if (fc_cell2int(cp->nargs) != 1) 1395 return (fc_syntax_error(cp, "nargs must be 1")); 1396 1397 if (fc_cell2int(cp->nresults) < 1) 1398 return (fc_syntax_error(cp, "nresults must be >= 1")); 1399 1400 virt = fc_cell2ptr(fc_arg(cp, 0)); 1401 1402 /* 1403 * Determine the access width .. we can switch on the 2nd 1404 * character of the name which is "rx@", "rl@", "rb@" or "rw@" 1405 */ 1406 switch (*(service + 1)) { 1407 case 'x': len = sizeof (x); break; 1408 case 'l': len = sizeof (l); break; 1409 case 'w': len = sizeof (w); break; 1410 case 'b': len = sizeof (b); break; 1411 } 1412 1413 /* 1414 * Check the alignment ... 1415 */ 1416 if (((intptr_t)virt & (len - 1)) != 0) 1417 return (fc_priv_error(cp, "unaligned access")); 1418 1419 /* 1420 * Find if this virt is 'within' a request we know about 1421 */ 1422 fc_lock_resource_list(rp); 1423 for (resp = rp->head; resp != NULL; resp = resp->next) { 1424 if (resp->type == RT_MAP) { 1425 if ((virt >= (caddr_t)resp->fc_map_virt) && 1426 ((virt + len) <= 1427 ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) 1428 break; 1429 } else if (resp->type == RT_CONTIGIOUS) { 1430 if ((virt >= (caddr_t)resp->fc_contig_virt) && 1431 ((virt + len) <= ((caddr_t)resp->fc_contig_virt + 1432 resp->fc_contig_len))) 1433 break; 1434 } 1435 } 1436 fc_unlock_resource_list(rp); 1437 1438 if (resp == NULL) { 1439 return (fc_priv_error(cp, "request not within " 1440 "known mappings")); 1441 } 1442 1443 switch (len) { 1444 case sizeof (x): 1445 if (resp->type == RT_MAP) 1446 error = ddi_peek64(rp->child, (int64_t *)virt, 1447 (int64_t *)&x); 1448 else /* RT_CONTIGIOUS */ 1449 x = *(int64_t *)virt; 1450 v = x; 1451 break; 1452 case sizeof (l): 1453 if (resp->type == RT_MAP) 1454 error = ddi_peek32(rp->child, (int32_t *)virt, 1455 (int32_t *)&l); 1456 else /* RT_CONTIGIOUS */ 1457 l = *(int32_t *)virt; 1458 v = l; 1459 break; 1460 case sizeof (w): 1461 if (resp->type == RT_MAP) 1462 error = ddi_peek16(rp->child, (int16_t *)virt, 1463 (int16_t *)&w); 1464 else /* RT_CONTIGIOUS */ 1465 w = *(int16_t *)virt; 1466 v = w; 1467 break; 1468 case sizeof (b): 1469 if (resp->type == RT_MAP) 1470 error = ddi_peek8(rp->child, (int8_t *)virt, 1471 (int8_t *)&b); 1472 else /* RT_CONTIGIOUS */ 1473 b = *(int8_t *)virt; 1474 v = b; 1475 break; 1476 } 1477 1478 if (error == DDI_FAILURE) { 1479 FC_DEBUG2(1, CE_CONT, "opl_register_fetch: access error " 1480 "accessing virt %p len %d\n", virt, len); 1481 return (fc_priv_error(cp, "access error")); 1482 } 1483 1484 FC_DEBUG3(1, CE_CONT, "register_fetch (%s) %llx %llx\n", 1485 service, virt, v); 1486 1487 cp->nresults = fc_int2cell(1); 1488 switch (len) { 1489 case sizeof (x): fc_result(cp, 0) = x; break; 1490 case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; 1491 case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; 1492 case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; 1493 } 1494 return (fc_success_op(ap, rp, cp)); 1495 } 1496 1497 static int 1498 opl_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1499 { 1500 size_t len; 1501 caddr_t virt; 1502 uint64_t v; 1503 uint64_t x; 1504 uint32_t l; 1505 uint16_t w; 1506 uint8_t b; 1507 char *service = fc_cell2ptr(cp->svc_name); 1508 struct fc_resource *resp; 1509 int error = 0; 1510 1511 if (fc_cell2int(cp->nargs) != 2) 1512 return (fc_syntax_error(cp, "nargs must be 2")); 1513 1514 virt = fc_cell2ptr(fc_arg(cp, 0)); 1515 1516 /* 1517 * Determine the access width .. we can switch on the 2nd 1518 * character of the name which is "rx!", "rl!", "rb!" or "rw!" 1519 */ 1520 switch (*(service + 1)) { 1521 case 'x': 1522 len = sizeof (x); 1523 x = fc_arg(cp, 1); 1524 v = x; 1525 break; 1526 case 'l': 1527 len = sizeof (l); 1528 l = fc_cell2uint32_t(fc_arg(cp, 1)); 1529 v = l; 1530 break; 1531 case 'w': 1532 len = sizeof (w); 1533 w = fc_cell2uint16_t(fc_arg(cp, 1)); 1534 v = w; 1535 break; 1536 case 'b': 1537 len = sizeof (b); 1538 b = fc_cell2uint8_t(fc_arg(cp, 1)); 1539 v = b; 1540 break; 1541 } 1542 1543 FC_DEBUG3(1, CE_CONT, "register_store (%s) %llx %llx\n", 1544 service, virt, v); 1545 1546 /* 1547 * Check the alignment ... 1548 */ 1549 if (((intptr_t)virt & (len - 1)) != 0) 1550 return (fc_priv_error(cp, "unaligned access")); 1551 1552 /* 1553 * Find if this virt is 'within' a request we know about 1554 */ 1555 fc_lock_resource_list(rp); 1556 for (resp = rp->head; resp != NULL; resp = resp->next) { 1557 if (resp->type == RT_MAP) { 1558 if ((virt >= (caddr_t)resp->fc_map_virt) && 1559 ((virt + len) <= 1560 ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) 1561 break; 1562 } else if (resp->type == RT_CONTIGIOUS) { 1563 if ((virt >= (caddr_t)resp->fc_contig_virt) && 1564 ((virt + len) <= ((caddr_t)resp->fc_contig_virt + 1565 resp->fc_contig_len))) 1566 break; 1567 } 1568 } 1569 fc_unlock_resource_list(rp); 1570 1571 if (resp == NULL) 1572 return (fc_priv_error(cp, "request not within" 1573 "known mappings")); 1574 1575 switch (len) { 1576 case sizeof (x): 1577 if (resp->type == RT_MAP) 1578 error = ddi_poke64(rp->child, (int64_t *)virt, x); 1579 else if (resp->type == RT_CONTIGIOUS) 1580 *(uint64_t *)virt = x; 1581 break; 1582 case sizeof (l): 1583 if (resp->type == RT_MAP) 1584 error = ddi_poke32(rp->child, (int32_t *)virt, l); 1585 else if (resp->type == RT_CONTIGIOUS) 1586 *(uint32_t *)virt = l; 1587 break; 1588 case sizeof (w): 1589 if (resp->type == RT_MAP) 1590 error = ddi_poke16(rp->child, (int16_t *)virt, w); 1591 else if (resp->type == RT_CONTIGIOUS) 1592 *(uint16_t *)virt = w; 1593 break; 1594 case sizeof (b): 1595 if (resp->type == RT_MAP) 1596 error = ddi_poke8(rp->child, (int8_t *)virt, b); 1597 else if (resp->type == RT_CONTIGIOUS) 1598 *(uint8_t *)virt = b; 1599 break; 1600 } 1601 1602 if (error == DDI_FAILURE) { 1603 FC_DEBUG2(1, CE_CONT, "opl_register_store: access error " 1604 "accessing virt %p len %d\n", virt, len); 1605 return (fc_priv_error(cp, "access error")); 1606 } 1607 1608 cp->nresults = fc_int2cell(0); 1609 return (fc_success_op(ap, rp, cp)); 1610 } 1611 1612 /* 1613 * opl_claim_memory 1614 * 1615 * claim-memory (align size vhint -- vaddr) 1616 */ 1617 static int 1618 opl_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1619 { 1620 int align, size, vhint; 1621 uint64_t answer, alen; 1622 ndi_ra_request_t request; 1623 struct fc_resource *resp; 1624 1625 if (fc_cell2int(cp->nargs) != 3) 1626 return (fc_syntax_error(cp, "nargs must be 3")); 1627 1628 if (fc_cell2int(cp->nresults) < 1) 1629 return (fc_syntax_error(cp, "nresults must be >= 1")); 1630 1631 vhint = fc_cell2int(fc_arg(cp, 2)); 1632 size = fc_cell2int(fc_arg(cp, 1)); 1633 align = fc_cell2int(fc_arg(cp, 0)); 1634 1635 FC_DEBUG3(1, CE_CONT, "opl_claim_memory: align=0x%x size=0x%x " 1636 "vhint=0x%x\n", align, size, vhint); 1637 1638 if (size == 0) { 1639 cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " 1640 "contiguous memory of size zero\n"); 1641 return (fc_priv_error(cp, "allocation error")); 1642 } 1643 1644 if (vhint) { 1645 cmn_err(CE_WARN, "opl_claim_memory - vhint is not zero " 1646 "vhint=0x%x - Ignoring Argument\n", vhint); 1647 } 1648 1649 bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); 1650 request.ra_flags = NDI_RA_ALLOC_BOUNDED; 1651 request.ra_boundbase = 0; 1652 request.ra_boundlen = 0xffffffff; 1653 request.ra_len = size; 1654 request.ra_align_mask = align - 1; 1655 1656 if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen, 1657 "opl-fcodemem", NDI_RA_PASS) != NDI_SUCCESS) { 1658 cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " 1659 "contiguous memory\n"); 1660 return (fc_priv_error(cp, "allocation error")); 1661 } 1662 1663 FC_DEBUG2(1, CE_CONT, "opl_claim_memory: address allocated=0x%lx " 1664 "size=0x%x\n", answer, alen); 1665 1666 cp->nresults = fc_int2cell(1); 1667 fc_result(cp, 0) = answer; 1668 1669 /* 1670 * Log this resource ... 1671 */ 1672 resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); 1673 resp->type = RT_CONTIGIOUS; 1674 resp->fc_contig_virt = (void *)answer; 1675 resp->fc_contig_len = size; 1676 fc_add_resource(rp, resp); 1677 1678 return (fc_success_op(ap, rp, cp)); 1679 } 1680 1681 /* 1682 * opl_release_memory 1683 * 1684 * release-memory (size vaddr -- ) 1685 */ 1686 static int 1687 opl_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1688 { 1689 int32_t vaddr, size; 1690 struct fc_resource *resp; 1691 1692 if (fc_cell2int(cp->nargs) != 2) 1693 return (fc_syntax_error(cp, "nargs must be 2")); 1694 1695 if (fc_cell2int(cp->nresults) != 0) 1696 return (fc_syntax_error(cp, "nresults must be 0")); 1697 1698 vaddr = fc_cell2int(fc_arg(cp, 1)); 1699 size = fc_cell2int(fc_arg(cp, 0)); 1700 1701 FC_DEBUG2(1, CE_CONT, "opl_release_memory: vaddr=0x%x size=0x%x\n", 1702 vaddr, size); 1703 1704 /* 1705 * Find if this request matches a mapping resource we set up. 1706 */ 1707 fc_lock_resource_list(rp); 1708 for (resp = rp->head; resp != NULL; resp = resp->next) { 1709 if (resp->type != RT_CONTIGIOUS) 1710 continue; 1711 if (resp->fc_contig_virt != (void *)(uintptr_t)vaddr) 1712 continue; 1713 if (resp->fc_contig_len == size) 1714 break; 1715 } 1716 fc_unlock_resource_list(rp); 1717 1718 if (resp == NULL) 1719 return (fc_priv_error(cp, "request doesn't match a " 1720 "known mapping")); 1721 1722 (void) ndi_ra_free(ddi_root_node(), vaddr, size, 1723 "opl-fcodemem", NDI_RA_PASS); 1724 1725 /* 1726 * remove the resource from the list and release it. 1727 */ 1728 fc_rem_resource(rp, resp); 1729 kmem_free(resp, sizeof (struct fc_resource)); 1730 1731 cp->nresults = fc_int2cell(0); 1732 1733 return (fc_success_op(ap, rp, cp)); 1734 } 1735 1736 /* 1737 * opl_vtop 1738 * 1739 * vtop (vaddr -- paddr.lo paddr.hi) 1740 */ 1741 static int 1742 opl_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1743 { 1744 int vaddr; 1745 uint64_t paddr; 1746 struct fc_resource *resp; 1747 1748 if (fc_cell2int(cp->nargs) != 1) 1749 return (fc_syntax_error(cp, "nargs must be 1")); 1750 1751 if (fc_cell2int(cp->nresults) >= 3) 1752 return (fc_syntax_error(cp, "nresults must be less than 2")); 1753 1754 vaddr = fc_cell2int(fc_arg(cp, 0)); 1755 1756 /* 1757 * Find if this request matches a mapping resource we set up. 1758 */ 1759 fc_lock_resource_list(rp); 1760 for (resp = rp->head; resp != NULL; resp = resp->next) { 1761 if (resp->type != RT_CONTIGIOUS) 1762 continue; 1763 if (((uint64_t)resp->fc_contig_virt <= vaddr) && 1764 (vaddr < (uint64_t)resp->fc_contig_virt + 1765 resp->fc_contig_len)) 1766 break; 1767 } 1768 fc_unlock_resource_list(rp); 1769 1770 if (resp == NULL) 1771 return (fc_priv_error(cp, "request doesn't match a " 1772 "known mapping")); 1773 1774 paddr = va_to_pa((void *)(uintptr_t)vaddr); 1775 1776 FC_DEBUG2(1, CE_CONT, "opl_vtop: vaddr=0x%x paddr=0x%x\n", 1777 vaddr, paddr); 1778 1779 cp->nresults = fc_int2cell(2); 1780 1781 fc_result(cp, 0) = paddr; 1782 fc_result(cp, 1) = 0; 1783 1784 return (fc_success_op(ap, rp, cp)); 1785 } 1786 1787 static int 1788 opl_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1789 { 1790 fc_phandle_t h; 1791 1792 if (fc_cell2int(cp->nargs) != 0) 1793 return (fc_syntax_error(cp, "nargs must be 0")); 1794 1795 if (fc_cell2int(cp->nresults) < 1) 1796 return (fc_syntax_error(cp, "nresults must be >= 1")); 1797 1798 h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); 1799 1800 cp->nresults = fc_int2cell(1); 1801 fc_result(cp, 0) = fc_phandle2cell(h); 1802 1803 return (fc_success_op(ap, rp, cp)); 1804 } 1805 1806 static int 1807 opl_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1808 { 1809 caddr_t dropin_name_virt, fcode_virt; 1810 char *dropin_name, *fcode; 1811 int fcode_len, status; 1812 1813 if (fc_cell2int(cp->nargs) != 3) 1814 return (fc_syntax_error(cp, "nargs must be 3")); 1815 1816 if (fc_cell2int(cp->nresults) < 1) 1817 return (fc_syntax_error(cp, "nresults must be >= 1")); 1818 1819 dropin_name_virt = fc_cell2ptr(fc_arg(cp, 0)); 1820 1821 fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); 1822 1823 fcode_len = fc_cell2int(fc_arg(cp, 2)); 1824 1825 dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 1826 1827 FC_DEBUG2(1, CE_CONT, "get_fcode: %x %d\n", fcode_virt, fcode_len); 1828 1829 if (copyinstr(fc_cell2ptr(dropin_name_virt), dropin_name, 1830 FC_SVC_NAME_LEN - 1, NULL)) { 1831 FC_DEBUG1(1, CE_CONT, "opl_get_fcode: " 1832 "fault copying in drop in name %p\n", dropin_name_virt); 1833 status = 0; 1834 } else { 1835 FC_DEBUG1(1, CE_CONT, "get_fcode: %s\n", dropin_name); 1836 1837 fcode = kmem_zalloc(fcode_len, KM_SLEEP); 1838 1839 if ((status = prom_get_fcode(dropin_name, fcode)) != 0) { 1840 1841 if (copyout((void *)fcode, (void *)fcode_virt, 1842 fcode_len)) { 1843 cmn_err(CE_WARN, " opl_get_fcode: Unable " 1844 "to copy out fcode image"); 1845 status = 0; 1846 } 1847 } 1848 1849 kmem_free(fcode, fcode_len); 1850 } 1851 1852 kmem_free(dropin_name, FC_SVC_NAME_LEN); 1853 1854 cp->nresults = fc_int2cell(1); 1855 fc_result(cp, 0) = status; 1856 1857 return (fc_success_op(ap, rp, cp)); 1858 } 1859 1860 static int 1861 opl_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1862 { 1863 caddr_t virt; 1864 char *dropin_name; 1865 int len; 1866 1867 if (fc_cell2int(cp->nargs) != 1) 1868 return (fc_syntax_error(cp, "nargs must be 1")); 1869 1870 if (fc_cell2int(cp->nresults) < 1) 1871 return (fc_syntax_error(cp, "nresults must be >= 1")); 1872 1873 virt = fc_cell2ptr(fc_arg(cp, 0)); 1874 1875 dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); 1876 1877 FC_DEBUG0(1, CE_CONT, "opl_get_fcode_size:\n"); 1878 1879 if (copyinstr(fc_cell2ptr(virt), dropin_name, 1880 FC_SVC_NAME_LEN - 1, NULL)) { 1881 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: " 1882 "fault copying in drop in name %p\n", virt); 1883 len = 0; 1884 } else { 1885 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: %s\n", dropin_name); 1886 1887 len = prom_get_fcode_size(dropin_name); 1888 } 1889 1890 kmem_free(dropin_name, FC_SVC_NAME_LEN); 1891 1892 FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: fcode_len = %d\n", len); 1893 1894 cp->nresults = fc_int2cell(1); 1895 fc_result(cp, 0) = len; 1896 1897 return (fc_success_op(ap, rp, cp)); 1898 } 1899 1900 static int 1901 opl_map_phys(dev_info_t *dip, struct regspec *phys_spec, 1902 caddr_t *addrp, ddi_device_acc_attr_t *accattrp, 1903 ddi_acc_handle_t *handlep) 1904 { 1905 ddi_map_req_t mapreq; 1906 ddi_acc_hdl_t *acc_handlep; 1907 int result; 1908 struct regspec *rspecp; 1909 1910 *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); 1911 acc_handlep = impl_acc_hdl_get(*handlep); 1912 acc_handlep->ah_vers = VERS_ACCHDL; 1913 acc_handlep->ah_dip = dip; 1914 acc_handlep->ah_rnumber = 0; 1915 acc_handlep->ah_offset = 0; 1916 acc_handlep->ah_len = 0; 1917 acc_handlep->ah_acc = *accattrp; 1918 rspecp = kmem_zalloc(sizeof (struct regspec), KM_SLEEP); 1919 *rspecp = *phys_spec; 1920 /* 1921 * cache a copy of the reg spec 1922 */ 1923 acc_handlep->ah_bus_private = rspecp; 1924 1925 mapreq.map_op = DDI_MO_MAP_LOCKED; 1926 mapreq.map_type = DDI_MT_REGSPEC; 1927 mapreq.map_obj.rp = (struct regspec *)phys_spec; 1928 mapreq.map_prot = PROT_READ | PROT_WRITE; 1929 mapreq.map_flags = DDI_MF_KERNEL_MAPPING; 1930 mapreq.map_handlep = acc_handlep; 1931 mapreq.map_vers = DDI_MAP_VERSION; 1932 1933 result = ddi_map(dip, &mapreq, 0, 0, addrp); 1934 1935 if (result != DDI_SUCCESS) { 1936 impl_acc_hdl_free(*handlep); 1937 kmem_free(rspecp, sizeof (struct regspec)); 1938 *handlep = (ddi_acc_handle_t)NULL; 1939 } else { 1940 acc_handlep->ah_addr = *addrp; 1941 } 1942 1943 return (result); 1944 } 1945 1946 static void 1947 opl_unmap_phys(ddi_acc_handle_t *handlep) 1948 { 1949 ddi_map_req_t mapreq; 1950 ddi_acc_hdl_t *acc_handlep; 1951 struct regspec *rspecp; 1952 1953 acc_handlep = impl_acc_hdl_get(*handlep); 1954 ASSERT(acc_handlep); 1955 rspecp = acc_handlep->ah_bus_private; 1956 1957 mapreq.map_op = DDI_MO_UNMAP; 1958 mapreq.map_type = DDI_MT_REGSPEC; 1959 mapreq.map_obj.rp = (struct regspec *)rspecp; 1960 mapreq.map_prot = PROT_READ | PROT_WRITE; 1961 mapreq.map_flags = DDI_MF_KERNEL_MAPPING; 1962 mapreq.map_handlep = acc_handlep; 1963 mapreq.map_vers = DDI_MAP_VERSION; 1964 1965 (void) ddi_map(acc_handlep->ah_dip, &mapreq, acc_handlep->ah_offset, 1966 acc_handlep->ah_len, &acc_handlep->ah_addr); 1967 1968 impl_acc_hdl_free(*handlep); 1969 /* 1970 * Free the cached copy 1971 */ 1972 kmem_free(rspecp, sizeof (struct regspec)); 1973 *handlep = (ddi_acc_handle_t)NULL; 1974 } 1975 1976 static int 1977 opl_get_hwd_va(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 1978 { 1979 uint32_t portid; 1980 void *hwd_virt; 1981 hwd_header_t *hwd_h = NULL; 1982 hwd_sb_t *hwd_sb = NULL; 1983 int lsb, ch, leaf; 1984 int status = 1; 1985 1986 /* Check the argument */ 1987 if (fc_cell2int(cp->nargs) != 2) 1988 return (fc_syntax_error(cp, "nargs must be 2")); 1989 1990 if (fc_cell2int(cp->nresults) < 1) 1991 return (fc_syntax_error(cp, "nresults must be >= 1")); 1992 1993 /* Get the parameters */ 1994 portid = fc_cell2uint32_t(fc_arg(cp, 0)); 1995 hwd_virt = (void *)fc_cell2ptr(fc_arg(cp, 1)); 1996 1997 /* Get the ID numbers */ 1998 lsb = OPL_IO_PORTID_TO_LSB(portid); 1999 ch = OPL_PORTID_TO_CHANNEL(portid); 2000 leaf = OPL_PORTID_TO_LEAF(portid); 2001 ASSERT(OPL_IO_PORTID(lsb, ch, leaf) == portid); 2002 2003 /* Set the pointer of hwd. */ 2004 if ((hwd_h = (hwd_header_t *)opl_boards[lsb].cfg_hwd) == NULL) { 2005 return (fc_priv_error(cp, "null hwd header")); 2006 } 2007 /* Set the pointer of hwd sb. */ 2008 if ((hwd_sb = (hwd_sb_t *)((char *)hwd_h + hwd_h->hdr_sb_info_offset)) 2009 == NULL) { 2010 return (fc_priv_error(cp, "null hwd sb")); 2011 } 2012 2013 if (ch == OPL_CMU_CHANNEL) { 2014 /* Copyout CMU-CH HW Descriptor */ 2015 if (copyout((void *)&hwd_sb->sb_cmu.cmu_ch, 2016 (void *)hwd_virt, sizeof (hwd_cmu_chan_t))) { 2017 cmn_err(CE_WARN, "opl_get_hwd_va: " 2018 "Unable to copy out cmuch descriptor for %x", 2019 portid); 2020 status = 0; 2021 } 2022 } else { 2023 /* Copyout PCI-CH HW Descriptor */ 2024 if (copyout((void *)&hwd_sb->sb_pci_ch[ch].pci_leaf[leaf], 2025 (void *)hwd_virt, sizeof (hwd_leaf_t))) { 2026 cmn_err(CE_WARN, "opl_get_hwd_va: " 2027 "Unable to copy out pcich descriptor for %x", 2028 portid); 2029 status = 0; 2030 } 2031 } 2032 2033 cp->nresults = fc_int2cell(1); 2034 fc_result(cp, 0) = status; 2035 2036 return (fc_success_op(ap, rp, cp)); 2037 } 2038 2039 /* 2040 * After Solaris boots, a user can enter OBP using L1A, etc. While in OBP, 2041 * interrupts may be received from PCI devices. These interrupts 2042 * cannot be handled meaningfully since the system is in OBP. These 2043 * interrupts need to be cleared on the CPU side so that the CPU may 2044 * continue with whatever it is doing. Devices that have raised the 2045 * interrupts are expected to reraise the interrupts after sometime 2046 * as they have not been handled. At that time, Solaris will have a 2047 * chance to properly service the interrupts. 2048 * 2049 * The location of the interrupt registers depends on what is present 2050 * at a port. OPL currently supports the Oberon and the CMU channel. 2051 * The following handler handles both kinds of ports and computes 2052 * interrupt register addresses from the specifications and Jupiter Bus 2053 * device bindings. 2054 * 2055 * Fcode drivers install their interrupt handler via a "master-interrupt" 2056 * service. For boot time devices, this takes place within OBP. In the case 2057 * of DR, OPL uses IKP. The Fcode drivers that run within the efcode framework 2058 * attempt to install their handler via the "master-interrupt" service. 2059 * However, we cannot meaningfully install the Fcode driver's handler. 2060 * Instead, we install our own handler in OBP which does the same thing. 2061 * 2062 * Note that the only handling done for interrupts here is to clear it 2063 * on the CPU side. If any device in the future requires more special 2064 * handling, we would have to put in some kind of framework for adding 2065 * device-specific handlers. This is *highly* unlikely, but possible. 2066 * 2067 * Finally, OBP provides a hook called "unix-interrupt-handler" to install 2068 * a Solaris-defined master-interrupt handler for a port. The default 2069 * definition for this method does nothing. Solaris may override this 2070 * with its own definition. This is the way the following handler gets 2071 * control from OBP when interrupts happen at a port after L1A, etc. 2072 */ 2073 2074 static char define_master_interrupt_handler[] = 2075 2076 /* 2077 * This method translates an Oberon port id to the base (physical) address 2078 * of the interrupt clear registers for that port id. 2079 */ 2080 2081 ": pcich-mid>clear-int-pa ( mid -- pa ) " 2082 " dup 1 >> 7 and ( mid ch# ) " 2083 " over 4 >> h# 1f and ( mid ch# lsb# ) " 2084 " 1 d# 46 << ( mid ch# lsb# pa ) " 2085 " swap d# 40 << or ( mid ch# pa ) " 2086 " swap d# 37 << or ( mid pa ) " 2087 " swap 1 and if h# 70.0000 else h# 60.0000 then " 2088 " or h# 1400 or ( pa ) " 2089 "; " 2090 2091 /* 2092 * This method translates a CMU channel port id to the base (physical) address 2093 * of the interrupt clear registers for that port id. There are two classes of 2094 * interrupts that need to be handled for a CMU channel: 2095 * - obio interrupts 2096 * - pci interrupts 2097 * So, there are two addresses that need to be computed. 2098 */ 2099 2100 ": cmuch-mid>clear-int-pa ( mid -- obio-pa pci-pa ) " 2101 " dup 1 >> 7 and ( mid ch# ) " 2102 " over 4 >> h# 1f and ( mid ch# lsb# ) " 2103 " 1 d# 46 << ( mid ch# lsb# pa ) " 2104 " swap d# 40 << or ( mid ch# pa ) " 2105 " swap d# 37 << or ( mid pa ) " 2106 " nip dup h# 1800 + ( pa obio-pa ) " 2107 " swap h# 1400 + ( obio-pa pci-pa ) " 2108 "; " 2109 2110 /* 2111 * This method checks if a given I/O port ID is valid or not. 2112 * For a given LSB, 2113 * Oberon ports range from 0 - 3 2114 * CMU ch ports range from 4 - 4 2115 * 2116 * Also, the Oberon supports leaves 0 and 1. 2117 * The CMU ch supports only one leaf, leaf 0. 2118 */ 2119 2120 ": valid-io-mid? ( mid -- flag ) " 2121 " dup 1 >> 7 and ( mid ch# ) " 2122 " dup 4 > if 2drop false exit then ( mid ch# ) " 2123 " 4 = swap 1 and 1 = and not " 2124 "; " 2125 2126 /* 2127 * This method checks if a given port id is a CMU ch. 2128 */ 2129 2130 ": cmuch? ( mid -- flag ) 1 >> 7 and 4 = ; " 2131 2132 /* 2133 * Given the base address of the array of interrupt clear registers for 2134 * a port id, this method iterates over the given interrupt number bitmap 2135 * and resets the interrupt on the CPU side for every interrupt number 2136 * in the bitmap. Note that physical addresses are used to perform the 2137 * writes, not virtual addresses. This allows the handler to work without 2138 * any involvement from Solaris. 2139 */ 2140 2141 ": clear-ints ( pa bitmap count -- ) " 2142 " 0 do ( pa bitmap ) " 2143 " dup 0= if 2drop unloop exit then " 2144 " tuck ( bitmap pa bitmap ) " 2145 " 1 and if ( bitmap pa ) " 2146 " dup i 8 * + 0 swap ( bitmap pa 0 pa' ) " 2147 " h# 15 spacex! ( bitmap pa ) " 2148 " then ( bitmap pa ) " 2149 " swap 1 >> ( pa bitmap ) " 2150 " loop " 2151 "; " 2152 2153 /* 2154 * This method replaces the master-interrupt handler in OBP. Once 2155 * this method is plumbed into OBP, OBP transfers control to this 2156 * handler while returning to Solaris from OBP after L1A. This method's 2157 * task is to simply reset received interrupts on the CPU side. 2158 * When the devices reassert the interrupts later, Solaris will 2159 * be able to see them and handle them. 2160 * 2161 * For each port ID that has interrupts, this method is called 2162 * once by OBP. The input arguments are: 2163 * mid portid 2164 * bitmap bitmap of interrupts that have happened 2165 * 2166 * This method returns true, if it is able to handle the interrupts. 2167 * OBP does nothing further. 2168 * 2169 * This method returns false, if it encountered a problem. Currently, 2170 * the only problem could be an invalid port id. OBP needs to do 2171 * its own processing in that case. If this method returns false, 2172 * it preserves the mid and bitmap arguments for OBP. 2173 */ 2174 2175 ": unix-resend-mondos ( mid bitmap -- [ mid bitmap false ] | true ) " 2176 2177 /* 2178 * Uncomment the following line if you want to display the input arguments. 2179 * This is meant for debugging. 2180 * " .\" Bitmap=\" dup u. .\" MID=\" over u. cr " 2181 */ 2182 2183 /* 2184 * If the port id is not valid (according to the Oberon and CMU ch 2185 * specifications, then return false to OBP to continue further 2186 * processing. 2187 */ 2188 2189 " over valid-io-mid? not if ( mid bitmap ) " 2190 " false exit " 2191 " then " 2192 2193 /* 2194 * If the port is a CMU ch, then the 64-bit bitmap represents 2195 * 2 32-bit bitmaps: 2196 * - obio interrupt bitmap (20 bits) 2197 * - pci interrupt bitmap (32 bits) 2198 * 2199 * - Split the bitmap into two 2200 * - Compute the base addresses of the interrupt clear registers 2201 * for both pci interrupts and obio interrupts 2202 * - Clear obio interrupts 2203 * - Clear pci interrupts 2204 */ 2205 2206 " over cmuch? if ( mid bitmap ) " 2207 " xlsplit ( mid pci-bit obio-bit ) " 2208 " rot cmuch-mid>clear-int-pa ( pci-bit obio-bit obio-pa pci-pa ) " 2209 " >r ( pci-bit obio-bit obio-pa ) ( r: pci-pa ) " 2210 " swap d# 20 clear-ints ( pci-bit ) ( r: pci-pa ) " 2211 " r> swap d# 32 clear-ints ( ) ( r: ) " 2212 2213 /* 2214 * If the port is an Oberon, then the 64-bit bitmap is used fully. 2215 * 2216 * - Compute the base address of the interrupt clear registers 2217 * - Clear interrupts 2218 */ 2219 2220 " else ( mid bitmap ) " 2221 " swap pcich-mid>clear-int-pa ( bitmap pa ) " 2222 " swap d# 64 clear-ints ( ) " 2223 " then " 2224 2225 /* 2226 * Always return true from here. 2227 */ 2228 2229 " true ( true ) " 2230 "; " 2231 ; 2232 2233 static char install_master_interrupt_handler[] = 2234 "' unix-resend-mondos to unix-interrupt-handler"; 2235 static char handler[] = "unix-interrupt-handler"; 2236 static char handler_defined[] = "p\" %s\" find nip swap l! "; 2237 2238 /*ARGSUSED*/ 2239 static int 2240 master_interrupt_init(uint32_t portid, uint32_t xt) 2241 { 2242 uint_t defined; 2243 char buf[sizeof (handler) + sizeof (handler_defined)]; 2244 2245 if (master_interrupt_inited) 2246 return (1); 2247 2248 /* 2249 * Check if the defer word "unix-interrupt-handler" is defined. 2250 * This must be defined for OPL systems. So, this is only a 2251 * sanity check. 2252 */ 2253 (void) sprintf(buf, handler_defined, handler); 2254 prom_interpret(buf, (uintptr_t)&defined, 0, 0, 0, 0); 2255 if (!defined) { 2256 cmn_err(CE_WARN, "master_interrupt_init: " 2257 "%s is not defined\n", handler); 2258 return (0); 2259 } 2260 2261 /* 2262 * Install the generic master-interrupt handler. Note that 2263 * this is only done one time on the first DR operation. 2264 * This is because, for OPL, one, single generic handler 2265 * handles all ports (Oberon and CMU channel) and all 2266 * interrupt sources within each port. 2267 * 2268 * The current support is only for the Oberon and CMU-channel. 2269 * If any others need to be supported, the handler has to be 2270 * modified accordingly. 2271 */ 2272 2273 /* 2274 * Define the OPL master interrupt handler 2275 */ 2276 prom_interpret(define_master_interrupt_handler, 0, 0, 0, 0, 0); 2277 2278 /* 2279 * Take over the master interrupt handler from OBP. 2280 */ 2281 prom_interpret(install_master_interrupt_handler, 0, 0, 0, 0, 0); 2282 2283 master_interrupt_inited = 1; 2284 2285 /* 2286 * prom_interpret() does not return a status. So, we assume 2287 * that the calls succeeded. In reality, the calls may fail 2288 * if there is a syntax error, etc in the strings. 2289 */ 2290 2291 return (1); 2292 } 2293 2294 /* 2295 * Install the master-interrupt handler for a device. 2296 */ 2297 static int 2298 opl_master_interrupt(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) 2299 { 2300 uint32_t portid, xt; 2301 int board, channel, leaf; 2302 int status; 2303 2304 /* Check the argument */ 2305 if (fc_cell2int(cp->nargs) != 2) 2306 return (fc_syntax_error(cp, "nargs must be 2")); 2307 2308 if (fc_cell2int(cp->nresults) < 1) 2309 return (fc_syntax_error(cp, "nresults must be >= 1")); 2310 2311 /* Get the parameters */ 2312 portid = fc_cell2uint32_t(fc_arg(cp, 0)); 2313 xt = fc_cell2uint32_t(fc_arg(cp, 1)); 2314 2315 board = OPL_IO_PORTID_TO_LSB(portid); 2316 channel = OPL_PORTID_TO_CHANNEL(portid); 2317 leaf = OPL_PORTID_TO_LEAF(portid); 2318 2319 if ((board >= HWD_SBS_PER_DOMAIN) || !OPL_VALID_CHANNEL(channel) || 2320 (OPL_OBERON_CHANNEL(channel) && !OPL_VALID_LEAF(leaf)) || 2321 ((channel == OPL_CMU_CHANNEL) && (leaf != 0))) { 2322 FC_DEBUG1(1, CE_CONT, "opl_master_interrupt: invalid port %x\n", 2323 portid); 2324 status = 0; 2325 } else { 2326 status = master_interrupt_init(portid, xt); 2327 } 2328 2329 cp->nresults = fc_int2cell(1); 2330 fc_result(cp, 0) = status; 2331 2332 return (fc_success_op(ap, rp, cp)); 2333 } 2334 2335 /* 2336 * Set the properties for a leaf node (Oberon leaf or CMU channel leaf). 2337 */ 2338 /*ARGSUSED*/ 2339 static int 2340 opl_create_leaf(dev_info_t *node, void *arg, uint_t flags) 2341 { 2342 int ret; 2343 2344 OPL_UPDATE_PROP(string, node, "name", OPL_PCI_LEAF_NODE); 2345 2346 OPL_UPDATE_PROP(string, node, "status", "okay"); 2347 2348 return (DDI_WALK_TERMINATE); 2349 } 2350 2351 static char * 2352 opl_get_probe_string(opl_probe_t *probe, int channel, int leaf) 2353 { 2354 char *probe_string; 2355 int portid; 2356 2357 probe_string = kmem_zalloc(PROBE_STR_SIZE, KM_SLEEP); 2358 2359 if (channel == OPL_CMU_CHANNEL) 2360 portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; 2361 else 2362 portid = probe-> 2363 pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; 2364 2365 (void) sprintf(probe_string, "%x", portid); 2366 2367 return (probe_string); 2368 } 2369 2370 static int 2371 opl_probe_leaf(opl_probe_t *probe) 2372 { 2373 int channel, leaf, portid, error, circ; 2374 int board; 2375 fco_handle_t fco_handle, *cfg_handle; 2376 dev_info_t *parent, *leaf_node; 2377 char unit_address[UNIT_ADDR_SIZE]; 2378 char *probe_string; 2379 opl_board_cfg_t *board_cfg; 2380 2381 board = probe->pr_board; 2382 channel = probe->pr_channel; 2383 leaf = probe->pr_leaf; 2384 parent = ddi_root_node(); 2385 board_cfg = &opl_boards[board]; 2386 2387 ASSERT(OPL_VALID_CHANNEL(channel)); 2388 ASSERT(OPL_VALID_LEAF(leaf)); 2389 2390 if (channel == OPL_CMU_CHANNEL) { 2391 portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; 2392 cfg_handle = &board_cfg->cfg_cmuch_handle; 2393 } else { 2394 portid = probe-> 2395 pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; 2396 cfg_handle = &board_cfg->cfg_pcich_handle[channel][leaf]; 2397 } 2398 2399 /* 2400 * Prevent any changes to leaf_node until we have bound 2401 * it to the correct driver. 2402 */ 2403 ndi_devi_enter(parent, &circ); 2404 2405 /* 2406 * Ideally, fcode would be run from the "sid_branch_create" 2407 * callback (that is the primary purpose of that callback). 2408 * However, the fcode interpreter was written with the 2409 * assumption that the "new_child" was linked into the 2410 * device tree. The callback is invoked with the devinfo node 2411 * in the DS_PROTO state. More investigation is needed before 2412 * we can invoke the interpreter from the callback. For now, 2413 * we create the "new_child" in the BOUND state, invoke the 2414 * fcode interpreter and then rebind the dip to use any 2415 * compatible properties created by fcode. 2416 */ 2417 2418 probe->pr_parent = parent; 2419 probe->pr_create = opl_create_leaf; 2420 probe->pr_hold = 1; 2421 2422 leaf_node = opl_create_node(probe); 2423 if (leaf_node == NULL) { 2424 2425 cmn_err(CE_WARN, "IKP: create leaf (%d-%d-%d) failed", 2426 probe->pr_board, probe->pr_channel, probe->pr_leaf); 2427 ndi_devi_exit(parent, circ); 2428 return (-1); 2429 } 2430 2431 /* 2432 * The platform DR interfaces created the dip in 2433 * bound state. Bring devinfo node down to linked 2434 * state and hold it there until compatible 2435 * properties are created. 2436 */ 2437 e_ddi_branch_rele(leaf_node); 2438 (void) i_ndi_unconfig_node(leaf_node, DS_LINKED, 0); 2439 ASSERT(i_ddi_node_state(leaf_node) == DS_LINKED); 2440 e_ddi_branch_hold(leaf_node); 2441 2442 mutex_enter(&DEVI(leaf_node)->devi_lock); 2443 DEVI(leaf_node)->devi_flags |= DEVI_NO_BIND; 2444 mutex_exit(&DEVI(leaf_node)->devi_lock); 2445 2446 /* 2447 * Drop the busy-hold on parent before calling 2448 * fcode_interpreter to prevent potential deadlocks 2449 */ 2450 ndi_devi_exit(parent, circ); 2451 2452 (void) sprintf(unit_address, "%x", portid); 2453 2454 /* 2455 * Get the probe string 2456 */ 2457 probe_string = opl_get_probe_string(probe, channel, leaf); 2458 2459 /* 2460 * The fcode pointer specified here is NULL and the fcode 2461 * size specified here is 0. This causes the user-level 2462 * fcode interpreter to issue a request to the fcode 2463 * driver to get the Oberon/cmu-ch fcode. 2464 */ 2465 fco_handle = opl_fc_ops_alloc_handle(parent, leaf_node, 2466 NULL, 0, unit_address, probe_string); 2467 2468 error = fcode_interpreter(parent, &opl_fc_do_op, fco_handle); 2469 2470 if (error != 0) { 2471 cmn_err(CE_WARN, "IKP: Unable to probe PCI leaf (%d-%d-%d)", 2472 probe->pr_board, probe->pr_channel, probe->pr_leaf); 2473 2474 opl_fc_ops_free_handle(fco_handle); 2475 2476 if (probe_string != NULL) 2477 kmem_free(probe_string, PROBE_STR_SIZE); 2478 2479 (void) opl_destroy_node(leaf_node); 2480 } else { 2481 *cfg_handle = fco_handle; 2482 2483 if (channel == OPL_CMU_CHANNEL) 2484 board_cfg->cfg_cmuch_probe_str = probe_string; 2485 else 2486 board_cfg->cfg_pcich_probe_str[channel][leaf] 2487 = probe_string; 2488 2489 /* 2490 * Compatible properties (if any) have been created, 2491 * so bind driver. 2492 */ 2493 ndi_devi_enter(parent, &circ); 2494 ASSERT(i_ddi_node_state(leaf_node) <= DS_LINKED); 2495 2496 mutex_enter(&DEVI(leaf_node)->devi_lock); 2497 DEVI(leaf_node)->devi_flags &= ~DEVI_NO_BIND; 2498 mutex_exit(&DEVI(leaf_node)->devi_lock); 2499 2500 ndi_devi_exit(parent, circ); 2501 2502 if (ndi_devi_bind_driver(leaf_node, 0) != DDI_SUCCESS) { 2503 cmn_err(CE_WARN, "IKP: Unable to bind PCI leaf " 2504 "(%d-%d-%d)", probe->pr_board, probe->pr_channel, 2505 probe->pr_leaf); 2506 } 2507 } 2508 2509 if ((error != 0) && (channel == OPL_CMU_CHANNEL)) 2510 return (-1); 2511 2512 return (0); 2513 } 2514 2515 static void 2516 opl_init_leaves(int myboard) 2517 { 2518 dev_info_t *parent, *node; 2519 char *name; 2520 int circ, ret; 2521 int len, portid, board, channel, leaf; 2522 opl_board_cfg_t *cfg; 2523 2524 parent = ddi_root_node(); 2525 2526 /* 2527 * Hold parent node busy to walk its child list 2528 */ 2529 ndi_devi_enter(parent, &circ); 2530 2531 for (node = ddi_get_child(parent); (node != NULL); node = 2532 ddi_get_next_sibling(node)) { 2533 2534 ret = OPL_GET_PROP(string, node, "name", &name, &len); 2535 if (ret != DDI_PROP_SUCCESS) { 2536 /* 2537 * The property does not exist for this node. 2538 */ 2539 continue; 2540 } 2541 2542 if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { 2543 2544 ret = OPL_GET_PROP(int, node, "portid", &portid, -1); 2545 if (ret == DDI_PROP_SUCCESS) { 2546 2547 ret = OPL_GET_PROP(int, node, "board#", 2548 &board, -1); 2549 if ((ret != DDI_PROP_SUCCESS) || 2550 (board != myboard)) { 2551 kmem_free(name, len); 2552 continue; 2553 } 2554 2555 cfg = &opl_boards[board]; 2556 channel = OPL_PORTID_TO_CHANNEL(portid); 2557 if (channel == OPL_CMU_CHANNEL) { 2558 2559 if (cfg->cfg_cmuch_handle != NULL) 2560 cfg->cfg_cmuch_leaf = node; 2561 2562 } else { 2563 2564 leaf = OPL_PORTID_TO_LEAF(portid); 2565 if (cfg->cfg_pcich_handle[ 2566 channel][leaf] != NULL) 2567 cfg->cfg_pcich_leaf[ 2568 channel][leaf] = node; 2569 } 2570 } 2571 } 2572 2573 kmem_free(name, len); 2574 if (ret != DDI_PROP_SUCCESS) 2575 break; 2576 } 2577 2578 ndi_devi_exit(parent, circ); 2579 } 2580 2581 /* 2582 * Create "pci" node and hierarchy for the Oberon channels and the 2583 * CMU channel. 2584 */ 2585 /*ARGSUSED*/ 2586 static int 2587 opl_probe_io(opl_probe_t *probe) 2588 { 2589 2590 int i, j; 2591 hwd_pci_ch_t *channels; 2592 2593 if (HWD_STATUS_OK(probe->pr_sb->sb_cmu.cmu_ch.chan_status)) { 2594 2595 probe->pr_channel = HWD_CMU_CHANNEL; 2596 probe->pr_channel_status = 2597 probe->pr_sb->sb_cmu.cmu_ch.chan_status; 2598 probe->pr_leaf = 0; 2599 probe->pr_leaf_status = probe->pr_channel_status; 2600 2601 if (opl_probe_leaf(probe) != 0) 2602 return (-1); 2603 } 2604 2605 channels = &probe->pr_sb->sb_pci_ch[0]; 2606 2607 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 2608 2609 if (!HWD_STATUS_OK(channels[i].pci_status)) 2610 continue; 2611 2612 probe->pr_channel = i; 2613 probe->pr_channel_status = channels[i].pci_status; 2614 2615 for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { 2616 2617 probe->pr_leaf = j; 2618 probe->pr_leaf_status = 2619 channels[i].pci_leaf[j].leaf_status; 2620 2621 if (!HWD_STATUS_OK(probe->pr_leaf_status)) 2622 continue; 2623 2624 (void) opl_probe_leaf(probe); 2625 } 2626 } 2627 opl_init_leaves(probe->pr_board); 2628 return (0); 2629 } 2630 2631 /* 2632 * Perform the probe in the following order: 2633 * 2634 * processors 2635 * memory 2636 * IO 2637 * 2638 * Each probe function returns 0 on sucess and a non-zero value on failure. 2639 * What is a failure is determined by the implementor of the probe function. 2640 * For example, while probing CPUs, any error encountered during probe 2641 * is considered a failure and causes the whole probe operation to fail. 2642 * However, for I/O, an error encountered while probing one device 2643 * should not prevent other devices from being probed. It should not cause 2644 * the whole probe operation to fail. 2645 */ 2646 int 2647 opl_probe_sb(int board, unsigned *cpu_impl) 2648 { 2649 opl_probe_t *probe; 2650 int ret; 2651 2652 if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) 2653 return (-1); 2654 2655 ASSERT(opl_cfg_inited != 0); 2656 2657 /* 2658 * If the previous probe failed and left a partially configured 2659 * board, we need to unprobe the board and start with a clean slate. 2660 */ 2661 if ((opl_boards[board].cfg_hwd != NULL) && 2662 (opl_unprobe_sb(board) != 0)) 2663 return (-1); 2664 2665 ret = 0; 2666 2667 probe = kmem_zalloc(sizeof (opl_probe_t), KM_SLEEP); 2668 probe->pr_board = board; 2669 2670 if ((opl_probe_init(probe) != 0) || 2671 2672 (opl_probe_cpu_chips(probe) != 0) || 2673 2674 (opl_probe_memory(probe) != 0) || 2675 2676 (opl_probe_io(probe) != 0)) { 2677 2678 /* 2679 * Probe failed. Perform cleanup. 2680 */ 2681 (void) opl_unprobe_sb(board); 2682 ret = -1; 2683 } 2684 2685 *cpu_impl = probe->pr_cpu_impl; 2686 2687 kmem_free(probe, sizeof (opl_probe_t)); 2688 2689 return (ret); 2690 } 2691 2692 /* 2693 * This unprobing also includes CMU-CH. 2694 */ 2695 /*ARGSUSED*/ 2696 static int 2697 opl_unprobe_io(int board) 2698 { 2699 int i, j, ret; 2700 opl_board_cfg_t *board_cfg; 2701 dev_info_t **node; 2702 fco_handle_t *hand; 2703 char **probe_str; 2704 2705 board_cfg = &opl_boards[board]; 2706 2707 for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { 2708 2709 for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { 2710 2711 node = &board_cfg->cfg_pcich_leaf[i][j]; 2712 hand = &board_cfg->cfg_pcich_handle[i][j]; 2713 probe_str = &board_cfg->cfg_pcich_probe_str[i][j]; 2714 2715 if (*node == NULL) 2716 continue; 2717 2718 if (*hand != NULL) { 2719 opl_fc_ops_free_handle(*hand); 2720 *hand = NULL; 2721 } 2722 2723 if (*probe_str != NULL) { 2724 kmem_free(*probe_str, PROBE_STR_SIZE); 2725 *probe_str = NULL; 2726 } 2727 2728 ret = opl_destroy_node(*node); 2729 if (ret != 0) { 2730 2731 cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) " 2732 "failed", board, i, j); 2733 return (-1); 2734 } 2735 2736 *node = NULL; 2737 2738 } 2739 } 2740 2741 node = &board_cfg->cfg_cmuch_leaf; 2742 hand = &board_cfg->cfg_cmuch_handle; 2743 probe_str = &board_cfg->cfg_cmuch_probe_str; 2744 2745 if (*node == NULL) 2746 return (0); 2747 2748 if (*hand != NULL) { 2749 opl_fc_ops_free_handle(*hand); 2750 *hand = NULL; 2751 } 2752 2753 if (*probe_str != NULL) { 2754 kmem_free(*probe_str, PROBE_STR_SIZE); 2755 *probe_str = NULL; 2756 } 2757 2758 if (opl_destroy_node(*node) != 0) { 2759 2760 cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) failed", board, 2761 OPL_CMU_CHANNEL, 0); 2762 return (-1); 2763 } 2764 2765 *node = NULL; 2766 2767 return (0); 2768 } 2769 2770 /* 2771 * Destroy the "pseudo-mc" node for a board. 2772 */ 2773 static int 2774 opl_unprobe_memory(int board) 2775 { 2776 opl_board_cfg_t *board_cfg; 2777 2778 board_cfg = &opl_boards[board]; 2779 2780 if (board_cfg->cfg_pseudo_mc == NULL) 2781 return (0); 2782 2783 if (opl_destroy_node(board_cfg->cfg_pseudo_mc) != 0) { 2784 2785 cmn_err(CE_WARN, "IKP: destroy pseudo-mc (%d) failed", board); 2786 return (-1); 2787 } 2788 2789 board_cfg->cfg_pseudo_mc = NULL; 2790 2791 return (0); 2792 } 2793 2794 /* 2795 * Destroy the "cmp" nodes for a board. This also destroys the "core" 2796 * and "cpu" nodes below the "cmp" nodes. 2797 */ 2798 static int 2799 opl_unprobe_processors(int board) 2800 { 2801 int i; 2802 dev_info_t **cfg_cpu_chips; 2803 2804 cfg_cpu_chips = opl_boards[board].cfg_cpu_chips; 2805 2806 for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { 2807 2808 if (cfg_cpu_chips[i] == NULL) 2809 continue; 2810 2811 if (opl_destroy_node(cfg_cpu_chips[i]) != 0) { 2812 2813 cmn_err(CE_WARN, "IKP: destroy chip (%d-%d) failed", 2814 board, i); 2815 return (-1); 2816 } 2817 2818 cfg_cpu_chips[i] = NULL; 2819 } 2820 2821 return (0); 2822 } 2823 2824 /* 2825 * Perform the unprobe in the following order: 2826 * 2827 * IO 2828 * memory 2829 * processors 2830 */ 2831 int 2832 opl_unprobe_sb(int board) 2833 { 2834 if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) 2835 return (-1); 2836 2837 ASSERT(opl_cfg_inited != 0); 2838 2839 if ((opl_unprobe_io(board) != 0) || 2840 2841 (opl_unprobe_memory(board) != 0) || 2842 2843 (opl_unprobe_processors(board) != 0)) 2844 2845 return (-1); 2846 2847 if (opl_boards[board].cfg_hwd != NULL) { 2848 #ifdef UCTEST 2849 size_t size = 0xA000; 2850 #endif 2851 /* Release the memory for the HWD */ 2852 void *hwdp = opl_boards[board].cfg_hwd; 2853 opl_boards[board].cfg_hwd = NULL; 2854 #ifdef UCTEST 2855 hwdp = (void *)((char *)hwdp - 0x1000); 2856 hat_unload(kas.a_hat, hwdp, size, HAT_UNLOAD_UNLOCK); 2857 vmem_free(heap_arena, hwdp, size); 2858 #else 2859 kmem_free(hwdp, HWD_DATA_SIZE); 2860 #endif 2861 } 2862 return (0); 2863 } 2864 2865 /* 2866 * For MAC patrol support, we need to update the PA-related properties 2867 * when there is a copy-rename event. This should be called after the 2868 * physical copy and rename has been done by DR, and before the MAC 2869 * patrol is restarted. 2870 */ 2871 int 2872 oplcfg_pa_swap(int from, int to) 2873 { 2874 dev_info_t *from_node = opl_boards[from].cfg_pseudo_mc; 2875 dev_info_t *to_node = opl_boards[to].cfg_pseudo_mc; 2876 opl_range_t *rangef, *ranget; 2877 int elems; 2878 int ret; 2879 2880 if ((OPL_GET_PROP_ARRAY(int, from_node, "sb-mem-ranges", rangef, 2881 elems) != DDI_SUCCESS) || (elems != 4)) { 2882 /* XXX -- bad news */ 2883 return (-1); 2884 } 2885 if ((OPL_GET_PROP_ARRAY(int, to_node, "sb-mem-ranges", ranget, 2886 elems) != DDI_SUCCESS) || (elems != 4)) { 2887 /* XXX -- bad news */ 2888 return (-1); 2889 } 2890 OPL_UPDATE_PROP_ARRAY(int, from_node, "sb-mem-ranges", (int *)ranget, 2891 4); 2892 OPL_UPDATE_PROP_ARRAY(int, to_node, "sb-mem-ranges", (int *)rangef, 2893 4); 2894 2895 OPL_FREE_PROP(ranget); 2896 OPL_FREE_PROP(rangef); 2897 2898 return (0); 2899 } 2900