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]
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>
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>
55 #include <sys/cheetahregs.h>
56 #include <sys/plat_ecc_unum.h>
57 #include <sys/plat_ecc_dimm.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)
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
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 */
152 ce_verbose_memory
= 2;
153 ce_verbose_other
= 2;
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) {
187 cmn_err(CE_NOTE
, "!Kernel Page Relocation is ENABLED");
189 cmn_err(CE_NOTE
, "!Kernel Page Relocation is DISABLED");
194 pgcnt_t starcat_cage_size_limit
;
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);
210 if (starcat_cage_size_limit
)
211 preferred_cage_size
= starcat_cage_size_limit
;
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
);
224 cmn_err(CE_NOTE
, "!DR Kernel Cage is ENABLED");
226 cmn_err(CE_NOTE
, "!DR Kernel Cage is DISABLED");
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.
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
)
252 return ((starcat_cpu_poweron
)(cp
));
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
)
267 return ((starcat_cpu_poweroff
)(cp
));
271 * The following are currently private to Starcat DR
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 */
319 plat_build_mem_nodes(prom_memlist_t
*list
, size_t nelems
)
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.
347 plat_fill_mc(pnode_t nodeid
)
350 uint64_t mc_addr
, mask
;
351 uint64_t mc_decode
[MAX_BANKS_PER_MC
];
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) ||
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");
385 if (prom_getprop(nodeid
, "reg", (caddr_t
)regs
) < 0)
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
)
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
410 mc_decode
[i
] = lddmcdecode(mask
& MC_OFFSET_MASK
);
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
,
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
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.
455 check_for_null_lpa(void)
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).
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
))
487 kmem_free(gdcd
, sizeof (gdcd_t
));
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;
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.
522 /* If MPO is disabled, return the default (UMA) handle */
523 plathand
= lgrp_default_handle
;
525 if (null_lpa_boards
> 0) {
526 /* Determine if MPO should be disabled */
528 plathand
= lgrp_default_handle
;
535 * Platform specific lgroup initialization
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
565 plat_lgrp_config(lgrp_config_flag_t evt
, uintptr_t arg
)
567 update_membounds_t
*umb
;
568 lgrp_config_mem_rename_t lmr
;
570 lgrp_handle_t hand
, shand
, thand
;
571 int mnode
, snode
, tnode
;
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
);
590 case LGRP_CONFIG_MEM_DEL
:
591 /* We don't have to do anything */
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
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
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
,
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
))
675 * Return platform handle for root lgroup
678 plat_lgrp_root_hand(void)
681 return (lgrp_default_handle
);
683 return (LGRP_DEFAULT_HANDLE
);
688 plat_freelist_process(int mnode
)
693 load_platform_drivers(void)
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",
717 cmn_err(CE_PANIC
, "prom_phandle_to_path(0x%x) failed\n",
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",
731 cmn_err(CE_PANIC
, "e_ddi_hold_devi_by_path(%s) failed\n",
734 ndi_rele_devi(chosen_devi
);
737 * iosram driver is now loaded so we need to set our read and
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");
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");
783 * No platform drivers on this platform
785 char *platform_module_list
[] = {
792 plat_tod_fault(enum tod_fault_type tod_bad
)
797 * Update the signature(s) in the IOSRAM's domain data section.
800 cpu_sgn_update(ushort_t sgn
, uchar_t state
, uchar_t sub_state
, int cpuid
)
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
)¤t_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.
819 sgn_update_all_cpus(sgn
, state
, sub_state
);
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
)))
835 (*iosram_wrp
)(DOMD_MAGIC
, DOMD_DSTATE_OFFSET
, sizeof (sig_state_t
),
840 * Update the signature(s) in the IOSRAM's domain data section for all CPUs.
843 sgn_update_all_cpus(ushort_t sgn
, uchar_t state
, uchar_t sub_state
)
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
),
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
);
867 get_cpu_sgn(int cpuid
)
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
);
879 get_cpu_sgn_state(int cpuid
)
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
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.
916 plat_get_ecache_cpu(dev_info_t
*dip
, void *arg
)
919 plat_ecache_cpu_arg_t
*cpuarg
;
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);
948 portid
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
949 DDI_PROP_DONTPASS
, "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
) {
968 cmn_err(CE_NOTE
, "cpuid=%d missing ecache-dimm-label property",
971 return (DDI_WALK_TERMINATE
);
974 if (cpuarg
->dimm
< numlabels
) {
975 cpuarg
->jnum
= kmem_alloc(strlen(dimm_labels
[cpuarg
->dimm
]) + 1,
977 if (cpuarg
->jnum
!= NULL
)
978 (void) strcpy(cpuarg
->jnum
, dimm_labels
[cpuarg
->dimm
]);
982 "cannot kmem_alloc for ecache dimm label");
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
= 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;
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
== NULL
)
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);
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
)
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
));
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)
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
));
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.
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!
1148 (void) snprintf(new_unum
, UNUM_NAMLEN
, "%s%u/P%u/B%d %s",
1149 (slot
? "IO" : "SB"), expander
, proc
, (bank
& 0x1), unum
);
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
)
1168 *lenp
= strlen(buf
);
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.
1179 plat_dmv_params(uint_t
*hwint
, uint_t
*swint
)
1181 *hwint
= STARCAT_DMV_HWINT
;
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).
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
1205 if (nodename_update_func
!= NULL
) {
1206 nodename_update_func(0);
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.
1220 efcode_alloc(caddr_t alloc_base
)
1222 caddr_t efcode_alloc_base
= (caddr_t
)roundup((uintptr_t)alloc_base
,
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
);
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
,
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. */
1266 (int (*)(char *))kobj_getsymvalue("drmach_name2type_idx", 0);
1268 if (drmach_name2type
== NULL
)
1271 return ((*drmach_name2type
)(name
));
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.
1290 starcat_system_claim(void)
1292 lbolt_debug_entry();
1294 prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG
, OBP_SIG
, 0, 0, 0);
1298 starcat_system_release(void)
1300 prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG
, OS_SIG
, 0, 0, 0);
1302 lbolt_debug_return();
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
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))