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/param.h> 29 #include <sys/systm.h> 30 #include <sys/sysmacros.h> 31 #include <sys/sunddi.h> 32 #include <sys/modctl.h> 33 #include <sys/promif.h> 34 #include <sys/machparam.h> 35 #include <sys/kobj.h> 36 #include <sys/mem_cage.h> 37 #include <sys/starfire.h> 38 39 #include <sys/platform_module.h> 40 #include <sys/errno.h> 41 #include <vm/page.h> 42 #include <vm/hat_sfmmu.h> 43 #include <sys/memnode.h> 44 #include <vm/vm_dep.h> 45 #include <sys/cpu_sgnblk_defs.h> 46 #include <sys/cpu_sgn.h> 47 #include <sys/kdi_impl.h> 48 49 extern cpu_sgnblk_t *cpu_sgnblkp[]; 50 51 /* Preallocation of spare tsb's for DR - none for now */ 52 int starfire_tsb_spares = STARFIRE_MAX_BOARDS << 1; 53 54 /* Set the maximum number of boards... for DR */ 55 int starfire_boards = STARFIRE_MAX_BOARDS; 56 57 /* Maximum number of cpus per board... for DR */ 58 int starfire_cpu_per_board = 4; 59 60 /* Maximum number of mem-units per board... for DR */ 61 int starfire_mem_per_board = 1; 62 63 /* Maximum number of io-units (buses) per board... for DR */ 64 int starfire_io_per_board = 2; 65 66 /* Preferred minimum cage size (expressed in pages)... for DR */ 67 pgcnt_t starfire_startup_cage_size = 0; 68 69 void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t); 70 71 int 72 set_platform_max_ncpus(void) 73 { 74 starfire_boards = MIN(starfire_boards, STARFIRE_MAX_BOARDS); 75 76 if (starfire_boards < 1) 77 starfire_boards = 1; 78 79 return (starfire_boards * starfire_cpu_per_board); 80 } 81 82 void 83 startup_platform(void) 84 { 85 } 86 87 int 88 set_platform_tsb_spares() 89 { 90 return (MIN(starfire_tsb_spares, MAX_UPA)); 91 } 92 93 void 94 set_platform_defaults(void) 95 { 96 extern char *tod_module_name; 97 extern int ts_dispatch_extended; 98 extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); 99 100 uint32_t revlevel; 101 char buf[20]; 102 103 #ifdef DEBUG 104 ce_verbose_memory = 2; 105 ce_verbose_other = 2; 106 #endif 107 108 /* 109 * Check to see if we have the right firmware 110 * We simply do a prom_test to see if 111 * "SUNW,UE10000-prom-version" interface exist. 112 */ 113 if (prom_test("SUNW,UE10000-prom-version") != 0) { 114 halt("Firmware upgrade is required to boot this OS!"); 115 } else { 116 /* 117 * Versions 5 to 50 and 150 or above can support this OS 118 */ 119 sprintf(buf, "cpu-prom-version swap l!"); 120 prom_interpret(buf, (uintptr_t)&revlevel, 0, 0, 0, 0); 121 if ((revlevel < 5) || ((revlevel > 50) && (revlevel < 150))) 122 halt("Firmware upgrade is required to boot this OS!"); 123 } 124 125 /* Set the CPU signature function pointer */ 126 cpu_sgn_func = cpu_sgn_update; 127 128 /* Set appropriate tod module for starfire */ 129 ASSERT(tod_module_name == NULL); 130 tod_module_name = "todstarfire"; 131 132 /* 133 * Use the alternate TS dispatch table, which is better 134 * tuned for large servers. 135 */ 136 if (ts_dispatch_extended == -1) /* use platform default */ 137 ts_dispatch_extended = 1; 138 } 139 140 #ifdef DEBUG 141 pgcnt_t starfire_cage_size_limit; 142 #endif 143 144 void 145 set_platform_cage_params(void) 146 { 147 extern pgcnt_t total_pages; 148 extern struct memlist *phys_avail; 149 150 if (kernel_cage_enable) { 151 pgcnt_t preferred_cage_size; 152 153 preferred_cage_size = 154 MAX(starfire_startup_cage_size, total_pages / 256); 155 156 #ifdef DEBUG 157 if (starfire_cage_size_limit) 158 preferred_cage_size = starfire_cage_size_limit; 159 #endif 160 /* 161 * Note: we are assuming that post has load the 162 * whole show in to the high end of memory. Having 163 * taken this leap, we copy the whole of phys_avail 164 * the glist and arrange for the cage to grow 165 * downward (descending pfns). 166 */ 167 kcage_range_init(phys_avail, KCAGE_DOWN, preferred_cage_size); 168 } 169 170 if (kcage_on) 171 cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED"); 172 else 173 cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED"); 174 } 175 176 void 177 load_platform_drivers(void) 178 { 179 /* load the NGDR driver */ 180 if (i_ddi_attach_pseudo_node("ngdr") == NULL) { 181 cmn_err(CE_WARN, "ngdr failed to load"); 182 } 183 } 184 185 /* 186 * Starfire does not support power control of CPUs from the OS. 187 */ 188 /*ARGSUSED*/ 189 int 190 plat_cpu_poweron(struct cpu *cp) 191 { 192 int (*starfire_cpu_poweron)(struct cpu *) = NULL; 193 194 starfire_cpu_poweron = 195 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0); 196 197 if (starfire_cpu_poweron == NULL) 198 return (ENOTSUP); 199 else 200 return ((starfire_cpu_poweron)(cp)); 201 } 202 203 /*ARGSUSED*/ 204 int 205 plat_cpu_poweroff(struct cpu *cp) 206 { 207 int (*starfire_cpu_poweroff)(struct cpu *) = NULL; 208 209 starfire_cpu_poweroff = 210 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0); 211 212 if (starfire_cpu_poweroff == NULL) 213 return (ENOTSUP); 214 else 215 return ((starfire_cpu_poweroff)(cp)); 216 } 217 218 void 219 plat_dmv_params(uint_t *hwint, uint_t *swint) 220 { 221 *hwint = STARFIRE_DMV_HWINT; 222 *swint = 0; 223 } 224 225 /* 226 * The following our currently private to Starfire DR 227 */ 228 int 229 plat_max_boards() 230 { 231 return (starfire_boards); 232 } 233 234 int 235 plat_max_cpu_units_per_board() 236 { 237 return (starfire_cpu_per_board); 238 } 239 240 int 241 plat_max_mem_units_per_board() 242 { 243 return (starfire_mem_per_board); 244 } 245 246 int 247 plat_max_io_units_per_board() 248 { 249 return (starfire_io_per_board); 250 } 251 252 253 /* 254 * This index is used to associate a given pfn to a place on the freelist. 255 * This results in dispersing pfn assignment over all the boards in the 256 * system. 257 * Choose the index randomly to prevent clustering pages of different 258 * colors on the same board. 259 */ 260 static uint_t random_idx(int ubound); 261 262 #define PFN_2_LBN(pfn) (((pfn) >> (STARFIRE_MC_MEMBOARD_SHIFT - PAGESHIFT)) % \ 263 STARFIRE_MAX_BOARDS) 264 265 void 266 plat_freelist_process(int mnode) 267 { 268 page_t *page, **freelist; 269 page_t *bdlist[STARFIRE_MAX_BOARDS]; 270 page_t **sortlist[STARFIRE_MAX_BOARDS]; 271 uint32_t idx, idy, size, color, max_color, lbn; 272 uint32_t bd_flags, bd_cnt, result, bds; 273 kmutex_t *pcm; 274 int mtype; 275 276 /* for each page size */ 277 for (mtype = 0; mtype < MAX_MEM_TYPES; mtype++) { 278 for (size = 0; size < mmu_page_sizes; size++) { 279 280 /* 281 * Compute the maximum # of phys colors based on 282 * page size. 283 */ 284 max_color = page_get_pagecolors(size); 285 286 /* for each color */ 287 for (color = 0; color < max_color; color++) { 288 289 bd_cnt = 0; 290 bd_flags = 0; 291 for (idx = 0; idx < STARFIRE_MAX_BOARDS; 292 idx++) { 293 bdlist[idx] = NULL; 294 sortlist[idx] = NULL; 295 } 296 297 /* find freelist */ 298 freelist = &PAGE_FREELISTS(mnode, size, 299 color, mtype); 300 301 if (*freelist == NULL) 302 continue; 303 304 /* acquire locks */ 305 pcm = PC_BIN_MUTEX(mnode, color, 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 = &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 prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0); 621 } 622 623 static void 624 starfire_system_release(void) 625 { 626 prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0); 627 } 628 629 void 630 plat_kdi_init(kdi_t *kdi) 631 { 632 kdi->pkdi_system_claim = starfire_system_claim; 633 kdi->pkdi_system_release = starfire_system_release; 634 } 635