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