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