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/esunddi.h> 33 #include <sys/sunndi.h> 34 #include <sys/modctl.h> 35 #include <sys/promif.h> 36 #include <sys/machparam.h> 37 #include <sys/kobj.h> 38 #include <sys/cpuvar.h> 39 #include <sys/mem_cage.h> 40 #include <sys/promif.h> 41 #include <sys/promimpl.h> 42 #include <sys/platform_module.h> 43 #include <sys/errno.h> 44 #include <sys/cpu_sgnblk_defs.h> 45 #include <sys/iosramio.h> 46 #include <sys/domaind.h> 47 #include <sys/starcat.h> 48 #include <sys/machsystm.h> 49 #include <sys/bootconf.h> 50 #include <sys/memnode.h> 51 #include <vm/vm_dep.h> 52 #include <vm/page.h> 53 #include <sys/cheetahregs.h> 54 #include <sys/plat_ecc_unum.h> 55 #include <sys/plat_ecc_dimm.h> 56 #include <sys/lgrp.h> 57 #include <sys/dr.h> 58 #include <sys/post/scat_dcd.h> 59 #include <sys/kdi_impl.h> 60 #include <sys/iosramreg.h> 61 #include <sys/iosramvar.h> 62 #include <sys/mc-us3.h> 63 64 /* Preallocation of spare tsb's for DR */ 65 int starcat_tsb_spares = STARCAT_SPARE_TSB_MAX; 66 67 /* Set the maximum number of slot0 + slot1 boards. .. for DR */ 68 int starcat_boards = STARCAT_BDSET_MAX * STARCAT_BDSET_SLOT_MAX; 69 70 /* Maximum number of cpus per board... for DR */ 71 int starcat_cpu_per_board = MAX(STARCAT_SLOT0_CPU_MAX, STARCAT_SLOT1_CPU_MAX); 72 73 /* Maximum number of mem-units per board... for DR */ 74 int starcat_mem_per_board = MAX(STARCAT_SLOT0_MEM_MAX, STARCAT_SLOT1_MEM_MAX); 75 76 /* Maximum number of io-units (buses) per board... for DR */ 77 int starcat_io_per_board = 2 * MAX(STARCAT_SLOT0_IO_MAX, STARCAT_SLOT1_IO_MAX); 78 79 /* Preferred minimum cage size (expressed in pages)... for DR */ 80 pgcnt_t starcat_startup_cage_size = 0; 81 82 /* Platform specific function to get unum information */ 83 int (*p2get_mem_unum)(int, uint64_t, char *, int, int *); 84 85 /* Memory for fcode claims. 16k times # maximum possible schizos */ 86 #define EFCODE_SIZE (STARCAT_BDSET_MAX * 4 * 0x4000) 87 int efcode_size = EFCODE_SIZE; 88 89 void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t); 90 91 /* 92 * The IOSRAM driver is loaded in load_platform_drivers() any cpu signature 93 * usage prior to that time will have not have a function to call. 94 */ 95 static int (*iosram_rdp)(uint32_t key, uint32_t off, uint32_t len, 96 caddr_t dptr) = prom_starcat_iosram_read; 97 static int (*iosram_wrp)(uint32_t key, uint32_t off, uint32_t len, 98 caddr_t dptr) = prom_starcat_iosram_write; 99 100 plat_dimm_sid_board_t domain_dimm_sids[STARCAT_BDSET_MAX]; 101 102 /* 103 * set_platform_max_ncpus should return the maximum number of CPUs that the 104 * platform supports. This function is called from check_cpus() to set the 105 * value of max_ncpus [see PSARC 1997/165 CPU Dynamic Reconfiguration]. 106 * Data elements which are allocated based upon max_ncpus are all accessed 107 * via cpu_seqid and not physical IDs. Previously, the value of max_ncpus 108 * was being set to the largest physical ID, which led to boot problems on 109 * systems with less than 1.25GB of memory. 110 */ 111 112 int 113 set_platform_max_ncpus(void) 114 { 115 int n; 116 117 /* 118 * Convert number of slot0 + slot1 boards to number of expander brds 119 * and constrain the value to an architecturally plausible range 120 */ 121 n = MAX(starcat_boards, STARCAT_BDSET_MIN * STARCAT_BDSET_SLOT_MAX); 122 n = MIN(n, STARCAT_BDSET_MAX * STARCAT_BDSET_SLOT_MAX); 123 n = (n + STARCAT_BDSET_SLOT_MAX - 1) / STARCAT_BDSET_SLOT_MAX; 124 125 /* return maximum number of cpus possible on N expander boards */ 126 return (n * STARCAT_BDSET_CPU_MAX - STARCAT_SLOT1_CPU_MAX); 127 } 128 129 int 130 set_platform_tsb_spares() 131 { 132 return (MIN(starcat_tsb_spares, MAX_UPA)); 133 } 134 135 #pragma weak mmu_init_large_pages 136 137 void 138 set_platform_defaults(void) 139 { 140 extern char *tod_module_name; 141 extern int ts_dispatch_extended; 142 extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); 143 extern int tsb_lgrp_affinity; 144 extern int segkmem_reloc; 145 extern void mmu_init_large_pages(size_t); 146 extern int ncpunode; /* number of CPUs detected by OBP */ 147 148 #ifdef DEBUG 149 ce_verbose_memory = 2; 150 ce_verbose_other = 2; 151 #endif 152 153 /* Set the CPU signature function pointer */ 154 cpu_sgn_func = cpu_sgn_update; 155 156 /* Set appropriate tod module for starcat */ 157 ASSERT(tod_module_name == NULL); 158 tod_module_name = "todstarcat"; 159 160 /* 161 * Use the alternate TS dispatch table, which is better 162 * tuned for large servers. 163 */ 164 if (ts_dispatch_extended == -1) 165 ts_dispatch_extended = 1; 166 167 /* 168 * Use lgroup-aware TSB allocations on this platform, 169 * since they are a considerable performance win. 170 */ 171 tsb_lgrp_affinity = 1; 172 173 if ((mmu_page_sizes == max_mmu_page_sizes) && 174 (mmu_ism_pagesize != DEFAULT_ISM_PAGESIZE)) { 175 if (&mmu_init_large_pages) 176 mmu_init_large_pages(mmu_ism_pagesize); 177 } 178 179 /* 180 * KPR (kernel page relocation) is supported on this platform. 181 */ 182 if (hat_kpr_enabled && kernel_cage_enable && ncpunode >= 32) { 183 segkmem_reloc = 1; 184 cmn_err(CE_NOTE, "!Kernel Page Relocation is ENABLED"); 185 } else { 186 cmn_err(CE_NOTE, "!Kernel Page Relocation is DISABLED"); 187 } 188 } 189 190 #ifdef DEBUG 191 pgcnt_t starcat_cage_size_limit; 192 #endif 193 194 void 195 set_platform_cage_params(void) 196 { 197 extern pgcnt_t total_pages; 198 extern struct memlist *phys_avail; 199 200 if (kernel_cage_enable) { 201 pgcnt_t preferred_cage_size; 202 203 preferred_cage_size = 204 MAX(starcat_startup_cage_size, total_pages / 256); 205 206 #ifdef DEBUG 207 if (starcat_cage_size_limit) 208 preferred_cage_size = starcat_cage_size_limit; 209 #endif 210 /* 211 * Note: we are assuming that post has load the 212 * whole show in to the high end of memory. Having 213 * taken this leap, we copy the whole of phys_avail 214 * the glist and arrange for the cage to grow 215 * downward (descending pfns). 216 */ 217 kcage_range_init(phys_avail, KCAGE_DOWN, preferred_cage_size); 218 } 219 220 if (kcage_on) 221 cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED"); 222 else 223 cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED"); 224 } 225 226 void 227 load_platform_modules(void) 228 { 229 if (modload("misc", "pcihp") < 0) { 230 cmn_err(CE_NOTE, "pcihp driver failed to load"); 231 } 232 } 233 234 /* 235 * Starcat does not support power control of CPUs from the OS. 236 */ 237 /*ARGSUSED*/ 238 int 239 plat_cpu_poweron(struct cpu *cp) 240 { 241 int (*starcat_cpu_poweron)(struct cpu *) = NULL; 242 243 starcat_cpu_poweron = 244 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0); 245 246 if (starcat_cpu_poweron == NULL) 247 return (ENOTSUP); 248 else 249 return ((starcat_cpu_poweron)(cp)); 250 } 251 252 /*ARGSUSED*/ 253 int 254 plat_cpu_poweroff(struct cpu *cp) 255 { 256 int (*starcat_cpu_poweroff)(struct cpu *) = NULL; 257 258 starcat_cpu_poweroff = 259 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0); 260 261 if (starcat_cpu_poweroff == NULL) 262 return (ENOTSUP); 263 else 264 return ((starcat_cpu_poweroff)(cp)); 265 } 266 267 /* 268 * The following are currently private to Starcat DR 269 */ 270 int 271 plat_max_boards() 272 { 273 return (starcat_boards); 274 } 275 276 int 277 plat_max_cpu_units_per_board() 278 { 279 return (starcat_cpu_per_board); 280 } 281 282 int 283 plat_max_mc_units_per_board() 284 { 285 return (starcat_mem_per_board); /* each CPU has a memory controller */ 286 } 287 288 int 289 plat_max_mem_units_per_board() 290 { 291 return (starcat_mem_per_board); 292 } 293 294 int 295 plat_max_io_units_per_board() 296 { 297 return (starcat_io_per_board); 298 } 299 300 int 301 plat_max_cpumem_boards(void) 302 { 303 return (STARCAT_BDSET_MAX); 304 } 305 306 int 307 plat_pfn_to_mem_node(pfn_t pfn) 308 { 309 return (pfn >> mem_node_pfn_shift); 310 } 311 312 #define STARCAT_MC_MEMBOARD_SHIFT 37 /* Boards on 128BG boundary */ 313 314 /* ARGSUSED */ 315 void 316 plat_build_mem_nodes(prom_memlist_t *list, size_t nelems) 317 { 318 size_t elem; 319 pfn_t basepfn; 320 pgcnt_t npgs; 321 322 /* 323 * Starcat mem slices are always aligned on a 128GB boundary, 324 * fixed, and limited to one slice per expander due to design 325 * of the centerplane ASICs. 326 */ 327 mem_node_pfn_shift = STARCAT_MC_MEMBOARD_SHIFT - MMU_PAGESHIFT; 328 mem_node_physalign = 0; 329 330 /* 331 * Boot install lists are arranged <addr, len>, <addr, len>, ... 332 */ 333 for (elem = 0; elem < nelems; list++, elem++) { 334 basepfn = btop(list->addr); 335 npgs = btop(list->size); 336 mem_node_add_slice(basepfn, basepfn + npgs - 1); 337 } 338 } 339 340 /* 341 * Find the CPU associated with a slice at boot-time. 342 */ 343 void 344 plat_fill_mc(pnode_t nodeid) 345 { 346 int len; 347 uint64_t mc_addr, mask; 348 uint64_t mc_decode[MAX_BANKS_PER_MC]; 349 uint32_t regs[4]; 350 int local_mc; 351 int portid; 352 int expnum; 353 int i; 354 355 /* 356 * Memory address decoding registers 357 * (see Chap 9 of SPARCV9 JSP-1 US-III implementation) 358 */ 359 const uint64_t mc_decode_addr[MAX_BANKS_PER_MC] = { 360 0x400028, 0x400010, 0x400018, 0x400020 361 }; 362 363 /* 364 * Starcat memory controller portid == global CPU id 365 */ 366 if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) || 367 (portid == -1)) 368 return; 369 370 expnum = STARCAT_CPUID_TO_EXPANDER(portid); 371 372 /* 373 * The "reg" property returns 4 32-bit values. The first two are 374 * combined to form a 64-bit address. The second two are for a 375 * 64-bit size, but we don't actually need to look at that value. 376 */ 377 len = prom_getproplen(nodeid, "reg"); 378 if (len != (sizeof (uint32_t) * 4)) { 379 prom_printf("Warning: malformed 'reg' property\n"); 380 return; 381 } 382 if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0) 383 return; 384 mc_addr = ((uint64_t)regs[0]) << 32; 385 mc_addr |= (uint64_t)regs[1]; 386 387 /* 388 * Figure out whether the memory controller we are examining 389 * belongs to this CPU/CMP or a different one. 390 */ 391 if (portid == cpunodes[CPU->cpu_id].portid) 392 local_mc = 1; 393 else 394 local_mc = 0; 395 396 for (i = 0; i < MAX_BANKS_PER_MC; i++) { 397 398 mask = mc_decode_addr[i]; 399 400 /* 401 * If the memory controller is local to this CPU, we use 402 * the special ASI to read the decode registers. 403 * Otherwise, we load the values from a magic address in 404 * I/O space. 405 */ 406 if (local_mc) 407 mc_decode[i] = lddmcdecode(mask & MC_OFFSET_MASK); 408 else 409 mc_decode[i] = lddphysio((mc_addr | mask)); 410 411 if (mc_decode[i] >> MC_VALID_SHIFT) { 412 uint64_t base = MC_BASE(mc_decode[i]) << PHYS2UM_SHIFT; 413 int sliceid = (base >> STARCAT_MC_MEMBOARD_SHIFT); 414 415 if (sliceid < max_mem_nodes) { 416 /* 417 * Establish start-of-day mappings of 418 * lgroup platform handles to memnodes. 419 * Handle == Expander Number 420 * Memnode == Fixed 128GB Slice 421 */ 422 plat_assign_lgrphand_to_mem_node(expnum, 423 sliceid); 424 } 425 } 426 } 427 } 428 429 /* 430 * Starcat support for lgroups. 431 * 432 * On Starcat, an lgroup platform handle == expander number. 433 * For split-slot configurations (e.g. slot 0 and slot 1 boards 434 * in different domains) an MCPU board has only remote memory. 435 * 436 * The centerplane logic provides fixed 128GB memory slices 437 * each of which map to a memnode. The initial mapping of 438 * memnodes to lgroup handles is determined at boot time. 439 * A DR addition of memory adds a new mapping. A DR copy-rename 440 * swaps mappings. 441 */ 442 443 /* 444 * Convert board number to expander number. 445 */ 446 #define BOARDNUM_2_EXPANDER(b) (b >> 1) 447 448 /* 449 * Return the number of boards configured with NULL LPA. 450 */ 451 static int 452 check_for_null_lpa(void) 453 { 454 gdcd_t *gdcd; 455 uint_t exp, nlpa; 456 457 /* 458 * Read GDCD from IOSRAM. 459 * If this fails indicate a NULL LPA condition. 460 */ 461 if ((gdcd = kmem_zalloc(sizeof (gdcd_t), KM_NOSLEEP)) == NULL) 462 return (EXP_COUNT+1); 463 464 if ((*iosram_rdp)(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd) || 465 (gdcd->h.dcd_magic != GDCD_MAGIC) || 466 (gdcd->h.dcd_version != DCD_VERSION)) { 467 kmem_free(gdcd, sizeof (gdcd_t)); 468 cmn_err(CE_WARN, "check_for_null_lpa: failed to access GDCD\n"); 469 return (EXP_COUNT+2); 470 } 471 472 /* 473 * Check for NULL LPAs on all slot 0 boards in domain 474 * (i.e. in all expanders marked good for this domain). 475 */ 476 nlpa = 0; 477 for (exp = 0; exp < EXP_COUNT; exp++) { 478 if (RSV_GOOD(gdcd->dcd_slot[exp][0].l1ss_rsv) && 479 (gdcd->dcd_slot[exp][0].l1ss_flags & 480 L1SSFLG_THIS_L1_NULL_PROC_LPA)) 481 nlpa++; 482 } 483 484 kmem_free(gdcd, sizeof (gdcd_t)); 485 return (nlpa); 486 } 487 488 /* 489 * Return the platform handle for the lgroup containing the given CPU 490 * 491 * For Starcat, lgroup platform handle == expander. 492 */ 493 494 extern int mpo_disabled; 495 extern lgrp_handle_t lgrp_default_handle; 496 int null_lpa_boards = -1; 497 498 lgrp_handle_t 499 plat_lgrp_cpu_to_hand(processorid_t id) 500 { 501 lgrp_handle_t plathand; 502 503 plathand = STARCAT_CPUID_TO_EXPANDER(id); 504 505 /* 506 * Return the real platform handle for the CPU until 507 * such time as we know that MPO should be disabled. 508 * At that point, we set the "mpo_disabled" flag to true, 509 * and from that point on, return the default handle. 510 * 511 * By the time we know that MPO should be disabled, the 512 * first CPU will have already been added to a leaf 513 * lgroup, but that's ok. The common lgroup code will 514 * double check that the boot CPU is in the correct place, 515 * and in the case where mpo should be disabled, will move 516 * it to the root if necessary. 517 */ 518 if (mpo_disabled) { 519 /* If MPO is disabled, return the default (UMA) handle */ 520 plathand = lgrp_default_handle; 521 } else { 522 if (null_lpa_boards > 0) { 523 /* Determine if MPO should be disabled */ 524 mpo_disabled = 1; 525 plathand = lgrp_default_handle; 526 } 527 } 528 return (plathand); 529 } 530 531 /* 532 * Platform specific lgroup initialization 533 */ 534 void 535 plat_lgrp_init(void) 536 { 537 extern uint32_t lgrp_expand_proc_thresh; 538 extern uint32_t lgrp_expand_proc_diff; 539 540 /* 541 * Set tuneables for Starcat architecture 542 * 543 * lgrp_expand_proc_thresh is the minimum load on the lgroups 544 * this process is currently running on before considering 545 * expanding threads to another lgroup. 546 * 547 * lgrp_expand_proc_diff determines how much less the remote lgroup 548 * must be loaded before expanding to it. 549 * 550 * Since remote latencies can be costly, attempt to keep 3 threads 551 * within the same lgroup before expanding to the next lgroup. 552 */ 553 lgrp_expand_proc_thresh = LGRP_LOADAVG_THREAD_MAX * 3; 554 lgrp_expand_proc_diff = LGRP_LOADAVG_THREAD_MAX; 555 } 556 557 /* 558 * Platform notification of lgroup (re)configuration changes 559 */ 560 /*ARGSUSED*/ 561 void 562 plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg) 563 { 564 update_membounds_t *umb; 565 lgrp_config_mem_rename_t lmr; 566 int sbd, tbd; 567 lgrp_handle_t hand, shand, thand; 568 int mnode, snode, tnode; 569 570 if (mpo_disabled) 571 return; 572 573 switch (evt) { 574 575 case LGRP_CONFIG_MEM_ADD: 576 /* 577 * Establish the lgroup handle to memnode translation. 578 */ 579 umb = (update_membounds_t *)arg; 580 581 hand = BOARDNUM_2_EXPANDER(umb->u_board); 582 mnode = plat_pfn_to_mem_node(umb->u_base >> MMU_PAGESHIFT); 583 plat_assign_lgrphand_to_mem_node(hand, mnode); 584 585 break; 586 587 case LGRP_CONFIG_MEM_DEL: 588 /* We don't have to do anything */ 589 590 break; 591 592 case LGRP_CONFIG_MEM_RENAME: 593 /* 594 * During a DR copy-rename operation, all of the memory 595 * on one board is moved to another board -- but the 596 * addresses/pfns and memnodes don't change. This means 597 * the memory has changed locations without changing identity. 598 * 599 * Source is where we are copying from and target is where we 600 * are copying to. After source memnode is copied to target 601 * memnode, the physical addresses of the target memnode are 602 * renamed to match what the source memnode had. Then target 603 * memnode can be removed and source memnode can take its 604 * place. 605 * 606 * To do this, swap the lgroup handle to memnode mappings for 607 * the boards, so target lgroup will have source memnode and 608 * source lgroup will have empty target memnode which is where 609 * its memory will go (if any is added to it later). 610 * 611 * Then source memnode needs to be removed from its lgroup 612 * and added to the target lgroup where the memory was living 613 * but under a different name/memnode. The memory was in the 614 * target memnode and now lives in the source memnode with 615 * different physical addresses even though it is the same 616 * memory. 617 */ 618 sbd = arg & 0xffff; 619 tbd = (arg & 0xffff0000) >> 16; 620 shand = BOARDNUM_2_EXPANDER(sbd); 621 thand = BOARDNUM_2_EXPANDER(tbd); 622 snode = plat_lgrphand_to_mem_node(shand); 623 tnode = plat_lgrphand_to_mem_node(thand); 624 625 plat_assign_lgrphand_to_mem_node(thand, snode); 626 plat_assign_lgrphand_to_mem_node(shand, tnode); 627 628 lmr.lmem_rename_from = shand; 629 lmr.lmem_rename_to = thand; 630 631 /* 632 * Remove source memnode of copy rename from its lgroup 633 * and add it to its new target lgroup 634 */ 635 lgrp_config(LGRP_CONFIG_MEM_RENAME, (uintptr_t)snode, 636 (uintptr_t)&lmr); 637 638 break; 639 640 default: 641 break; 642 } 643 } 644 645 /* 646 * Return latency between "from" and "to" lgroups 647 * 648 * This latency number can only be used for relative comparison 649 * between lgroups on the running system, cannot be used across platforms, 650 * and may not reflect the actual latency. It is platform and implementation 651 * specific, so platform gets to decide its value. It would be nice if the 652 * number was at least proportional to make comparisons more meaningful though. 653 * NOTE: The numbers below are supposed to be load latencies for uncached 654 * memory divided by 10. 655 */ 656 int 657 plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to) 658 { 659 /* 660 * Return min remote latency when there are more than two lgroups 661 * (root and child) and getting latency between two different lgroups 662 * or root is involved 663 */ 664 if (lgrp_optimizations() && (from != to || 665 from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE)) 666 return (48); 667 else 668 return (28); 669 } 670 671 /* 672 * Return platform handle for root lgroup 673 */ 674 lgrp_handle_t 675 plat_lgrp_root_hand(void) 676 { 677 if (mpo_disabled) 678 return (lgrp_default_handle); 679 680 return (LGRP_DEFAULT_HANDLE); 681 } 682 683 /* ARGSUSED */ 684 void 685 plat_freelist_process(int mnode) 686 { 687 } 688 689 void 690 load_platform_drivers(void) 691 { 692 uint_t tunnel; 693 pnode_t nodeid; 694 dev_info_t *chosen_devi; 695 char chosen_iosram[MAXNAMELEN]; 696 697 /* 698 * Get /chosen node - that's where the tunnel property is 699 */ 700 nodeid = prom_chosennode(); 701 702 /* 703 * Get the iosram property from the chosen node. 704 */ 705 if (prom_getprop(nodeid, IOSRAM_CHOSEN_PROP, (caddr_t)&tunnel) <= 0) { 706 prom_printf("Unable to get iosram property\n"); 707 cmn_err(CE_PANIC, "Unable to get iosram property\n"); 708 } 709 710 if (prom_phandle_to_path((phandle_t)tunnel, chosen_iosram, 711 sizeof (chosen_iosram)) < 0) { 712 (void) prom_printf("prom_phandle_to_path(0x%x) failed\n", 713 tunnel); 714 cmn_err(CE_PANIC, "prom_phandle_to_path(0x%x) failed\n", 715 tunnel); 716 } 717 718 /* 719 * Attach all driver instances along the iosram's device path 720 */ 721 if (i_ddi_attach_hw_nodes("iosram") != DDI_SUCCESS) { 722 cmn_err(CE_WARN, "IOSRAM failed to load\n"); 723 } 724 725 if ((chosen_devi = e_ddi_hold_devi_by_path(chosen_iosram, 0)) == NULL) { 726 (void) prom_printf("e_ddi_hold_devi_by_path(%s) failed\n", 727 chosen_iosram); 728 cmn_err(CE_PANIC, "e_ddi_hold_devi_by_path(%s) failed\n", 729 chosen_iosram); 730 } 731 ndi_rele_devi(chosen_devi); 732 733 /* 734 * iosram driver is now loaded so we need to set our read and 735 * write pointers. 736 */ 737 iosram_rdp = (int (*)(uint32_t, uint32_t, uint32_t, caddr_t)) 738 modgetsymvalue("iosram_rd", 0); 739 iosram_wrp = (int (*)(uint32_t, uint32_t, uint32_t, caddr_t)) 740 modgetsymvalue("iosram_wr", 0); 741 742 /* 743 * Need to check for null proc LPA after IOSRAM driver is loaded 744 * and before multiple lgroups created (when start_other_cpus() called) 745 */ 746 null_lpa_boards = check_for_null_lpa(); 747 748 /* load and attach the axq driver */ 749 if (i_ddi_attach_hw_nodes("axq") != DDI_SUCCESS) { 750 cmn_err(CE_WARN, "AXQ failed to load\n"); 751 } 752 753 /* load Starcat Solaris Mailbox Client driver */ 754 if (modload("misc", "scosmb") < 0) { 755 cmn_err(CE_WARN, "SCOSMB failed to load\n"); 756 } 757 758 /* load the DR driver */ 759 if (i_ddi_attach_hw_nodes("dr") != DDI_SUCCESS) { 760 cmn_err(CE_WARN, "dr failed to load"); 761 } 762 763 /* 764 * Load the mc-us3 memory driver. 765 */ 766 if (i_ddi_attach_hw_nodes("mc-us3") != DDI_SUCCESS) 767 cmn_err(CE_WARN, "mc-us3 failed to load"); 768 else 769 (void) ddi_hold_driver(ddi_name_to_major("mc-us3")); 770 771 /* Load the schizo pci bus nexus driver. */ 772 if (i_ddi_attach_hw_nodes("pcisch") != DDI_SUCCESS) 773 cmn_err(CE_WARN, "pcisch failed to load"); 774 775 plat_ecc_init(); 776 } 777 778 779 /* 780 * No platform drivers on this platform 781 */ 782 char *platform_module_list[] = { 783 (char *)0 784 }; 785 786 787 /*ARGSUSED*/ 788 void 789 plat_tod_fault(enum tod_fault_type tod_bad) 790 { 791 } 792 793 /* 794 * Update the signature(s) in the IOSRAM's domain data section. 795 */ 796 void 797 cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid) 798 { 799 sig_state_t new_sgn; 800 sig_state_t current_sgn; 801 802 /* 803 * If the substate is REBOOT, then check for panic flow 804 */ 805 if (sub_state == SIGSUBST_REBOOT) { 806 (*iosram_rdp)(DOMD_MAGIC, DOMD_DSTATE_OFFSET, 807 sizeof (sig_state_t), (caddr_t)¤t_sgn); 808 if (current_sgn.state_t.state == SIGST_EXIT) 809 sub_state = SIGSUBST_PANIC_REBOOT; 810 } 811 812 /* 813 * cpuid == -1 indicates that the operation applies to all cpus. 814 */ 815 if (cpuid < 0) { 816 sgn_update_all_cpus(sgn, state, sub_state); 817 return; 818 } 819 820 new_sgn.signature = CPU_SIG_BLD(sgn, state, sub_state); 821 (*iosram_wrp)(DOMD_MAGIC, 822 DOMD_CPUSIGS_OFFSET + cpuid * sizeof (sig_state_t), 823 sizeof (sig_state_t), (caddr_t)&new_sgn); 824 825 /* 826 * Under certain conditions we don't update the signature 827 * of the domain_state. 828 */ 829 if ((sgn == OS_SIG) && 830 ((state == SIGST_OFFLINE) || (state == SIGST_DETACHED))) 831 return; 832 (*iosram_wrp)(DOMD_MAGIC, DOMD_DSTATE_OFFSET, sizeof (sig_state_t), 833 (caddr_t)&new_sgn); 834 } 835 836 /* 837 * Update the signature(s) in the IOSRAM's domain data section for all CPUs. 838 */ 839 void 840 sgn_update_all_cpus(ushort_t sgn, uchar_t state, uchar_t sub_state) 841 { 842 sig_state_t new_sgn; 843 int i = 0; 844 845 new_sgn.signature = CPU_SIG_BLD(sgn, state, sub_state); 846 847 /* 848 * First update the domain_state signature 849 */ 850 (*iosram_wrp)(DOMD_MAGIC, DOMD_DSTATE_OFFSET, sizeof (sig_state_t), 851 (caddr_t)&new_sgn); 852 853 for (i = 0; i < NCPU; i++) { 854 if (cpu[i] != NULL && (cpu[i]->cpu_flags & 855 (CPU_EXISTS|CPU_QUIESCED))) { 856 (*iosram_wrp)(DOMD_MAGIC, 857 DOMD_CPUSIGS_OFFSET + i * sizeof (sig_state_t), 858 sizeof (sig_state_t), (caddr_t)&new_sgn); 859 } 860 } 861 } 862 863 ushort_t 864 get_cpu_sgn(int cpuid) 865 { 866 sig_state_t cpu_sgn; 867 868 (*iosram_rdp)(DOMD_MAGIC, 869 DOMD_CPUSIGS_OFFSET + cpuid * sizeof (sig_state_t), 870 sizeof (sig_state_t), (caddr_t)&cpu_sgn); 871 872 return (cpu_sgn.state_t.sig); 873 } 874 875 uchar_t 876 get_cpu_sgn_state(int cpuid) 877 { 878 sig_state_t cpu_sgn; 879 880 (*iosram_rdp)(DOMD_MAGIC, 881 DOMD_CPUSIGS_OFFSET + cpuid * sizeof (sig_state_t), 882 sizeof (sig_state_t), (caddr_t)&cpu_sgn); 883 884 return (cpu_sgn.state_t.state); 885 } 886 887 888 /* 889 * Type of argument passed into plat_get_ecache_cpu via ddi_walk_devs 890 * for matching on specific CPU node in device tree 891 */ 892 893 typedef struct { 894 char *jnum; /* output, kmem_alloc'd if successful */ 895 int cpuid; /* input, to match cpuid/portid/upa-portid */ 896 uint_t dimm; /* input, index into ecache-dimm-label */ 897 } plat_ecache_cpu_arg_t; 898 899 900 /* 901 * plat_get_ecache_cpu is called repeatedly by ddi_walk_devs with pointers 902 * to device tree nodes (dip) and to a plat_ecache_cpu_arg_t structure (arg). 903 * Returning DDI_WALK_CONTINUE tells ddi_walk_devs to keep going, returning 904 * DDI_WALK_TERMINATE ends the walk. When the node for the specific CPU 905 * being searched for is found, the walk is done. But before returning to 906 * ddi_walk_devs and plat_get_ecacheunum, we grab this CPU's ecache-dimm-label 907 * property and set the jnum member of the plat_ecache_cpu_arg_t structure to 908 * point to the label corresponding to this specific ecache DIMM. It is up 909 * to plat_get_ecacheunum to kmem_free this string. 910 */ 911 912 static int 913 plat_get_ecache_cpu(dev_info_t *dip, void *arg) 914 { 915 char *devtype; 916 plat_ecache_cpu_arg_t *cpuarg; 917 char **dimm_labels; 918 uint_t numlabels; 919 int portid; 920 921 /* 922 * Check device_type, must be "cpu" 923 */ 924 925 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 926 "device_type", &devtype) != DDI_PROP_SUCCESS) 927 return (DDI_WALK_CONTINUE); 928 929 if (strcmp(devtype, "cpu")) { 930 ddi_prop_free((void *)devtype); 931 return (DDI_WALK_CONTINUE); 932 } 933 934 ddi_prop_free((void *)devtype); 935 936 /* 937 * Check cpuid, portid, upa-portid (in that order), must 938 * match the cpuid being sought 939 */ 940 941 portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 942 DDI_PROP_DONTPASS, "cpuid", -1); 943 944 if (portid == -1) 945 portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 946 DDI_PROP_DONTPASS, "portid", -1); 947 948 if (portid == -1) 949 portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 950 DDI_PROP_DONTPASS, "upa-portid", -1); 951 952 cpuarg = (plat_ecache_cpu_arg_t *)arg; 953 954 if (portid != cpuarg->cpuid) 955 return (DDI_WALK_CONTINUE); 956 957 /* 958 * Found the right CPU, fetch ecache-dimm-label property 959 */ 960 961 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 962 "ecache-dimm-label", &dimm_labels, &numlabels) 963 != DDI_PROP_SUCCESS) { 964 #ifdef DEBUG 965 cmn_err(CE_NOTE, "cpuid=%d missing ecache-dimm-label property", 966 portid); 967 #endif /* DEBUG */ 968 return (DDI_WALK_TERMINATE); 969 } 970 971 if (cpuarg->dimm < numlabels) { 972 cpuarg->jnum = kmem_alloc(strlen(dimm_labels[cpuarg->dimm]) + 1, 973 KM_SLEEP); 974 if (cpuarg->jnum != (char *)NULL) 975 (void) strcpy(cpuarg->jnum, dimm_labels[cpuarg->dimm]); 976 #ifdef DEBUG 977 else 978 cmn_err(CE_WARN, 979 "cannot kmem_alloc for ecache dimm label"); 980 #endif /* DEBUG */ 981 } 982 983 ddi_prop_free((void *)dimm_labels); 984 return (DDI_WALK_TERMINATE); 985 } 986 987 988 /* 989 * Bit 4 of physical address indicates ecache 0 or 1 990 */ 991 992 #define ECACHE_DIMM_MASK 0x10 993 994 /* 995 * plat_get_ecacheunum is called to generate the unum for an ecache error. 996 * After some initialization, nearly all of the work is done by ddi_walk_devs 997 * and plat_get_ecache_cpu. 998 */ 999 1000 int 1001 plat_get_ecacheunum(int cpuid, unsigned long long physaddr, char *buf, 1002 int buflen, int *ustrlen) 1003 { 1004 plat_ecache_cpu_arg_t findcpu; 1005 uint_t expander, slot, proc; 1006 1007 findcpu.jnum = (char *)NULL; 1008 findcpu.cpuid = cpuid; 1009 1010 /* 1011 * Bit 4 of physaddr equal 0 maps to E0 and 1 maps to E1 1012 * except for Panther and Jaguar where it indicates the reverse 1013 */ 1014 if (IS_PANTHER(cpunodes[CPU->cpu_id].implementation) || 1015 IS_JAGUAR(cpunodes[CPU->cpu_id].implementation)) 1016 findcpu.dimm = (physaddr & ECACHE_DIMM_MASK) ? 0 : 1; 1017 else 1018 findcpu.dimm = (physaddr & ECACHE_DIMM_MASK) ? 1 : 0; 1019 1020 /* 1021 * Walk the device tree, find this specific CPU, and get the label 1022 * for this ecache, returned here in findcpu.jnum 1023 */ 1024 1025 ddi_walk_devs(ddi_root_node(), plat_get_ecache_cpu, (void *)&findcpu); 1026 1027 if (findcpu.jnum == (char *)NULL) 1028 return (-1); 1029 1030 expander = STARCAT_CPUID_TO_EXPANDER(cpuid); 1031 slot = STARCAT_CPUID_TO_BOARDSLOT(cpuid); 1032 1033 /* 1034 * STARCAT_CPUID_TO_PORTID clears the CoreID bit so that 1035 * STARCAT_CPUID_TO_AGENT will return a physical proc (0 - 3). 1036 */ 1037 proc = STARCAT_CPUID_TO_AGENT(STARCAT_CPUID_TO_PORTID(cpuid)); 1038 1039 /* 1040 * NOTE: Any modifications to the snprintf() call below will require 1041 * changing plat_log_fruid_error() as well! 1042 */ 1043 (void) snprintf(buf, buflen, "%s%u/P%u/E%u J%s", (slot ? "IO" : "SB"), 1044 expander, proc, findcpu.dimm, findcpu.jnum); 1045 1046 *ustrlen = strlen(buf); 1047 1048 kmem_free(findcpu.jnum, strlen(findcpu.jnum) + 1); 1049 1050 return (0); 1051 } 1052 1053 /*ARGSUSED*/ 1054 int 1055 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id, 1056 int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp) 1057 { 1058 int ret; 1059 1060 /* 1061 * check if it's a Memory or an Ecache error. 1062 */ 1063 if (flt_in_memory) { 1064 if (p2get_mem_unum != NULL) { 1065 return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8), 1066 buf, buflen, lenp)); 1067 } else { 1068 return (ENOTSUP); 1069 } 1070 } else if (flt_status & ECC_ECACHE) { 1071 if ((ret = plat_get_ecacheunum(flt_bus_id, 1072 P2ALIGN(flt_addr, 8), buf, buflen, lenp)) != 0) 1073 return (EIO); 1074 } else { 1075 return (ENOTSUP); 1076 } 1077 1078 return (ret); 1079 } 1080 1081 static int (*ecc_mailbox_msg_func)(plat_ecc_message_type_t, void *) = NULL; 1082 1083 /* 1084 * To keep OS mailbox handling localized, all we do is forward the call to the 1085 * scosmb module (if it is available). 1086 */ 1087 int 1088 plat_send_ecc_mailbox_msg(plat_ecc_message_type_t msg_type, void *datap) 1089 { 1090 /* 1091 * find the symbol for the mailbox sender routine in the scosmb module 1092 */ 1093 if (ecc_mailbox_msg_func == NULL) 1094 ecc_mailbox_msg_func = (int (*)(plat_ecc_message_type_t, 1095 void *))modgetsymvalue("scosmb_log_ecc_error", 0); 1096 1097 /* 1098 * If the symbol was found, call it. Otherwise, there is not much 1099 * else we can do and console messages will have to suffice. 1100 */ 1101 if (ecc_mailbox_msg_func) 1102 return ((*ecc_mailbox_msg_func)(msg_type, datap)); 1103 else 1104 return (ENODEV); 1105 } 1106 1107 int 1108 plat_make_fru_cpuid(int sb, int m, int proc) 1109 { 1110 return (MAKE_CPUID(sb, m, proc)); 1111 } 1112 1113 /* 1114 * board number for a given proc 1115 */ 1116 int 1117 plat_make_fru_boardnum(int proc) 1118 { 1119 return (STARCAT_CPUID_TO_EXPANDER(proc)); 1120 } 1121 1122 /* 1123 * This platform hook gets called from mc_add_mem_unum_label() in the mc-us3 1124 * driver giving each platform the opportunity to add platform 1125 * specific label information to the unum for ECC error logging purposes. 1126 */ 1127 void 1128 plat_add_mem_unum_label(char *unum, int mcid, int bank, int dimm) 1129 { 1130 char new_unum[UNUM_NAMLEN]; 1131 uint_t expander = STARCAT_CPUID_TO_EXPANDER(mcid); 1132 uint_t slot = STARCAT_CPUID_TO_BOARDSLOT(mcid); 1133 1134 /* 1135 * STARCAT_CPUID_TO_PORTID clears the CoreID bit so that 1136 * STARCAT_CPUID_TO_AGENT will return a physical proc (0 - 3). 1137 */ 1138 uint_t proc = STARCAT_CPUID_TO_AGENT(STARCAT_CPUID_TO_PORTID(mcid)); 1139 1140 /* 1141 * NOTE: Any modifications to the two sprintf() calls below will 1142 * require changing plat_log_fruid_error() as well! 1143 */ 1144 if (dimm == -1) 1145 (void) snprintf(new_unum, UNUM_NAMLEN, "%s%u/P%u/B%d %s", 1146 (slot ? "IO" : "SB"), expander, proc, (bank & 0x1), unum); 1147 else 1148 (void) snprintf(new_unum, UNUM_NAMLEN, "%s%u/P%u/B%d/D%d %s", 1149 (slot ? "IO" : "SB"), expander, 1150 proc, (bank & 0x1), (dimm & 0x3), unum); 1151 1152 (void) strcpy(unum, new_unum); 1153 } 1154 1155 int 1156 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp) 1157 { 1158 int expander = STARCAT_CPUID_TO_EXPANDER(cpuid); 1159 int slot = STARCAT_CPUID_TO_BOARDSLOT(cpuid); 1160 1161 if (snprintf(buf, buflen, "%s%d", (slot ? "IO" : "SB"), expander) 1162 >= buflen) { 1163 return (ENOSPC); 1164 } else { 1165 *lenp = strlen(buf); 1166 return (0); 1167 } 1168 } 1169 1170 /* 1171 * This routine is used by the data bearing mondo (DMV) initialization 1172 * routine to determine the number of hardware and software DMV interrupts 1173 * that a platform supports. 1174 */ 1175 void 1176 plat_dmv_params(uint_t *hwint, uint_t *swint) 1177 { 1178 *hwint = STARCAT_DMV_HWINT; 1179 *swint = 0; 1180 } 1181 1182 /* 1183 * If provided, this function will be called whenever the nodename is updated. 1184 * To keep OS mailbox handling localized, all we do is forward the call to the 1185 * scosmb module (if it is available). 1186 */ 1187 void 1188 plat_nodename_set(void) 1189 { 1190 void (*nodename_update_func)(uint64_t) = NULL; 1191 1192 /* 1193 * find the symbol for the nodename update routine in the scosmb module 1194 */ 1195 nodename_update_func = (void (*)(uint64_t)) 1196 modgetsymvalue("scosmb_update_nodename", 0); 1197 1198 /* 1199 * If the symbol was found, call it. Otherwise, log a note (but not to 1200 * the console). 1201 */ 1202 if (nodename_update_func != NULL) { 1203 nodename_update_func(0); 1204 } else { 1205 cmn_err(CE_NOTE, 1206 "!plat_nodename_set: scosmb_update_nodename not found\n"); 1207 } 1208 } 1209 1210 caddr_t efcode_vaddr = NULL; 1211 caddr_t efcode_paddr = NULL; 1212 /* 1213 * Preallocate enough memory for fcode claims. 1214 */ 1215 1216 caddr_t 1217 efcode_alloc(caddr_t alloc_base) 1218 { 1219 caddr_t efcode_alloc_base = (caddr_t)roundup((uintptr_t)alloc_base, 1220 MMU_PAGESIZE); 1221 caddr_t vaddr; 1222 1223 /* 1224 * allocate the physical memory schizo fcode. 1225 */ 1226 if ((vaddr = (caddr_t)BOP_ALLOC(bootops, efcode_alloc_base, 1227 efcode_size, MMU_PAGESIZE)) == NULL) 1228 cmn_err(CE_PANIC, "Cannot allocate Efcode Memory"); 1229 1230 efcode_vaddr = vaddr; 1231 1232 return (efcode_alloc_base + efcode_size); 1233 } 1234 1235 caddr_t 1236 plat_startup_memlist(caddr_t alloc_base) 1237 { 1238 caddr_t tmp_alloc_base; 1239 1240 tmp_alloc_base = efcode_alloc(alloc_base); 1241 tmp_alloc_base = (caddr_t)roundup((uintptr_t)tmp_alloc_base, 1242 ecache_alignsize); 1243 return (tmp_alloc_base); 1244 } 1245 1246 /* 1247 * This is a helper function to determine if a given 1248 * node should be considered for a dr operation according 1249 * to predefined dr names. This is accomplished using 1250 * a function defined in drmach module. The drmach module 1251 * owns the definition of dr allowable names. 1252 * Formal Parameter: The name of a device node. 1253 * Expected Return Value: -1, device node name does not map to a valid dr name. 1254 * A value greater or equal to 0, name is valid. 1255 */ 1256 int 1257 starcat_dr_name(char *name) 1258 { 1259 int (*drmach_name2type)(char *) = NULL; 1260 1261 /* Get a pointer to helper function in the dramch module. */ 1262 drmach_name2type = 1263 (int (*)(char *))kobj_getsymvalue("drmach_name2type_idx", 0); 1264 1265 if (drmach_name2type == NULL) 1266 return (-1); 1267 1268 return ((*drmach_name2type)(name)); 1269 } 1270 1271 void 1272 startup_platform(void) 1273 { 1274 } 1275 1276 /* 1277 * KDI functions - used by the in-situ kernel debugger (kmdb) to perform 1278 * platform-specific operations. These functions execute when the world is 1279 * stopped, and as such cannot make any blocking calls, hold locks, etc. 1280 * promif functions are a special case, and may be used. 1281 */ 1282 1283 static void 1284 starcat_system_claim(void) 1285 { 1286 prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0); 1287 } 1288 1289 static void 1290 starcat_system_release(void) 1291 { 1292 prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0); 1293 } 1294 1295 void 1296 plat_kdi_init(kdi_t *kdi) 1297 { 1298 kdi->pkdi_system_claim = starcat_system_claim; 1299 kdi->pkdi_system_release = starcat_system_release; 1300 } 1301 1302 /* 1303 * This function returns 1 if large pages for kernel heap are supported 1304 * and 0 otherwise. 1305 * 1306 * Currently we disable lp kmem support if kpr is going to be enabled 1307 * because in the case of large pages hat_add_callback()/hat_delete_callback() 1308 * cause network performance degradation 1309 */ 1310 int 1311 plat_lpkmem_is_supported(void) 1312 { 1313 extern int segkmem_reloc; 1314 1315 if (hat_kpr_enabled && kernel_cage_enable && 1316 (ncpunode >= 32 || segkmem_reloc == 1)) 1317 return (0); 1318 1319 return (1); 1320 } 1321