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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 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 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(mnode, size, 298 color, mtype); 299 300 if (*freelist == NULL) 301 continue; 302 303 /* acquire locks */ 304 pcm = PC_BIN_MUTEX(mnode, color, PG_FREE_LIST); 305 mutex_enter(pcm); 306 307 /* 308 * read freelist & sort pages by logical 309 * board number 310 */ 311 /* grab pages till last one. */ 312 while (*freelist) { 313 page = *freelist; 314 result = page_trylock(page, SE_EXCL); 315 316 ASSERT(result); 317 318 /* Delete from freelist */ 319 if (size != 0) { 320 page_vpsub(freelist, page); 321 } else { 322 mach_page_sub(freelist, page); 323 } 324 325 /* detect the lbn */ 326 lbn = PFN_2_LBN(page->p_pagenum); 327 328 /* add to bdlist[lbn] */ 329 if (size != 0) { 330 page_vpadd(&bdlist[lbn], page); 331 } else { 332 mach_page_add(&bdlist[lbn], 333 page); 334 } 335 336 /* if lbn new */ 337 if ((bd_flags & (1 << lbn)) == 0) { 338 bd_flags |= (1 << lbn); 339 bd_cnt++; 340 } 341 page_unlock(page); 342 } 343 344 /* 345 * Make the sortlist so 346 * bd_cnt choices show up 347 */ 348 bds = 0; 349 for (idx = 0; idx < STARFIRE_MAX_BOARDS; 350 idx++) { 351 if (bdlist[idx]) 352 sortlist[bds++] = &bdlist[idx]; 353 } 354 355 /* 356 * Set random start. 357 */ 358 (void) random_idx(-color); 359 360 /* 361 * now rebuild the freelist by shuffling 362 * pages from bd lists 363 */ 364 while (bd_cnt) { 365 366 /* 367 * get "random" index between 0 & 368 * bd_cnt 369 */ 370 371 ASSERT(bd_cnt && 372 (bd_cnt < STARFIRE_MAX_BOARDS+1)); 373 374 idx = random_idx(bd_cnt); 375 376 page = *sortlist[idx]; 377 result = page_trylock(page, SE_EXCL); 378 379 ASSERT(result); 380 381 /* Delete from sort_list */ 382 /* & Append to freelist */ 383 /* Big pages use vp_add - 8k don't */ 384 if (size != 0) { 385 page_vpsub(sortlist[idx], page); 386 page_vpadd(freelist, page); 387 } else { 388 mach_page_sub(sortlist[idx], 389 page); 390 mach_page_add(freelist, page); 391 } 392 393 /* needed for indexing tmp lists */ 394 lbn = PFN_2_LBN(page->p_pagenum); 395 396 /* 397 * if this was the last page on this 398 * list? 399 */ 400 if (*sortlist[idx] == NULL) { 401 402 /* have to find brd list */ 403 404 /* idx is lbn? -- No! */ 405 /* sortlist, brdlist */ 406 /* have diff indexs */ 407 bd_flags &= ~(1 << lbn); 408 --bd_cnt; 409 410 /* 411 * redo the sortlist so only 412 * bd_cnt choices show up 413 */ 414 bds = 0; 415 for (idy = 0; 416 idy < STARFIRE_MAX_BOARDS; 417 idy++) { 418 if (bdlist[idy]) { 419 sortlist[bds++] 420 /* CSTYLED */ 421 = &bdlist[idy]; 422 } 423 } 424 } 425 page_unlock(page); 426 } 427 mutex_exit(pcm); 428 } 429 } 430 } 431 } 432 433 /* 434 * If ubound > 0, will return an int between 0 & ubound 435 * If ubound < 0, will set "random seed" 436 */ 437 static uint_t 438 random_idx(int ubound) 439 { 440 static int idx = 0; 441 442 if (ubound > 0) { 443 idx = (idx + 1) % ubound; 444 return (idx); 445 } 446 idx = -ubound; 447 return (0); 448 } 449 450 /* 451 * No platform drivers on this platform 452 */ 453 char *platform_module_list[] = { 454 (char *)0 455 }; 456 457 /*ARGSUSED*/ 458 void 459 plat_tod_fault(enum tod_fault_type tod_bad) 460 { 461 } 462 463 /* 464 * Update signature block and the signature ring buffer of a given cpu_id. 465 */ 466 void 467 cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid) 468 { 469 uchar_t idx; 470 cpu_sgnblk_t *cpu_sgnblkptr; 471 472 /* 473 * cpuid == -1 indicates that the operation applies to all cpus. 474 */ 475 if (cpuid < 0) { 476 sgn_update_all_cpus(sgn, state, sub_state); 477 return; 478 } 479 480 if (cpu_sgnblkp[cpuid] == NULL) 481 return; 482 483 cpu_sgnblkptr = cpu_sgnblkp[cpuid]; 484 485 /* 486 * Map new generic cpu states to older Starfire states. 487 */ 488 switch (state) { 489 case SIGST_OFFLINE: 490 state = SIGBST_OFFLINE; 491 break; 492 case SIGST_RESUME_INPROGRESS: 493 state = SIGBST_RESUME_INPROGRESS; 494 break; 495 case SIGST_QUIESCE_INPROGRESS: 496 state = SIGBST_QUIESCE_INPROGRESS; 497 break; 498 case SIGST_QUIESCED: 499 state = SIGBST_QUIESCED; 500 break; 501 case SIGST_EXIT: 502 switch (sub_state) { 503 case SIGSUBST_DEBUG: 504 state = SIGBST_RUN; 505 sub_state = EXIT_NULL; 506 break; 507 case SIGSUBST_PANIC_CONT: 508 state = SIGBST_RUN; 509 sub_state = EXIT_PANIC2; 510 break; 511 case SIGSUBST_DUMP: 512 state = SIGBST_EXIT; 513 sub_state = EXIT_PANIC2; 514 break; 515 default: 516 break; 517 } 518 break; 519 default: 520 break; 521 } 522 523 cpu_sgnblkptr->sigb_signature.state_t.sig = sgn; 524 cpu_sgnblkptr->sigb_signature.state_t.state = state; 525 cpu_sgnblkptr->sigb_signature.state_t.sub_state = sub_state; 526 527 /* Update the ring buffer */ 528 idx = cpu_sgnblkptr->sigb_ringbuf.wr_ptr; 529 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sig = sgn; 530 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.state = state; 531 cpu_sgnblkptr->sigb_ringbuf.ringbuf[idx].state_t.sub_state = sub_state; 532 cpu_sgnblkptr->sigb_ringbuf.wr_ptr += 1; 533 cpu_sgnblkptr->sigb_ringbuf.wr_ptr &= RB_IDX_MASK; 534 } 535 536 /* 537 * Update signature block and the signature ring buffer of all CPUs. 538 */ 539 void 540 sgn_update_all_cpus(ushort_t sgn, uchar_t state, uchar_t sub_state) 541 { 542 int i = 0; 543 uchar_t cpu_state; 544 uchar_t cpu_sub_state; 545 546 for (i = 0; i < NCPU; i++) { 547 cpu_sgnblk_t *sblkp; 548 549 sblkp = cpu_sgnblkp[i]; 550 cpu_sub_state = sub_state; 551 552 if ((sblkp != NULL) && (cpu[i] != NULL && (cpu[i]->cpu_flags & 553 (CPU_EXISTS|CPU_QUIESCED)))) { 554 555 if (sub_state == EXIT_REBOOT) { 556 cpu_sub_state = 557 sblkp->sigb_signature.state_t.sub_state; 558 559 if ((cpu_sub_state == EXIT_PANIC1) || 560 (cpu_sub_state == EXIT_PANIC2)) 561 cpu_sub_state = EXIT_PANIC_REBOOT; 562 else 563 cpu_sub_state = EXIT_REBOOT; 564 } 565 566 /* 567 * If we get here from an OBP sync after watchdog, 568 * we need to retain the watchdog sync state so that 569 * hostmon knows what's going on. So if we're in 570 * watchdog we don't update the state. 571 */ 572 573 cpu_state = sblkp->sigb_signature.state_t.state; 574 if (cpu_state == SIGBST_WATCHDOG_SYNC) 575 cpu_sgn_update(sgn, SIGBST_WATCHDOG_SYNC, 576 cpu_sub_state, i); 577 else if (cpu_state == SIGBST_REDMODE_SYNC) 578 cpu_sgn_update(sgn, SIGBST_REDMODE_SYNC, 579 cpu_sub_state, i); 580 else 581 cpu_sgn_update(sgn, state, cpu_sub_state, i); 582 } 583 } 584 } 585 586 int 587 cpu_sgn_exists(int cpuid) 588 { 589 return (cpu_sgnblkp[cpuid] != NULL); 590 } 591 592 ushort_t 593 get_cpu_sgn(int cpuid) 594 { 595 if (cpu_sgnblkp[cpuid] == NULL) 596 return ((ushort_t)-1); 597 598 return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.sig); 599 } 600 601 uchar_t 602 get_cpu_sgn_state(int cpuid) 603 { 604 if (cpu_sgnblkp[cpuid] == NULL) 605 return ((uchar_t)-1); 606 607 return (cpu_sgnblkp[cpuid]->sigb_signature.state_t.state); 608 } 609 610 /* 611 * KDI functions - used by the in-situ kernel debugger (kmdb) to perform 612 * platform-specific operations. These functions execute when the world is 613 * stopped, and as such cannot make any blocking calls, hold locks, etc. 614 * promif functions are a special case, and may be used. 615 */ 616 617 static void 618 starfire_system_claim(void) 619 { 620 lbolt_debug_entry(); 621 622 prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0); 623 } 624 625 static void 626 starfire_system_release(void) 627 { 628 prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0); 629 630 lbolt_debug_return(); 631 } 632 633 void 634 plat_kdi_init(kdi_t *kdi) 635 { 636 kdi->pkdi_system_claim = starfire_system_claim; 637 kdi->pkdi_system_release = starfire_system_release; 638 } 639