536 hat_getkpfnum needs to be removed
[illumos-gate.git] / usr / src / uts / sun4u / starcat / os / starcat.c
blob0fdcba26b81907dcfd7ea268e62e54b2d10dd3b3
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
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>
67 /* Preallocation of spare tsb's for DR */
68 int starcat_tsb_spares = STARCAT_SPARE_TSB_MAX;
70 /* Set the maximum number of slot0 + slot1 boards. .. for DR */
71 int starcat_boards = STARCAT_BDSET_MAX * STARCAT_BDSET_SLOT_MAX;
73 /* Maximum number of cpus per board... for DR */
74 int starcat_cpu_per_board = MAX(STARCAT_SLOT0_CPU_MAX, STARCAT_SLOT1_CPU_MAX);
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);
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);
82 /* Preferred minimum cage size (expressed in pages)... for DR */
83 pgcnt_t starcat_startup_cage_size = 0;
85 /* Platform specific function to get unum information */
86 int (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
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;
92 void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t);
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.
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;
103 plat_dimm_sid_board_t domain_dimm_sids[STARCAT_BDSET_MAX];
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.
116 set_platform_max_ncpus(void)
118 int n;
121 * Convert number of slot0 + slot1 boards to number of expander brds
122 * and constrain the value to an architecturally plausible range
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;
128 /* return maximum number of cpus possible on N expander boards */
129 return (n * STARCAT_BDSET_CPU_MAX - STARCAT_SLOT1_CPU_MAX);
133 set_platform_tsb_spares()
135 return (MIN(starcat_tsb_spares, MAX_UPA));
138 #pragma weak mmu_init_large_pages
140 void
141 set_platform_defaults(void)
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 */
151 #ifdef DEBUG
152 ce_verbose_memory = 2;
153 ce_verbose_other = 2;
154 #endif
156 /* Set the CPU signature function pointer */
157 cpu_sgn_func = cpu_sgn_update;
159 /* Set appropriate tod module for starcat */
160 ASSERT(tod_module_name == NULL);
161 tod_module_name = "todstarcat";
164 * Use the alternate TS dispatch table, which is better
165 * tuned for large servers.
167 if (ts_dispatch_extended == -1)
168 ts_dispatch_extended = 1;
171 * Use lgroup-aware TSB allocations on this platform,
172 * since they are a considerable performance win.
174 tsb_lgrp_affinity = 1;
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);
183 * KPR (kernel page relocation) is supported on this platform.
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");
193 #ifdef DEBUG
194 pgcnt_t starcat_cage_size_limit;
195 #endif
197 void
198 set_platform_cage_params(void)
200 extern pgcnt_t total_pages;
201 extern struct memlist *phys_avail;
203 if (kernel_cage_enable) {
204 pgcnt_t preferred_cage_size;
206 preferred_cage_size =
207 MAX(starcat_startup_cage_size, total_pages / 256);
209 #ifdef DEBUG
210 if (starcat_cage_size_limit)
211 preferred_cage_size = starcat_cage_size_limit;
212 #endif
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).
220 kcage_range_init(phys_avail, KCAGE_DOWN, preferred_cage_size);
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");
229 void
230 load_platform_modules(void)
232 if (modload("misc", "pcihp") < 0) {
233 cmn_err(CE_NOTE, "pcihp driver failed to load");
238 * Starcat does not support power control of CPUs from the OS.
240 /*ARGSUSED*/
242 plat_cpu_poweron(struct cpu *cp)
244 int (*starcat_cpu_poweron)(struct cpu *) = NULL;
246 starcat_cpu_poweron =
247 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0);
249 if (starcat_cpu_poweron == NULL)
250 return (ENOTSUP);
251 else
252 return ((starcat_cpu_poweron)(cp));
255 /*ARGSUSED*/
257 plat_cpu_poweroff(struct cpu *cp)
259 int (*starcat_cpu_poweroff)(struct cpu *) = NULL;
261 starcat_cpu_poweroff =
262 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0);
264 if (starcat_cpu_poweroff == NULL)
265 return (ENOTSUP);
266 else
267 return ((starcat_cpu_poweroff)(cp));
271 * The following are currently private to Starcat DR
274 plat_max_boards()
276 return (starcat_boards);
280 plat_max_cpu_units_per_board()
282 return (starcat_cpu_per_board);
286 plat_max_mc_units_per_board()
288 return (starcat_mem_per_board); /* each CPU has a memory controller */
292 plat_max_mem_units_per_board()
294 return (starcat_mem_per_board);
298 plat_max_io_units_per_board()
300 return (starcat_io_per_board);
304 plat_max_cpumem_boards(void)
306 return (STARCAT_BDSET_MAX);
310 plat_pfn_to_mem_node(pfn_t pfn)
312 return (pfn >> mem_node_pfn_shift);
315 #define STARCAT_MC_MEMBOARD_SHIFT 37 /* Boards on 128BG boundary */
317 /* ARGSUSED */
318 void
319 plat_build_mem_nodes(prom_memlist_t *list, size_t nelems)
321 size_t elem;
322 pfn_t basepfn;
323 pgcnt_t npgs;
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.
330 mem_node_pfn_shift = STARCAT_MC_MEMBOARD_SHIFT - MMU_PAGESHIFT;
331 mem_node_physalign = 0;
334 * Boot install lists are arranged <addr, len>, <addr, len>, ...
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);
344 * Find the CPU associated with a slice at boot-time.
346 void
347 plat_fill_mc(pnode_t nodeid)
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;
359 * Memory address decoding registers
360 * (see Chap 9 of SPARCV9 JSP-1 US-III implementation)
362 const uint64_t mc_decode_addr[MAX_BANKS_PER_MC] = {
363 0x400028, 0x400010, 0x400018, 0x400020
367 * Starcat memory controller portid == global CPU id
369 if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
370 (portid == -1))
371 return;
373 expnum = STARCAT_CPUID_TO_EXPANDER(portid);
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.
380 len = prom_getproplen(nodeid, "reg");
381 if (len != (sizeof (uint32_t) * 4)) {
382 prom_printf("Warning: malformed 'reg' property\n");
383 return;
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];
391 * Figure out whether the memory controller we are examining
392 * belongs to this CPU/CMP or a different one.
394 if (portid == cpunodes[CPU->cpu_id].portid)
395 local_mc = 1;
396 else
397 local_mc = 0;
399 for (i = 0; i < MAX_BANKS_PER_MC; i++) {
401 mask = mc_decode_addr[i];
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.
409 if (local_mc)
410 mc_decode[i] = lddmcdecode(mask & MC_OFFSET_MASK);
411 else
412 mc_decode[i] = lddphysio((mc_addr | mask));
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);
418 if (sliceid < max_mem_nodes) {
420 * Establish start-of-day mappings of
421 * lgroup platform handles to memnodes.
422 * Handle == Expander Number
423 * Memnode == Fixed 128GB Slice
425 plat_assign_lgrphand_to_mem_node(expnum,
426 sliceid);
433 * Starcat support for lgroups.
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.
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.
447 * Convert board number to expander number.
449 #define BOARDNUM_2_EXPANDER(b) (b >> 1)
452 * Return the number of boards configured with NULL LPA.
454 static int
455 check_for_null_lpa(void)
457 gdcd_t *gdcd;
458 uint_t exp, nlpa;
461 * Read GDCD from IOSRAM.
462 * If this fails indicate a NULL LPA condition.
464 if ((gdcd = kmem_zalloc(sizeof (gdcd_t), KM_NOSLEEP)) == NULL)
465 return (EXP_COUNT+1);
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);
476 * Check for NULL LPAs on all slot 0 boards in domain
477 * (i.e. in all expanders marked good for this domain).
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++;
487 kmem_free(gdcd, sizeof (gdcd_t));
488 return (nlpa);
492 * Return the platform handle for the lgroup containing the given CPU
494 * For Starcat, lgroup platform handle == expander.
497 extern int mpo_disabled;
498 extern lgrp_handle_t lgrp_default_handle;
499 int null_lpa_boards = -1;
501 lgrp_handle_t
502 plat_lgrp_cpu_to_hand(processorid_t id)
504 lgrp_handle_t plathand;
506 plathand = STARCAT_CPUID_TO_EXPANDER(id);
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.
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.
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;
531 return (plathand);
535 * Platform specific lgroup initialization
537 void
538 plat_lgrp_init(void)
540 extern uint32_t lgrp_expand_proc_thresh;
541 extern uint32_t lgrp_expand_proc_diff;
544 * Set tuneables for Starcat architecture
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.
550 * lgrp_expand_proc_diff determines how much less the remote lgroup
551 * must be loaded before expanding to it.
553 * Since remote latencies can be costly, attempt to keep 3 threads
554 * within the same lgroup before expanding to the next lgroup.
556 lgrp_expand_proc_thresh = LGRP_LOADAVG_THREAD_MAX * 3;
557 lgrp_expand_proc_diff = LGRP_LOADAVG_THREAD_MAX;
561 * Platform notification of lgroup (re)configuration changes
563 /*ARGSUSED*/
564 void
565 plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg)
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;
573 if (mpo_disabled)
574 return;
576 switch (evt) {
578 case LGRP_CONFIG_MEM_ADD:
580 * Establish the lgroup handle to memnode translation.
582 umb = (update_membounds_t *)arg;
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);
588 break;
590 case LGRP_CONFIG_MEM_DEL:
591 /* We don't have to do anything */
593 break;
595 case LGRP_CONFIG_MEM_RENAME:
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.
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.
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).
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.
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);
628 plat_assign_lgrphand_to_mem_node(thand, snode);
629 plat_assign_lgrphand_to_mem_node(shand, tnode);
631 lmr.lmem_rename_from = shand;
632 lmr.lmem_rename_to = thand;
635 * Remove source memnode of copy rename from its lgroup
636 * and add it to its new target lgroup
638 lgrp_config(LGRP_CONFIG_MEM_RENAME, (uintptr_t)snode,
639 (uintptr_t)&lmr);
641 break;
643 default:
644 break;
649 * Return latency between "from" and "to" lgroups
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.
660 plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to)
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
667 if (lgrp_optimizations() && (from != to ||
668 from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE))
669 return (48);
670 else
671 return (28);
675 * Return platform handle for root lgroup
677 lgrp_handle_t
678 plat_lgrp_root_hand(void)
680 if (mpo_disabled)
681 return (lgrp_default_handle);
683 return (LGRP_DEFAULT_HANDLE);
686 /* ARGSUSED */
687 void
688 plat_freelist_process(int mnode)
692 void
693 load_platform_drivers(void)
695 uint_t tunnel;
696 pnode_t nodeid;
697 dev_info_t *chosen_devi;
698 char chosen_iosram[MAXNAMELEN];
701 * Get /chosen node - that's where the tunnel property is
703 nodeid = prom_chosennode();
706 * Get the iosram property from the chosen node.
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");
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);
722 * Attach all driver instances along the iosram's device path
724 if (i_ddi_attach_hw_nodes("iosram") != DDI_SUCCESS) {
725 cmn_err(CE_WARN, "IOSRAM failed to load\n");
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);
734 ndi_rele_devi(chosen_devi);
737 * iosram driver is now loaded so we need to set our read and
738 * write pointers.
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);
746 * Need to check for null proc LPA after IOSRAM driver is loaded
747 * and before multiple lgroups created (when start_other_cpus() called)
749 null_lpa_boards = check_for_null_lpa();
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");
756 /* load Starcat Solaris Mailbox Client driver */
757 if (modload("misc", "scosmb") < 0) {
758 cmn_err(CE_WARN, "SCOSMB failed to load\n");
761 /* load the DR driver */
762 if (i_ddi_attach_hw_nodes("dr") != DDI_SUCCESS) {
763 cmn_err(CE_WARN, "dr failed to load");
767 * Load the mc-us3 memory driver.
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"));
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");
778 plat_ecc_init();
783 * No platform drivers on this platform
785 char *platform_module_list[] = {
786 (char *)0
790 /*ARGSUSED*/
791 void
792 plat_tod_fault(enum tod_fault_type tod_bad)
797 * Update the signature(s) in the IOSRAM's domain data section.
799 void
800 cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid)
802 sig_state_t new_sgn;
803 sig_state_t current_sgn;
806 * If the substate is REBOOT, then check for panic flow
808 if (sub_state == SIGSUBST_REBOOT) {
809 (*iosram_rdp)(DOMD_MAGIC, DOMD_DSTATE_OFFSET,
810 sizeof (sig_state_t), (caddr_t)&current_sgn);
811 if (current_sgn.state_t.state == SIGST_EXIT)
812 sub_state = SIGSUBST_PANIC_REBOOT;
816 * cpuid == -1 indicates that the operation applies to all cpus.
818 if (cpuid < 0) {
819 sgn_update_all_cpus(sgn, state, sub_state);
820 return;
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);
829 * Under certain conditions we don't update the signature
830 * of the domain_state.
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);
840 * Update the signature(s) in the IOSRAM's domain data section for all CPUs.
842 void
843 sgn_update_all_cpus(ushort_t sgn, uchar_t state, uchar_t sub_state)
845 sig_state_t new_sgn;
846 int i = 0;
848 new_sgn.signature = CPU_SIG_BLD(sgn, state, sub_state);
851 * First update the domain_state signature
853 (*iosram_wrp)(DOMD_MAGIC, DOMD_DSTATE_OFFSET, sizeof (sig_state_t),
854 (caddr_t)&new_sgn);
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);
866 ushort_t
867 get_cpu_sgn(int cpuid)
869 sig_state_t cpu_sgn;
871 (*iosram_rdp)(DOMD_MAGIC,
872 DOMD_CPUSIGS_OFFSET + cpuid * sizeof (sig_state_t),
873 sizeof (sig_state_t), (caddr_t)&cpu_sgn);
875 return (cpu_sgn.state_t.sig);
878 uchar_t
879 get_cpu_sgn_state(int cpuid)
881 sig_state_t cpu_sgn;
883 (*iosram_rdp)(DOMD_MAGIC,
884 DOMD_CPUSIGS_OFFSET + cpuid * sizeof (sig_state_t),
885 sizeof (sig_state_t), (caddr_t)&cpu_sgn);
887 return (cpu_sgn.state_t.state);
892 * Type of argument passed into plat_get_ecache_cpu via ddi_walk_devs
893 * for matching on specific CPU node in device tree
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;
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.
915 static int
916 plat_get_ecache_cpu(dev_info_t *dip, void *arg)
918 char *devtype;
919 plat_ecache_cpu_arg_t *cpuarg;
920 char **dimm_labels;
921 uint_t numlabels;
922 int portid;
925 * Check device_type, must be "cpu"
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);
932 if (strcmp(devtype, "cpu")) {
933 ddi_prop_free((void *)devtype);
934 return (DDI_WALK_CONTINUE);
937 ddi_prop_free((void *)devtype);
940 * Check cpuid, portid, upa-portid (in that order), must
941 * match the cpuid being sought
944 portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
945 DDI_PROP_DONTPASS, "cpuid", -1);
947 if (portid == -1)
948 portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
949 DDI_PROP_DONTPASS, "portid", -1);
951 if (portid == -1)
952 portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
953 DDI_PROP_DONTPASS, "upa-portid", -1);
955 cpuarg = (plat_ecache_cpu_arg_t *)arg;
957 if (portid != cpuarg->cpuid)
958 return (DDI_WALK_CONTINUE);
961 * Found the right CPU, fetch ecache-dimm-label property
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);
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 */
986 ddi_prop_free((void *)dimm_labels);
987 return (DDI_WALK_TERMINATE);
992 * Bit 4 of physical address indicates ecache 0 or 1
995 #define ECACHE_DIMM_MASK 0x10
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.
1004 plat_get_ecacheunum(int cpuid, unsigned long long physaddr, char *buf,
1005 int buflen, int *ustrlen)
1007 plat_ecache_cpu_arg_t findcpu;
1008 uint_t expander, slot, proc;
1010 findcpu.jnum = (char *)NULL;
1011 findcpu.cpuid = cpuid;
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
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;
1024 * Walk the device tree, find this specific CPU, and get the label
1025 * for this ecache, returned here in findcpu.jnum
1028 ddi_walk_devs(ddi_root_node(), plat_get_ecache_cpu, (void *)&findcpu);
1030 if (findcpu.jnum == (char *)NULL)
1031 return (-1);
1033 expander = STARCAT_CPUID_TO_EXPANDER(cpuid);
1034 slot = STARCAT_CPUID_TO_BOARDSLOT(cpuid);
1037 * STARCAT_CPUID_TO_PORTID clears the CoreID bit so that
1038 * STARCAT_CPUID_TO_AGENT will return a physical proc (0 - 3).
1040 proc = STARCAT_CPUID_TO_AGENT(STARCAT_CPUID_TO_PORTID(cpuid));
1043 * NOTE: Any modifications to the snprintf() call below will require
1044 * changing plat_log_fruid_error() as well!
1046 (void) snprintf(buf, buflen, "%s%u/P%u/E%u J%s", (slot ? "IO" : "SB"),
1047 expander, proc, findcpu.dimm, findcpu.jnum);
1049 *ustrlen = strlen(buf);
1051 kmem_free(findcpu.jnum, strlen(findcpu.jnum) + 1);
1053 return (0);
1056 /*ARGSUSED*/
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)
1061 int ret;
1064 * check if it's a Memory or an Ecache error.
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);
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);
1081 return (ret);
1084 static int (*ecc_mailbox_msg_func)(plat_ecc_message_type_t, void *) = NULL;
1087 * To keep OS mailbox handling localized, all we do is forward the call to the
1088 * scosmb module (if it is available).
1091 plat_send_ecc_mailbox_msg(plat_ecc_message_type_t msg_type, void *datap)
1094 * find the symbol for the mailbox sender routine in the scosmb module
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);
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.
1104 if (ecc_mailbox_msg_func)
1105 return ((*ecc_mailbox_msg_func)(msg_type, datap));
1106 else
1107 return (ENODEV);
1111 plat_make_fru_cpuid(int sb, int m, int proc)
1113 return (MAKE_CPUID(sb, m, proc));
1117 * board number for a given proc
1120 plat_make_fru_boardnum(int proc)
1122 return (STARCAT_CPUID_TO_EXPANDER(proc));
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.
1130 void
1131 plat_add_mem_unum_label(char *unum, int mcid, int bank, int dimm)
1133 char new_unum[UNUM_NAMLEN];
1134 uint_t expander = STARCAT_CPUID_TO_EXPANDER(mcid);
1135 uint_t slot = STARCAT_CPUID_TO_BOARDSLOT(mcid);
1138 * STARCAT_CPUID_TO_PORTID clears the CoreID bit so that
1139 * STARCAT_CPUID_TO_AGENT will return a physical proc (0 - 3).
1141 uint_t proc = STARCAT_CPUID_TO_AGENT(STARCAT_CPUID_TO_PORTID(mcid));
1144 * NOTE: Any modifications to the two sprintf() calls below will
1145 * require changing plat_log_fruid_error() as well!
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);
1155 (void) strcpy(unum, new_unum);
1159 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
1161 int expander = STARCAT_CPUID_TO_EXPANDER(cpuid);
1162 int slot = STARCAT_CPUID_TO_BOARDSLOT(cpuid);
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);
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.
1178 void
1179 plat_dmv_params(uint_t *hwint, uint_t *swint)
1181 *hwint = STARCAT_DMV_HWINT;
1182 *swint = 0;
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).
1190 void
1191 plat_nodename_set(void)
1193 void (*nodename_update_func)(uint64_t) = NULL;
1196 * find the symbol for the nodename update routine in the scosmb module
1198 nodename_update_func = (void (*)(uint64_t))
1199 modgetsymvalue("scosmb_update_nodename", 0);
1202 * If the symbol was found, call it. Otherwise, log a note (but not to
1203 * the console).
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");
1213 caddr_t efcode_vaddr = NULL;
1214 caddr_t efcode_paddr = NULL;
1216 * Preallocate enough memory for fcode claims.
1219 caddr_t
1220 efcode_alloc(caddr_t alloc_base)
1222 caddr_t efcode_alloc_base = (caddr_t)roundup((uintptr_t)alloc_base,
1223 MMU_PAGESIZE);
1224 caddr_t vaddr;
1227 * allocate the physical memory schizo fcode.
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");
1233 efcode_vaddr = vaddr;
1235 return (efcode_alloc_base + efcode_size);
1238 caddr_t
1239 plat_startup_memlist(caddr_t alloc_base)
1241 caddr_t tmp_alloc_base;
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);
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.
1260 starcat_dr_name(char *name)
1262 int (*drmach_name2type)(char *) = NULL;
1264 /* Get a pointer to helper function in the dramch module. */
1265 drmach_name2type =
1266 (int (*)(char *))kobj_getsymvalue("drmach_name2type_idx", 0);
1268 if (drmach_name2type == NULL)
1269 return (-1);
1271 return ((*drmach_name2type)(name));
1274 void
1275 startup_platform(void)
1277 /* set per platform constants for mutex backoff */
1278 mutex_backoff_base = 2;
1279 mutex_cap_factor = 64;
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.
1289 static void
1290 starcat_system_claim(void)
1292 lbolt_debug_entry();
1294 prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0);
1297 static void
1298 starcat_system_release(void)
1300 prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0);
1302 lbolt_debug_return();
1305 void
1306 plat_kdi_init(kdi_t *kdi)
1308 kdi->pkdi_system_claim = starcat_system_claim;
1309 kdi->pkdi_system_release = starcat_system_release;
1313 * This function returns 1 if large pages for kernel heap are supported
1314 * and 0 otherwise.
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
1321 plat_lpkmem_is_supported(void)
1323 extern int segkmem_reloc;
1325 if (kernel_cage_enable && (ncpunode >= 32 || segkmem_reloc == 1))
1326 return (0);
1328 return (1);