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