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 (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/sysmacros.h> 29 #include <sys/sunddi.h> 30 #include <sys/modctl.h> 31 #include <sys/promif.h> 32 #include <sys/machparam.h> 33 #include <sys/kobj.h> 34 #include <sys/mem_cage.h> 35 #include <sys/starfire.h> 36 37 #include <sys/platform_module.h> 38 #include <sys/errno.h> 39 #include <vm/page.h> 40 #include <vm/hat_sfmmu.h> 41 #include <sys/memnode.h> 42 #include <vm/vm_dep.h> 43 #include <sys/cpu_sgnblk_defs.h> 44 #include <sys/cpu_sgn.h> 45 #include <sys/kdi_impl.h> 46 #include <sys/clock_impl.h> 47 48 extern cpu_sgnblk_t *cpu_sgnblkp[]; 49 50 /* Preallocation of spare tsb's for DR - none for now */ 51 int starfire_tsb_spares = STARFIRE_MAX_BOARDS << 1; 52 53 /* Set the maximum number of boards... for DR */ 54 int starfire_boards = STARFIRE_MAX_BOARDS; 55 56 /* Maximum number of cpus per board... for DR */ 57 int starfire_cpu_per_board = 4; 58 59 /* Maximum number of mem-units per board... for DR */ 60 int starfire_mem_per_board = 1; 61 62 /* Maximum number of io-units (buses) per board... for DR */ 63 int starfire_io_per_board = 2; 64 65 /* Preferred minimum cage size (expressed in pages)... for DR */ 66 pgcnt_t starfire_startup_cage_size = 0; 67 68 void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t); 69 70 int 71 set_platform_max_ncpus(void) 72 { 73 starfire_boards = MIN(starfire_boards, STARFIRE_MAX_BOARDS); 74 75 if (starfire_boards < 1) 76 starfire_boards = 1; 77 78 return (starfire_boards * starfire_cpu_per_board); 79 } 80 81 void 82 startup_platform(void) 83 { 84 } 85 86 int 87 set_platform_tsb_spares() 88 { 89 return (MIN(starfire_tsb_spares, MAX_UPA)); 90 } 91 92 void 93 set_platform_defaults(void) 94 { 95 extern char *tod_module_name; 96 extern int ts_dispatch_extended; 97 extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); 98 99 uint32_t revlevel; 100 char buf[20]; 101 102 #ifdef DEBUG 103 ce_verbose_memory = 2; 104 ce_verbose_other = 2; 105 #endif 106 107 /* 108 * Check to see if we have the right firmware 109 * We simply do a prom_test to see if 110 * "SUNW,UE10000-prom-version" interface exist. 111 */ 112 if (prom_test("SUNW,UE10000-prom-version") != 0) { 113 halt("Firmware upgrade is required to boot this OS!"); 114 } else { 115 /* 116 * Versions 5 to 50 and 150 or above can support this OS 117 */ 118 (void) sprintf(buf, "cpu-prom-version swap l!"); 119 prom_interpret(buf, (uintptr_t)&revlevel, 0, 0, 0, 0); 120 if ((revlevel < 5) || ((revlevel > 50) && (revlevel < 150))) 121 halt("Firmware upgrade is required to boot this OS!"); 122 } 123 124 /* Set the CPU signature function pointer */ 125 cpu_sgn_func = cpu_sgn_update; 126 127 /* Set appropriate tod module for starfire */ 128 ASSERT(tod_module_name == NULL); 129 tod_module_name = "todstarfire"; 130 131 /* 132 * Use the alternate TS dispatch table, which is better 133 * tuned for large servers. 134 */ 135 if (ts_dispatch_extended == -1) /* use platform default */ 136 ts_dispatch_extended = 1; 137 } 138 139 #ifdef DEBUG 140 pgcnt_t starfire_cage_size_limit; 141 #endif 142 143 void 144 set_platform_cage_params(void) 145 { 146 extern pgcnt_t total_pages; 147 extern struct memlist *phys_avail; 148 149 if (kernel_cage_enable) { 150 pgcnt_t preferred_cage_size; 151 152 preferred_cage_size = 153 MAX(starfire_startup_cage_size, total_pages / 256); 154 155 #ifdef DEBUG 156 if (starfire_cage_size_limit) 157 preferred_cage_size = starfire_cage_size_limit; 158 #endif 159 /* 160 * Note: we are assuming that post has load the 161 * whole show in to the high end of memory. Having 162 * taken this leap, we copy the whole of phys_avail 163 * the glist and arrange for the cage to grow 164 * downward (descending pfns). 165 */ 166 kcage_range_init(phys_avail, KCAGE_DOWN, preferred_cage_size); 167 } 168 169 if (kcage_on) 170 cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED"); 171 else 172 cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED"); 173 } 174 175 void 176 load_platform_drivers(void) 177 { 178 /* load the NGDR driver */ 179 if (i_ddi_attach_pseudo_node("ngdr") == NULL) { 180 cmn_err(CE_WARN, "ngdr failed to load"); 181 } 182 } 183 184 /* 185 * Starfire does not support power control of CPUs from the OS. 186 */ 187 /*ARGSUSED*/ 188 int 189 plat_cpu_poweron(struct cpu *cp) 190 { 191 int (*starfire_cpu_poweron)(struct cpu *) = NULL; 192 193 starfire_cpu_poweron = 194 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0); 195 196 if (starfire_cpu_poweron == NULL) 197 return (ENOTSUP); 198 else 199 return ((starfire_cpu_poweron)(cp)); 200 } 201 202 /*ARGSUSED*/ 203 int 204 plat_cpu_poweroff(struct cpu *cp) 205 { 206 int (*starfire_cpu_poweroff)(struct cpu *) = NULL; 207 208 starfire_cpu_poweroff = 209 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0); 210 211 if (starfire_cpu_poweroff == NULL) 212 return (ENOTSUP); 213 else 214 return ((starfire_cpu_poweroff)(cp)); 215 } 216 217 void 218 plat_dmv_params(uint_t *hwint, uint_t *swint) 219 { 220 *hwint = STARFIRE_DMV_HWINT; 221 *swint = 0; 222 } 223 224 /* 225 * The following our currently private to Starfire DR 226 */ 227 int 228 plat_max_boards() 229 { 230 return (starfire_boards); 231 } 232 233 int 234 plat_max_cpu_units_per_board() 235 { 236 return (starfire_cpu_per_board); 237 } 238 239 int 240 plat_max_mem_units_per_board() 241 { 242 return (starfire_mem_per_board); 243 } 244 245 int 246 plat_max_io_units_per_board() 247 { 248 return (starfire_io_per_board); 249 } 250 251 252 /* 253 * This index is used to associate a given pfn to a place on the freelist. 254 * This results in dispersing pfn assignment over all the boards in the 255 * system. 256 * Choose the index randomly to prevent clustering pages of different 257 * colors on the same board. 258 */ 259 static uint_t random_idx(int ubound); 260 261 #define PFN_2_LBN(pfn) (((pfn) >> (STARFIRE_MC_MEMBOARD_SHIFT - PAGESHIFT)) % \ 262 STARFIRE_MAX_BOARDS) 263 264 void 265 plat_freelist_process(int mnode) 266 { 267 page_t *page, **freelist; 268 page_t *bdlist[STARFIRE_MAX_BOARDS]; 269 page_t **sortlist[STARFIRE_MAX_BOARDS]; 270 uint32_t idx, idy, size, color, max_color, lbn; 271 uint32_t bd_flags, bd_cnt, result, bds; 272 kmutex_t *pcm; 273 int mtype; 274 275 /* for each page size */ 276 for (mtype = 0; mtype < MAX_MEM_TYPES; mtype++) { 277 for (size = 0; size < mmu_page_sizes; size++) { 278 279 /* 280 * Compute the maximum # of phys colors based on 281 * page size. 282 */ 283 max_color = page_get_pagecolors(size); 284 285 /* for each color */ 286 for (color = 0; color < max_color; color++) { 287 288 bd_cnt = 0; 289 bd_flags = 0; 290 for (idx = 0; idx < STARFIRE_MAX_BOARDS; 291 idx++) { 292 bdlist[idx] = NULL; 293 sortlist[idx] = NULL; 294 } 295 296 /* find freelist */ 297 freelist = &PAGE_FREELISTS(PLT_USER, mnode, 298 size, color, mtype); 299 300 if (*freelist == NULL) 301 continue; 302 303 /* acquire locks */ 304 pcm = PC_BIN_MUTEX(PLT_USER, mnode, color, 305 PG_FREE_LIST); 306 mutex_enter(pcm); 307 308 /* 309 * read freelist & sort pages by logical 310 * board number 311 */ 312 /* grab pages till last one. */ 313 while (*freelist) { 314 page = *freelist; 315 result = page_trylock(page, SE_EXCL); 316 317 ASSERT(result); 318 319 /* Delete from freelist */ 320 if (size != 0) { 321 page_vpsub(freelist, page); 322 } else { 323 mach_page_sub(freelist, page); 324 } 325 326 /* detect the lbn */ 327 lbn = PFN_2_LBN(page->p_pagenum); 328 329 /* add to bdlist[lbn] */ 330 if (size != 0) { 331 page_vpadd(&bdlist[lbn], page); 332 } else { 333 mach_page_add(&bdlist[lbn], 334 page); 335 } 336 337 /* if lbn new */ 338 if ((bd_flags & (1 << lbn)) == 0) { 339 bd_flags |= (1 << lbn); 340 bd_cnt++; 341 } 342 page_unlock(page); 343 } 344 345 /* 346 * Make the sortlist so 347 * bd_cnt choices show up 348 */ 349 bds = 0; 350 for (idx = 0; idx < STARFIRE_MAX_BOARDS; 351 idx++) { 352 if (bdlist[idx]) 353 sortlist[bds++] = &bdlist[idx]; 354 } 355 356 /* 357 * Set random start. 358 */ 359 (void) random_idx(-color); 360 361 /* 362 * now rebuild the freelist by shuffling 363 * pages from bd lists 364 */ 365 while (bd_cnt) { 366 367 /* 368 * get "random" index between 0 & 369 * bd_cnt 370 */ 371 372 ASSERT(bd_cnt && 373 (bd_cnt < STARFIRE_MAX_BOARDS+1)); 374 375 idx = random_idx(bd_cnt); 376 377 page = *sortlist[idx]; 378 result = page_trylock(page, SE_EXCL); 379 380 ASSERT(result); 381 382 /* Delete from sort_list */ 383 /* & Append to freelist */ 384 /* Big pages use vp_add - 8k don't */ 385 if (size != 0) { 386 page_vpsub(sortlist[idx], page); 387 page_vpadd(freelist, page); 388 } else { 389 mach_page_sub(sortlist[idx], 390 page); 391 mach_page_add(freelist, page); 392 } 393 394 /* needed for indexing tmp lists */ 395 lbn = PFN_2_LBN(page->p_pagenum); 396 397 /* 398 * if this was the last page on this 399 * list? 400 */ 401 if (*sortlist[idx] == NULL) { 402 403 /* have to find brd list */ 404 405 /* idx is lbn? -- No! */ 406 /* sortlist, brdlist */ 407 /* have diff indexs */ 408 bd_flags &= ~(1 << lbn); 409 --bd_cnt; 410 411 /* 412 * redo the sortlist so only 413 * bd_cnt choices show up 414 */ 415 bds = 0; 416 for (idy = 0; 417 idy < STARFIRE_MAX_BOARDS; 418 idy++) { 419 if (bdlist[idy]) { 420 sortlist[bds++] 421 /* CSTYLED */ 422 = &bdlist[idy]; 423 } 424 } 425 } 426 page_unlock(page); 427 } 428 mutex_exit(pcm); 429 } 430 } 431 } 432 } 433 434 /* 435 * If ubound > 0, will return an int between 0 & ubound 436 * If ubound < 0, will set "random seed" 437 */ 438 static uint_t 439 random_idx(int ubound) 440 { 441 static int idx = 0; 442 443 if (ubound > 0) { 444 idx = (idx + 1) % ubound; 445 return (idx); 446 } 447 idx = -ubound; 448 return (0); 449 } 450 451 /* 452 * No platform drivers on this platform 453 */ 454 char *platform_module_list[] = { 455 (char *)0 456 }; 457 458 /*ARGSUSED*/ 459 void 460 plat_tod_fault(enum tod_fault_type tod_bad) 461 { 462 } 463 464 /* 465 * Update signature block and the signature ring buffer of a given cpu_id. 466 */ 467 void 468 cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid) 469 { 470 uchar_t idx; 471 cpu_sgnblk_t *cpu_sgnblkptr; 472 473 /* 474 * cpuid == -1 indicates that the operation applies to all cpus. 475 */ 476 if (cpuid < 0) { 477 sgn_update_all_cpus(sgn, state, sub_state); 478 return; 479 } 480 481 if (cpu_sgnblkp[cpuid] == NULL) 482 return; 483 484 cpu_sgnblkptr = cpu_sgnblkp[cpuid]; 485 486 /* 487 * Map new generic cpu states to older Starfire states. 488 */ 489 switch (state) { 490 case SIGST_OFFLINE: 491 state = SIGBST_OFFLINE; 492 break; 493 case SIGST_RESUME_INPROGRESS: 494 state = SIGBST_RESUME_INPROGRESS; 495 break; 496 case SIGST_QUIESCE_INPROGRESS: 497 state = SIGBST_QUIESCE_INPROGRESS; 498 break; 499 case SIGST_QUIESCED: 500 state = SIGBST_QUIESCED; 501 break; 502 case SIGST_EXIT: 503 switch (sub_state) { 504 case SIGSUBST_DEBUG: 505 state = SIGBST_RUN; 506 sub_state = EXIT_NULL; 507 break; 508 case SIGSUBST_PANIC_CONT: 509 state = SIGBST_RUN; 510 sub_state = EXIT_PANIC2; 511 break; 512 case SIGSUBST_DUMP: 513 state = SIGBST_EXIT; 514 sub_state = EXIT_PANIC2; 515 break; 516 default: 517 break; 518 } 519 break; 520 default: 521 break; 522 } 523 524 cpu_sgnblkptr->sigb_signature.state_t.sig = sgn; 525 cpu_sgnblkptr->sigb_signature.state_t.state = state; 526 cpu_sgnblkptr->sigb_signature.state_t.sub_state = sub_state; 527 528 /* Update the ring buffer */ 529 idx = cpu_sgnblkptr->sigb_ringbuf.wr_ptr; 530 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sig = sgn; 531 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.state = state; 532 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sub_state = sub_state; 533 cpu_sgnblkptr->sigb_ringbuf.wr_ptr += 1; 534 cpu_sgnblkptr->sigb_ringbuf.wr_ptr &= RB_IDX_MASK; 535 } 536 537 /* 538 * Update signature block and the signature ring buffer of all CPUs. 539 */ 540 void 541 sgn_update_all_cpus(ushort_t sgn, uchar_t state, uchar_t sub_state) 542 { 543 int i = 0; 544 uchar_t cpu_state; 545 uchar_t cpu_sub_state; 546 547 for (i = 0; i < NCPU; i++) { 548 cpu_sgnblk_t *sblkp; 549 550 sblkp = cpu_sgnblkp[i]; 551 cpu_sub_state = sub_state; 552 553 if ((sblkp != NULL) && (cpu[i] != NULL && (cpu[i]->cpu_flags & 554 (CPU_EXISTS|CPU_QUIESCED)))) { 555 556 if (sub_state == EXIT_REBOOT) { 557 cpu_sub_state = 558 sblkp->sigb_signature.state_t.sub_state; 559 560 if ((cpu_sub_state == EXIT_PANIC1) || 561 (cpu_sub_state == EXIT_PANIC2)) 562 cpu_sub_state = EXIT_PANIC_REBOOT; 563 else 564 cpu_sub_state = EXIT_REBOOT; 565 } 566 567 /* 568 * If we get here from an OBP sync after watchdog, 569 * we need to retain the watchdog sync state so that 570 * hostmon knows what's going on. So if we're in 571 * watchdog we don't update the state. 572 */ 573 574 cpu_state = sblkp->sigb_signature.state_t.state; 575 if (cpu_state == SIGBST_WATCHDOG_SYNC) 576 cpu_sgn_update(sgn, SIGBST_WATCHDOG_SYNC, 577 cpu_sub_state, i); 578 else if (cpu_state == SIGBST_REDMODE_SYNC) 579 cpu_sgn_update(sgn, SIGBST_REDMODE_SYNC, 580 cpu_sub_state, i); 581 else 582 cpu_sgn_update(sgn, state, cpu_sub_state, i); 583 } 584 } 585 } 586 587 int 588 cpu_sgn_exists(int cpuid) 589 { 590 return (cpu_sgnblkp[cpuid] != NULL); 591 } 592 593 ushort_t 594 get_cpu_sgn(int cpuid) 595 { 596 if (cpu_sgnblkp[cpuid] == NULL) 597 return ((ushort_t)-1); 598 599 return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.sig); 600 } 601 602 uchar_t 603 get_cpu_sgn_state(int cpuid) 604 { 605 if (cpu_sgnblkp[cpuid] == NULL) 606 return ((uchar_t)-1); 607 608 return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.state); 609 } 610 611 /* 612 * KDI functions - used by the in-situ kernel debugger (kmdb) to perform 613 * platform-specific operations. These functions execute when the world is 614 * stopped, and as such cannot make any blocking calls, hold locks, etc. 615 * promif functions are a special case, and may be used. 616 */ 617 618 static void 619 starfire_system_claim(void) 620 { 621 lbolt_debug_entry(); 622 623 prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0); 624 } 625 626 static void 627 starfire_system_release(void) 628 { 629 prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0); 630 631 lbolt_debug_return(); 632 } 633 634 void 635 plat_kdi_init(kdi_t *kdi) 636 { 637 kdi->pkdi_system_claim = starfire_system_claim; 638 kdi->pkdi_system_release = starfire_system_release; 639 } 640