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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * CPU management for serengeti DR 31 * 32 * There are three states a CPU can be in: 33 * 34 * disconnected: In reset 35 * connect,unconfigured: Idling in OBP's idle loop 36 * configured: Running Solaris 37 * 38 * State transitions: 39 * 40 * connect configure 41 * ------------> ------------> 42 * disconnected connected configured 43 * unconfigured 44 * <----------- <------------- 45 * disconnect unconfigure 46 * 47 * Firmware involvements 48 * 49 * start_cpu(SC) 50 * prom_serengeti_wakeupcpu(OBP) 51 * ------------> -------------------------> 52 * disconnected connected configured 53 * unconfigured 54 * <----------- <------------------------- 55 * prom_serengeti_cpu_off(OBP) prom_serengeti_cpu_off(OBP) 56 * stop_cpu(SC) prom_serengeti_wakeupcpu(OBP) 57 * 58 * SIR (Software Initiated Reset) is used to unconfigure a CPU. 59 * After the CPU has completed flushing the caches, it issues an 60 * sir instruction to put itself through POST. POST detects that 61 * it is an SIR, and re-enters OBP as a slave. When the operation 62 * completes successfully, the CPU will be idling in OBP. 63 */ 64 65 #include <sys/obpdefs.h> 66 #include <sys/types.h> 67 #include <sys/cmn_err.h> 68 #include <sys/cpuvar.h> 69 #include <sys/membar.h> 70 #include <sys/x_call.h> 71 #include <sys/machsystm.h> 72 #include <sys/cpu_sgnblk_defs.h> 73 #include <sys/pte.h> 74 #include <vm/hat_sfmmu.h> 75 #include <sys/promif.h> 76 #include <sys/note.h> 77 #include <sys/vmsystm.h> 78 #include <vm/seg_kmem.h> 79 80 #include <sys/sbd_ioctl.h> 81 #include <sys/sbd.h> 82 #include <sys/sbdp_priv.h> 83 #include <sys/sbdp_mem.h> 84 #include <sys/sbdp_error.h> 85 #include <sys/sgsbbc_iosram.h> 86 #include <sys/prom_plat.h> 87 #include <sys/cheetahregs.h> 88 89 uint64_t *sbdp_valp; 90 extern uint64_t va_to_pa(void *); 91 static int sbdp_cpu_ntries = 50000; 92 static int sbdp_cpu_delay = 100; 93 void sbdp_get_cpu_sram_addr(uint64_t, uint64_t); 94 static int cpusram_map(caddr_t *, pgcnt_t *); 95 static void cpusram_unmap(caddr_t *, pgcnt_t); 96 extern int prom_serengeti_wakeupcpu(pnode_t); 97 extern int prom_serengeti_cpu_off(pnode_t); 98 extern sbdp_wnode_t *sbdp_get_wnodep(int); 99 extern caddr_t sbdp_shutdown_va; 100 static int sbdp_prom_get_cpu(void *arg, int changed); 101 102 103 int 104 sbdp_disconnect_cpu(sbdp_handle_t *hp, dev_info_t *dip, processorid_t cpuid) 105 { 106 pnode_t nodeid; 107 int bd, wnode; 108 sbdp_wnode_t *wnodep; 109 sbdp_bd_t *bdp = NULL; 110 int rv = 0; 111 processorid_t cpu = cpuid; 112 processorid_t portid; 113 static fn_t f = "sbdp_disconnect_cpu"; 114 115 SBDP_DBG_FUNC("%s\n", f); 116 117 nodeid = ddi_get_nodeid(dip); 118 119 /* 120 * Get board number and node number 121 * The check for determining if nodeid is valid is done inside 122 * sbdp_get_bd_and_wnode_num. 123 */ 124 if (SBDP_INJECT_ERROR(f, 0) || 125 sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) != 0) { 126 127 rv = -1; 128 goto out; 129 } 130 131 /* 132 * Grab the lock to prevent status threads from accessing 133 * registers on the CPU when it is being put into reset. 134 */ 135 wnodep = sbdp_get_wnodep(wnode); 136 bdp = &wnodep->bds[bd]; 137 ASSERT(bdp); 138 mutex_enter(&bdp->bd_mutex); 139 140 /* 141 * Mark the CPU in reset. This should be done before calling 142 * the SC because we won't know at which stage it failed if 143 * the SC call returns failure. 144 */ 145 sbdp_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid), 1); 146 147 /* 148 * Ask OBP to mark the CPU as in POST 149 */ 150 if (SBDP_INJECT_ERROR(f, 1) || prom_serengeti_cpu_off(nodeid) != 0) { 151 152 rv = -1; 153 goto out; 154 } 155 156 /* 157 * Ask the SC to put the CPU into reset. If the first 158 * core is not present, the stop CPU interface needs 159 * to be called with the portid rather than the cpuid. 160 */ 161 portid = SG_CPUID_TO_PORTID(cpuid); 162 if (!SBDP_IS_CPU_PRESENT(bdp, SG_CPUID_TO_CPU_UNIT(portid))) { 163 cpu = portid; 164 } 165 166 if (SBDP_INJECT_ERROR(f, 2) || sbdp_stop_cpu(cpu) != 0) { 167 168 rv = -1; 169 goto out; 170 } 171 172 out: 173 if (bdp != NULL) { 174 mutex_exit(&bdp->bd_mutex); 175 } 176 177 if (rv != 0) { 178 sbdp_set_err(hp->h_err, ESGT_STOPCPU, NULL); 179 } 180 181 return (rv); 182 } 183 184 int 185 sbdp_connect_cpu(sbdp_handle_t *hp, dev_info_t *dip, processorid_t cpuid) 186 { 187 pnode_t nodeid; 188 sbd_error_t *sep; 189 int i; 190 int bd, wnode; 191 int rv = 0; 192 static fn_t f = "sbdp_connect_cpu"; 193 194 SBDP_DBG_FUNC("%s\n", f); 195 196 sep = hp->h_err; 197 198 nodeid = ddi_get_nodeid(dip); 199 200 /* 201 * The check for determining if nodeid is valid is done inside 202 * sbdp_get_bd_and_wnode_num. 203 */ 204 if (SBDP_INJECT_ERROR(f, 0) || 205 sbdp_get_bd_and_wnode_num(nodeid, &bd, &wnode) != 0) { 206 207 rv = -1; 208 goto out; 209 } 210 211 /* 212 * Ask the SC to bring the CPU out of reset. 213 * At this point, the sb_dev_present bit is not set for the CPU. 214 * From sbd point of view the CPU is not present yet. No 215 * status threads will try to read registers off the CPU. 216 * Since we are already holding sb_mutex, it is not necessary 217 * to grab the board mutex when checking and setting the 218 * cpus_in_reset bit. 219 */ 220 if (sbdp_is_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid))) { 221 222 sbdp_wnode_t *wnodep; 223 sbdp_bd_t *bdp = NULL; 224 processorid_t cpu = cpuid; 225 processorid_t portid; 226 227 wnodep = sbdp_get_wnodep(wnode); 228 bdp = &wnodep->bds[bd]; 229 ASSERT(bdp); 230 231 /* 232 * If the first core is not present, the start CPU 233 * interface needs to be called with the portid rather 234 * than the cpuid. 235 */ 236 portid = SG_CPUID_TO_PORTID(cpuid); 237 if (!SBDP_IS_CPU_PRESENT(bdp, SG_CPUID_TO_CPU_UNIT(portid))) { 238 cpu = portid; 239 } 240 241 if (SBDP_INJECT_ERROR(f, 1) || sbdp_start_cpu(cpu) != 0) { 242 243 rv = -1; 244 goto out; 245 } 246 247 if (SBDP_INJECT_ERROR(f, 2) || 248 prom_serengeti_wakeupcpu(nodeid) != 0) { 249 250 rv = -1; 251 goto out; 252 } 253 } 254 255 /* 256 * Mark the CPU out of reset. 257 */ 258 sbdp_cpu_in_reset(wnode, bd, SG_CPUID_TO_CPU_UNIT(cpuid), 0); 259 260 /* 261 * Refresh the bd info 262 * we need to wait until all cpus are out of reset 263 */ 264 for (i = 0; i < SG_MAX_CPUS_PER_BD; i++) 265 if (sbdp_is_cpu_present(wnode, bd, i) && 266 sbdp_is_cpu_in_reset(wnode, bd, i) == 1) { 267 break; 268 } 269 270 if (i == SG_MAX_CPUS_PER_BD) { 271 /* 272 * All cpus are out of reset so it is safe to 273 * update the bd info 274 */ 275 sbdp_add_new_bd_info(wnode, bd); 276 } 277 278 out: 279 if (rv != 0) 280 sbdp_set_err(sep, ESGT_WAKEUPCPU, NULL); 281 282 return (rv); 283 } 284 285 int 286 sbdp_cpu_poweron(struct cpu *cp) 287 { 288 int cpuid; 289 int ntries; 290 pnode_t nodeid; 291 extern void restart_other_cpu(int); 292 static fn_t f = "sbdp_cpu_poweron"; 293 294 SBDP_DBG_FUNC("%s\n", f); 295 296 ASSERT(MUTEX_HELD(&cpu_lock)); 297 298 ntries = sbdp_cpu_ntries; 299 cpuid = cp->cpu_id; 300 301 nodeid = cpunodes[cpuid].nodeid; 302 ASSERT(nodeid != (pnode_t)0); 303 304 /* 305 * This is a safe guard in case the CPU has taken a trap 306 * and idling in POST. 307 */ 308 if (SBDP_INJECT_ERROR(f, 0) || 309 prom_serengeti_wakeupcpu(nodeid) != 0) { 310 311 return (EBUSY); 312 } 313 314 cp->cpu_flags &= ~CPU_POWEROFF; 315 316 /* 317 * NOTE: restart_other_cpu pauses cpus during the 318 * slave cpu start. This helps to quiesce the 319 * bus traffic a bit which makes the tick sync 320 * routine in the prom more robust. 321 */ 322 SBDP_DBG_CPU("%s: COLD START for cpu (%d)\n", f, cpuid); 323 324 restart_other_cpu(cpuid); 325 326 SBDP_DBG_CPU("after restarting other cpus\n"); 327 328 /* 329 * Wait for the cpu to reach its idle thread before 330 * we zap him with a request to blow away the mappings 331 * he (might) have for the sbdp_shutdown_asm code 332 * he may have executed on unconfigure. 333 */ 334 while ((cp->cpu_thread != cp->cpu_idle_thread) && (ntries > 0)) { 335 DELAY(sbdp_cpu_delay); 336 ntries--; 337 } 338 339 SBDP_DBG_CPU("%s: waited %d out of %d loops for cpu %d\n", 340 f, sbdp_cpu_ntries - ntries, sbdp_cpu_ntries, cpuid); 341 342 return (0); 343 } 344 345 346 #define SBDP_CPU_SRAM_ADDR 0x7fff0900000ull 347 #define SBDP_CPU_SRAM_SIZE 0x20000ull 348 349 static const char cpyren_key[] = "COPYREN"; 350 351 static uint64_t bbsram_pa; 352 static uint_t bbsram_size; 353 354 typedef struct { 355 caddr_t vaddr; 356 pgcnt_t npages; 357 uint64_t *pa; 358 uint_t *size; 359 } sbdp_cpu_sram_map_t; 360 361 int 362 sbdp_cpu_poweroff(struct cpu *cp) 363 { 364 processorid_t cpuid; 365 static void sbdp_cpu_shutdown_self(void); 366 pnode_t nodeid; 367 sbdp_cpu_sram_map_t map; 368 static fn_t f = "sbdp_cpu_poweroff"; 369 370 SBDP_DBG_FUNC("%s\n", f); 371 372 ASSERT(MUTEX_HELD(&cpu_lock)); 373 374 /* 375 * Capture all CPUs (except for detaching proc) to prevent 376 * crosscalls to the detaching proc until it has cleared its 377 * bit in cpu_ready_set. 378 */ 379 cpuid = cp->cpu_id; 380 381 nodeid = cpunodes[cpuid].nodeid; 382 ASSERT(nodeid != (pnode_t)0); 383 384 *sbdp_valp = 0ull; 385 /* 386 * Do the cpu sram mapping now. This avoids problems with 387 * mutexes and high PILS 388 */ 389 if (SBDP_INJECT_ERROR(f, 0) || 390 cpusram_map(&map.vaddr, &map.npages) != DDI_SUCCESS) { 391 return (EBUSY); 392 } 393 394 map.pa = &bbsram_pa; 395 map.size = &bbsram_size; 396 397 /* 398 * Do a cross call to the cpu so it obtains the base address 399 */ 400 xc_one(cpuid, sbdp_get_cpu_sram_addr, (uint64_t)&map, 401 (uint64_t)NULL); 402 403 cpusram_unmap(&map.vaddr, map.npages); 404 405 if (SBDP_INJECT_ERROR(f, 1) || bbsram_size == 0) { 406 cmn_err(CE_WARN, "cpu%d: Key \"%s\" missing from CPU SRAM TOC", 407 cpuid, cpyren_key); 408 return (EBUSY); 409 } 410 411 if ((bbsram_pa & MMU_PAGEOFFSET) != 0) { 412 cmn_err(CE_WARN, "cpu%d: CPU SRAM key \"%s\" not page aligned, " 413 "offset = 0x%lx", cpuid, cpyren_key, 414 bbsram_pa - SBDP_CPU_SRAM_ADDR); 415 return (EBUSY); 416 } 417 418 if (bbsram_size < MMU_PAGESIZE) { 419 cmn_err(CE_WARN, "cpu%d: CPU SRAM key \"%s\" too small, " 420 "size = 0x%x", cpuid, cpyren_key, bbsram_size); 421 return (EBUSY); 422 } 423 424 /* 425 * Capture all CPUs (except for detaching proc) to prevent 426 * crosscalls to the detaching proc until it has cleared its 427 * bit in cpu_ready_set. 428 * 429 * The CPU's remain paused and the prom_mutex is known to be free. 430 * This prevents the x-trap victim from blocking when doing prom 431 * IEEE-1275 calls at a high PIL level. 432 */ 433 434 promsafe_pause_cpus(); 435 436 /* 437 * Quiesce interrupts on the target CPU. We do this by setting 438 * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to 439 * prevent it from receiving cross calls and cross traps. 440 * This prevents the processor from receiving any new soft interrupts. 441 */ 442 443 mp_cpu_quiesce(cp); 444 445 /* tell the prom the cpu is going away */ 446 if (SBDP_INJECT_ERROR(f, 2) || prom_serengeti_cpu_off(nodeid) != 0) 447 return (EBUSY); 448 449 /* 450 * An sir instruction is issued at the end of the shutdown 451 * routine to make the CPU go through POST and re-enter OBP. 452 */ 453 xt_one_unchecked(cp->cpu_id, (xcfunc_t *)idle_stop_xcall, 454 (uint64_t)sbdp_cpu_shutdown_self, 0); 455 456 *sbdp_valp = 3ull; 457 458 start_cpus(); 459 460 /* 461 * Wait until we reach the OBP idle loop or time out. 462 * prom_serengeti_wakeupcpu waits for up to 60 seconds for the 463 * CPU to reach OBP idle loop. 464 */ 465 if (SBDP_INJECT_ERROR(f, 3) || 466 prom_serengeti_wakeupcpu(nodeid) != 0) { 467 468 /* 469 * If it fails here, we still consider the unconfigure 470 * operation as successful. 471 */ 472 cmn_err(CE_WARN, "cpu%d: CPU failed to enter OBP idle loop.\n", 473 cpuid); 474 } 475 476 ASSERT(!(CPU_IN_SET(cpu_ready_set, cpuid))); 477 478 bbsram_pa = 0; 479 bbsram_size = 0; 480 481 return (0); 482 } 483 484 processorid_t 485 sbdp_get_cpuid(sbdp_handle_t *hp, dev_info_t *dip) 486 { 487 int cpuid; 488 char type[OBP_MAXPROPNAME]; 489 pnode_t nodeid; 490 sbd_error_t *sep; 491 static fn_t f = "sbdp_get_cpuid"; 492 493 SBDP_DBG_FUNC("%s\n", f); 494 495 nodeid = ddi_get_nodeid(dip); 496 if (sbdp_is_node_bad(nodeid)) 497 return (-1); 498 499 sep = hp->h_err; 500 501 if (prom_getproplen(nodeid, "device_type") < OBP_MAXPROPNAME) 502 (void) prom_getprop(nodeid, "device_type", (caddr_t)type); 503 else { 504 sbdp_set_err(sep, ESGT_NO_DEV_TYPE, NULL); 505 return (-1); 506 } 507 508 if (strcmp(type, "cpu") != 0) { 509 sbdp_set_err(sep, ESGT_NOT_CPUTYPE, NULL); 510 return (-1); 511 } 512 513 /* 514 * Check to see if property "cpuid" exists first. 515 * If not, check for "portid". 516 */ 517 if (prom_getprop(nodeid, "cpuid", (caddr_t)&cpuid) == -1) 518 if (prom_getprop(nodeid, "portid", (caddr_t)&cpuid) == -1) { 519 520 return (-1); 521 } 522 523 return ((processorid_t)cpuid & SG_CPU_ID_MASK); 524 } 525 526 int 527 sbdp_cpu_get_impl(sbdp_handle_t *hp, dev_info_t *dip) 528 { 529 int impl; 530 char type[OBP_MAXPROPNAME]; 531 pnode_t nodeid; 532 sbd_error_t *sep; 533 static fn_t f = "sbdp_cpu_get_impl"; 534 535 SBDP_DBG_FUNC("%s\n", f); 536 537 nodeid = ddi_get_nodeid(dip); 538 if (sbdp_is_node_bad(nodeid)) 539 return (-1); 540 541 sep = hp->h_err; 542 543 if (prom_getproplen(nodeid, "device_type") < OBP_MAXPROPNAME) 544 (void) prom_getprop(nodeid, "device_type", (caddr_t)type); 545 else { 546 sbdp_set_err(sep, ESGT_NO_DEV_TYPE, NULL); 547 return (-1); 548 } 549 550 if (strcmp(type, "cpu") != 0) { 551 sbdp_set_err(sep, ESGT_NOT_CPUTYPE, NULL); 552 return (-1); 553 } 554 555 /* 556 * Get the implementation# property. 557 */ 558 if (prom_getprop(nodeid, "implementation#", (caddr_t)&impl) == -1) 559 return (-1); 560 561 return (impl); 562 } 563 564 struct sbdp_prom_get_node_args { 565 pnode_t node; /* current node */ 566 processorid_t portid; /* portid we are looking for */ 567 pnode_t result_node; /* node found with the above portid */ 568 }; 569 570 pnode_t 571 sbdp_find_nearby_cpu_by_portid(pnode_t nodeid, processorid_t portid) 572 { 573 struct sbdp_prom_get_node_args arg; 574 static fn_t f = "sbdp_find_nearby_cpu_by_portid"; 575 576 SBDP_DBG_FUNC("%s\n", f); 577 578 arg.node = nodeid; 579 arg.portid = portid; 580 (void) prom_tree_access(sbdp_prom_get_cpu, &arg, NULL); 581 582 return (arg.result_node); 583 } 584 585 /*ARGSUSED*/ 586 static int 587 sbdp_prom_get_cpu(void *arg, int changed) 588 { 589 int portid; 590 pnode_t parent, cur_node; 591 struct sbdp_prom_get_node_args *argp = arg; 592 static fn_t f = "sbdp_prom_get_cpu"; 593 594 SBDP_DBG_FUNC("%s\n", f); 595 596 parent = prom_parentnode(argp->node); 597 598 for (cur_node = prom_childnode(parent); cur_node != OBP_NONODE; 599 cur_node = prom_nextnode(cur_node)) { 600 601 if (prom_getprop(cur_node, OBP_PORTID, (caddr_t)&portid) < 0) 602 continue; 603 604 if ((portid == argp->portid) && (cur_node != argp->node)) 605 break; 606 } 607 608 argp->result_node = cur_node; 609 610 return (0); 611 } 612 613 614 /* 615 * A detaching CPU is xcalled with an xtrap to sbdp_cpu_stop_self() after 616 * it has been offlined. The function of this routine is to get the cpu 617 * spinning in a safe place. The requirement is that the system will not 618 * reference anything on the detaching board (memory and i/o is detached 619 * elsewhere) and that the CPU not reference anything on any other board 620 * in the system. This isolation is required during and after the writes 621 * to the domain masks to remove the board from the domain. 622 * 623 * To accomplish this isolation the following is done: 624 * 0) Map the CPUSRAM to obtain the correct address in SRAM 625 * 1) Create a locked mapping to a location in CPU SRAM where 626 * the cpu will execute. 627 * 2) Copy the target function (sbdp_shutdown_asm) in which 628 * the cpu will execute into CPU SRAM. 629 * 3) Jump into function with CPU SRAM. 630 * Function will: 631 * 3.1) Flush its Ecache (displacement). 632 * 3.2) Flush its Dcache with HW mechanism. 633 * 3.3) Flush its Icache with HW mechanism. 634 * 3.4) Flush all valid and _unlocked_ D-TLB entries. 635 * 3.5) Flush all valid and _unlocked_ I-TLB entries. 636 * 4) Jump into a tight loop. 637 */ 638 639 static void 640 sbdp_cpu_stop_self(uint64_t pa) 641 { 642 cpu_t *cp = CPU; 643 int cpuid = cp->cpu_id; 644 tte_t tte; 645 volatile uint_t *src, *dst; 646 uint_t funclen; 647 sbdp_shutdown_t sht; 648 uint_t bbsram_pfn; 649 uint64_t bbsram_addr; 650 void (*bbsram_func)(sbdp_shutdown_t *); 651 extern void sbdp_shutdown_asm(sbdp_shutdown_t *); 652 extern void sbdp_shutdown_asm_end(void); 653 654 funclen = (uint_t)sbdp_shutdown_asm_end - (uint_t)sbdp_shutdown_asm; 655 ASSERT(funclen <= MMU_PAGESIZE); 656 ASSERT(bbsram_pa != 0); 657 ASSERT((bbsram_pa & MMU_PAGEOFFSET) == 0); 658 ASSERT(bbsram_size >= MMU_PAGESIZE); 659 660 stdphys(pa, 3); 661 bbsram_pfn = (uint_t)(bbsram_pa >> MMU_PAGESHIFT); 662 663 bbsram_addr = (uint64_t)sbdp_shutdown_va; 664 sht.estack = bbsram_addr + MMU_PAGESIZE; 665 sht.flushaddr = ecache_flushaddr; 666 667 tte.tte_inthi = TTE_VALID_INT | TTE_SZ_INT(TTE8K) | 668 TTE_PFN_INTHI(bbsram_pfn); 669 tte.tte_intlo = TTE_PFN_INTLO(bbsram_pfn) | 670 TTE_HWWR_INT | TTE_PRIV_INT | TTE_LCK_INT; 671 sfmmu_dtlb_ld_kva(sbdp_shutdown_va, &tte); /* load dtlb */ 672 sfmmu_itlb_ld_kva(sbdp_shutdown_va, &tte); /* load itlb */ 673 674 for (src = (uint_t *)sbdp_shutdown_asm, dst = (uint_t *)bbsram_addr; 675 src < (uint_t *)sbdp_shutdown_asm_end; src++, dst++) 676 *dst = *src; 677 678 bbsram_func = (void (*)())bbsram_addr; 679 sht.size = (uint32_t)cpunodes[cpuid].ecache_size << 1; 680 sht.linesize = (uint32_t)cpunodes[cpuid].ecache_linesize; 681 sht.physaddr = pa; 682 683 /* 684 * Signal to sbdp_cpu_poweroff() that we're just 685 * about done. 686 */ 687 cp->cpu_m.in_prom = 1; 688 689 stdphys(pa, 4); 690 (*bbsram_func)(&sht); 691 } 692 693 /* ARGSUSED */ 694 void 695 sbdp_get_cpu_sram_addr(uint64_t arg1, uint64_t arg2) 696 { 697 uint64_t *pap; 698 uint_t *sizep; 699 struct iosram_toc *tocp; 700 uint_t offset; 701 uint_t size; 702 sbdp_cpu_sram_map_t *map; 703 int i; 704 fn_t f = "sbdp_get_cpu_sram_addr"; 705 706 SBDP_DBG_FUNC("%s\n", f); 707 708 map = (sbdp_cpu_sram_map_t *)arg1; 709 tocp = (struct iosram_toc *)map->vaddr; 710 pap = map->pa; 711 sizep = map->size; 712 713 for (i = 0; i < tocp->iosram_tagno; i++) { 714 if (strcmp(tocp->iosram_keys[i].key, cpyren_key) == 0) 715 break; 716 } 717 if (i == tocp->iosram_tagno) { 718 *pap = 0; 719 *sizep = 0; 720 return; 721 } 722 offset = tocp->iosram_keys[i].offset; 723 size = tocp->iosram_keys[i].size; 724 725 /* 726 * The address we want is the begining of cpusram + offset 727 */ 728 *pap = SBDP_CPU_SRAM_ADDR + offset; 729 730 *sizep = size; 731 } 732 733 static int 734 cpusram_map(caddr_t *vaddrp, pgcnt_t *npp) 735 { 736 uint_t pgoffset; 737 pgcnt_t npages; 738 pfn_t pfn; 739 uint64_t base; 740 caddr_t kaddr; 741 uint_t mapping_attr; 742 743 base = (uint64_t)SBDP_CPU_SRAM_ADDR & (~MMU_PAGEOFFSET); 744 pfn = mmu_btop(base); 745 746 /* 747 * Do a quick sanity check to make sure we are in I/O space. 748 */ 749 if (pf_is_memory(pfn)) 750 return (DDI_FAILURE); 751 752 pgoffset = (ulong_t)SBDP_CPU_SRAM_ADDR & MMU_PAGEOFFSET; 753 npages = mmu_btopr(SBDP_CPU_SRAM_SIZE + pgoffset); 754 755 kaddr = vmem_alloc(heap_arena, ptob(npages), VM_NOSLEEP); 756 if (kaddr == NULL) 757 return (DDI_ME_NORESOURCES); 758 759 mapping_attr = PROT_READ; 760 /* 761 * Now map in the pages we've allocated... 762 */ 763 hat_devload(kas.a_hat, kaddr, ptob(npages), pfn, mapping_attr, 764 HAT_LOAD_LOCK); 765 766 *vaddrp = kaddr + pgoffset; 767 *npp = npages; 768 769 return (DDI_SUCCESS); 770 } 771 772 static void 773 cpusram_unmap(caddr_t *vaddrp, pgcnt_t npages) 774 { 775 uint_t pgoffset; 776 caddr_t base; 777 caddr_t addr = *vaddrp; 778 779 780 pgoffset = (ulong_t)SBDP_CPU_SRAM_ADDR & MMU_PAGEOFFSET; 781 base = addr - pgoffset; 782 hat_unload(kas.a_hat, base, ptob(npages), HAT_UNLOAD_UNLOCK); 783 vmem_free(heap_arena, base, ptob(npages)); 784 785 *vaddrp = 0; 786 } 787 788 789 static void 790 sbdp_cpu_shutdown_self(void) 791 { 792 cpu_t *cp = CPU; 793 int cpuid = cp->cpu_id; 794 extern void flush_windows(void); 795 uint64_t pa = va_to_pa((void *)sbdp_valp); 796 797 stdphys(pa, 8); 798 flush_windows(); 799 800 (void) spl8(); 801 802 stdphys(pa, 6); 803 804 ASSERT(cp->cpu_intr_actv == 0); 805 ASSERT(cp->cpu_thread == cp->cpu_idle_thread || 806 cp->cpu_thread == cp->cpu_startup_thread); 807 808 cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF; 809 810 CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid); 811 812 stdphys(pa, 7); 813 sbdp_cpu_stop_self(pa); 814 815 cmn_err(CE_PANIC, "sbdp_cpu_shutdown_self: CPU %d FAILED TO SHUTDOWN", 816 cpuid); 817 } 818 819 typedef struct { 820 int node; 821 int board; 822 int non_panther_cpus; 823 } sbdp_node_walk_t; 824 825 static int 826 sbdp_find_non_panther_cpus(dev_info_t *dip, void *node_args) 827 { 828 int impl, cpuid, portid; 829 int buflen; 830 char buf[OBP_MAXPROPNAME]; 831 sbdp_node_walk_t *args = (sbdp_node_walk_t *)node_args; 832 833 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 834 DDI_PROP_DONTPASS, OBP_DEVICETYPE, (caddr_t)buf, 835 &buflen) != DDI_PROP_SUCCESS) { 836 return (DDI_WALK_CONTINUE); 837 } 838 839 if (strcmp(buf, "cpu") != 0) { 840 return (DDI_WALK_CONTINUE); 841 } 842 843 if ((impl = ddi_getprop(DDI_DEV_T_ANY, dip, 844 DDI_PROP_DONTPASS, "implementation#", -1)) == -1) { 845 return (DDI_WALK_CONTINUE); 846 } 847 848 if ((cpuid = ddi_getprop(DDI_DEV_T_ANY, dip, 849 DDI_PROP_DONTPASS, "cpuid", -1)) == -1) { 850 return (DDI_WALK_CONTINUE); 851 } 852 853 portid = SG_CPUID_TO_PORTID(cpuid); 854 855 /* filter out nodes not on this board */ 856 if (SG_PORTID_TO_BOARD_NUM(portid) != args->board || 857 SG_PORTID_TO_NODEID(portid) != args->node) { 858 return (DDI_WALK_PRUNECHILD); 859 } 860 861 switch (impl) { 862 case CHEETAH_IMPL: 863 case CHEETAH_PLUS_IMPL: 864 case JAGUAR_IMPL: 865 args->non_panther_cpus++; 866 break; 867 case PANTHER_IMPL: 868 break; 869 default: 870 ASSERT(0); 871 args->non_panther_cpus++; 872 break; 873 } 874 875 SBDP_DBG_CPU("cpuid=0x%x, portid=0x%x, impl=0x%x, device_type=%s", 876 cpuid, portid, impl, buf); 877 878 return (DDI_WALK_CONTINUE); 879 } 880 881 int 882 sbdp_board_non_panther_cpus(int node, int board) 883 { 884 sbdp_node_walk_t arg = {0}; 885 886 arg.node = node; 887 arg.board = board; 888 889 /* 890 * Root node doesn't have to be held. 891 */ 892 ddi_walk_devs(ddi_root_node(), sbdp_find_non_panther_cpus, 893 (void *)&arg); 894 895 return (arg.non_panther_cpus); 896 } 897