11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
52220Sstevel * Common Development and Distribution License (the "License").
62220Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
212220Sstevel
221708Sstevel /*
2311066Srafael.vanoni@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel #include <sys/time.h>
281708Sstevel #include <sys/cpuvar.h>
291708Sstevel #include <sys/dditypes.h>
301708Sstevel #include <sys/ddipropdefs.h>
311708Sstevel #include <sys/ddi_impldefs.h>
321708Sstevel #include <sys/sunddi.h>
331708Sstevel #include <sys/esunddi.h>
341708Sstevel #include <sys/sunndi.h>
351708Sstevel #include <sys/platform_module.h>
361708Sstevel #include <sys/errno.h>
371708Sstevel #include <sys/conf.h>
381708Sstevel #include <sys/modctl.h>
391708Sstevel #include <sys/promif.h>
401708Sstevel #include <sys/promimpl.h>
411708Sstevel #include <sys/prom_plat.h>
421708Sstevel #include <sys/cmn_err.h>
431708Sstevel #include <sys/sysmacros.h>
441708Sstevel #include <sys/mem_cage.h>
451708Sstevel #include <sys/kobj.h>
461708Sstevel #include <sys/utsname.h>
471708Sstevel #include <sys/cpu_sgnblk_defs.h>
481708Sstevel #include <sys/atomic.h>
491708Sstevel #include <sys/kdi_impl.h>
501708Sstevel
511708Sstevel #include <sys/sgsbbc.h>
521708Sstevel #include <sys/sgsbbc_iosram.h>
531708Sstevel #include <sys/sgsbbc_iosram_priv.h>
541708Sstevel #include <sys/sgsbbc_mailbox.h>
551708Sstevel #include <sys/sgsgn.h>
561708Sstevel #include <sys/sgcn.h>
571708Sstevel #include <sys/serengeti.h>
581708Sstevel #include <sys/sgfrutypes.h>
591708Sstevel #include <sys/machsystm.h>
601708Sstevel #include <sys/sbd_ioctl.h>
611708Sstevel #include <sys/sbd.h>
621708Sstevel #include <sys/sbdp_mem.h>
631708Sstevel
641708Sstevel #include <sys/memnode.h>
651708Sstevel #include <vm/vm_dep.h>
661708Sstevel #include <vm/page.h>
671708Sstevel
681708Sstevel #include <sys/cheetahregs.h>
691708Sstevel #include <sys/plat_ecc_unum.h>
701708Sstevel #include <sys/plat_ecc_dimm.h>
711708Sstevel
721708Sstevel #include <sys/lgrp.h>
7311066Srafael.vanoni@sun.com #include <sys/clock_impl.h>
741708Sstevel
751708Sstevel static int sg_debug = 0;
761708Sstevel
771708Sstevel #ifdef DEBUG
781708Sstevel #define DCMNERR if (sg_debug) cmn_err
791708Sstevel #else
801708Sstevel #define DCMNERR
811708Sstevel #endif
821708Sstevel
831708Sstevel int (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
841708Sstevel
851708Sstevel /* local functions */
861708Sstevel static void cpu_sgn_update(ushort_t sgn, uchar_t state,
871708Sstevel uchar_t sub_state, int cpuid);
881708Sstevel
891708Sstevel
901708Sstevel /*
911708Sstevel * Local data.
921708Sstevel *
931708Sstevel * iosram_write_ptr is a pointer to iosram_write(). Because of
941708Sstevel * kernel dynamic linking, we can't get to the function by name,
951708Sstevel * but we can look up its address, and store it in this variable
961708Sstevel * instead.
971708Sstevel *
981708Sstevel * We include the extern for iosram_write() here not because we call
991708Sstevel * it, but to force compilation errors if its prototype doesn't
1001708Sstevel * match the prototype of iosram_write_ptr.
1011708Sstevel *
1021708Sstevel * The same issues apply to iosram_read() and iosram_read_ptr.
1031708Sstevel */
1041708Sstevel /*CSTYLED*/
1051708Sstevel extern int iosram_write (int, uint32_t, caddr_t, uint32_t);
1061708Sstevel static int (*iosram_write_ptr)(int, uint32_t, caddr_t, uint32_t) = NULL;
1071708Sstevel /*CSTYLED*/
1081708Sstevel extern int iosram_read (int, uint32_t, caddr_t, uint32_t);
1091708Sstevel static int (*iosram_read_ptr)(int, uint32_t, caddr_t, uint32_t) = NULL;
1101708Sstevel
1111708Sstevel
1121708Sstevel /*
1131708Sstevel * Variable to indicate if the date should be obtained from the SC or not.
1141708Sstevel */
1151708Sstevel int todsg_use_sc = FALSE; /* set the false at the beginning */
1161708Sstevel
1171708Sstevel /*
1181708Sstevel * Preallocation of spare tsb's for DR
1191708Sstevel *
1201708Sstevel * We don't allocate spares for Wildcat since TSBs should come
1211708Sstevel * out of memory local to the node.
1221708Sstevel */
1231708Sstevel #define IOMMU_PER_SCHIZO 2
1241708Sstevel int serengeti_tsb_spares = (SG_MAX_IO_BDS * SG_SCHIZO_PER_IO_BD *
1251708Sstevel IOMMU_PER_SCHIZO);
1261708Sstevel
1271708Sstevel /*
1282241Shuah * sg_max_ncpus is the maximum number of CPUs supported on Serengeti.
1292241Shuah * sg_max_ncpus is set to be smaller than NCPU to reduce the amount of
1302241Shuah * memory the logs take up until we have a dynamic log memory allocation
1312241Shuah * solution.
1321708Sstevel */
1332241Shuah int sg_max_ncpus = (24 * 2); /* (max # of processors * # of cores/proc) */
1341708Sstevel
1351708Sstevel /*
1361708Sstevel * variables to control mailbox message timeouts.
1371708Sstevel * These can be patched via /etc/system or mdb.
1381708Sstevel */
1391708Sstevel int sbbc_mbox_default_timeout = MBOX_DEFAULT_TIMEOUT;
1401708Sstevel int sbbc_mbox_min_timeout = MBOX_MIN_TIMEOUT;
1411708Sstevel
1421708Sstevel /* cached 'chosen' node_id */
1431708Sstevel pnode_t chosen_nodeid = (pnode_t)0;
1441708Sstevel
1451708Sstevel static void (*sg_ecc_taskq_func)(sbbc_ecc_mbox_t *) = NULL;
1461708Sstevel static int (*sg_ecc_mbox_func)(sbbc_ecc_mbox_t *) = NULL;
1471708Sstevel
1481708Sstevel /*
1491708Sstevel * Table that maps memory slices to a specific memnode.
1501708Sstevel */
1511708Sstevel int slice_to_memnode[SG_MAX_SLICE];
1521708Sstevel
1531708Sstevel plat_dimm_sid_board_t domain_dimm_sids[SG_MAX_CPU_BDS];
1541708Sstevel
1551708Sstevel
1561708Sstevel int
set_platform_tsb_spares()1571708Sstevel set_platform_tsb_spares()
1581708Sstevel {
1591708Sstevel return (MIN(serengeti_tsb_spares, MAX_UPA));
1601708Sstevel }
1611708Sstevel
1621708Sstevel #pragma weak mmu_init_large_pages
1631708Sstevel
1641708Sstevel void
set_platform_defaults(void)1651708Sstevel set_platform_defaults(void)
1661708Sstevel {
1671708Sstevel extern int watchdog_enable;
1681708Sstevel extern uint64_t xc_tick_limit_scale;
1691708Sstevel extern void mmu_init_large_pages(size_t);
1701708Sstevel
1711708Sstevel #ifdef DEBUG
1721708Sstevel char *todsg_name = "todsg";
1731708Sstevel ce_verbose_memory = 2;
1741708Sstevel ce_verbose_other = 2;
1751708Sstevel #endif /* DEBUG */
1761708Sstevel
1771708Sstevel watchdog_enable = TRUE;
1781708Sstevel watchdog_available = TRUE;
1791708Sstevel
1801708Sstevel cpu_sgn_func = cpu_sgn_update;
1811708Sstevel
1821708Sstevel #ifdef DEBUG
1831708Sstevel /* tod_module_name should be set to "todsg" from OBP property */
1841708Sstevel if (tod_module_name && (strcmp(tod_module_name, todsg_name) == 0))
1851708Sstevel prom_printf("Using todsg driver\n");
1861708Sstevel else {
1871708Sstevel prom_printf("Force using todsg driver\n");
1881708Sstevel tod_module_name = todsg_name;
1891708Sstevel }
1901708Sstevel #endif /* DEBUG */
1911708Sstevel
1921708Sstevel /* Serengeti does not support forthdebug */
1931708Sstevel forthdebug_supported = 0;
1941708Sstevel
1951708Sstevel
1961708Sstevel /*
1971708Sstevel * Some DR operations require the system to be sync paused.
1981708Sstevel * Sync pause on Serengeti could potentially take up to 4
1991708Sstevel * seconds to complete depending on the load on the SC. To
2001708Sstevel * avoid send_mond panics during such operations, we need to
2011708Sstevel * increase xc_tick_limit to a larger value on Serengeti by
2021708Sstevel * setting xc_tick_limit_scale to 5.
2031708Sstevel */
2041708Sstevel xc_tick_limit_scale = 5;
2051708Sstevel
2061708Sstevel if ((mmu_page_sizes == max_mmu_page_sizes) &&
2072659Ssusans (mmu_ism_pagesize != DEFAULT_ISM_PAGESIZE)) {
2081708Sstevel if (&mmu_init_large_pages)
2091708Sstevel mmu_init_large_pages(mmu_ism_pagesize);
2101708Sstevel }
2111708Sstevel }
2121708Sstevel
2131708Sstevel void
load_platform_modules(void)2141708Sstevel load_platform_modules(void)
2151708Sstevel {
2161708Sstevel if (modload("misc", "pcihp") < 0) {
2171708Sstevel cmn_err(CE_NOTE, "pcihp driver failed to load");
2181708Sstevel }
2191708Sstevel }
2201708Sstevel
2211708Sstevel /*ARGSUSED*/
2221708Sstevel int
plat_cpu_poweron(struct cpu * cp)2231708Sstevel plat_cpu_poweron(struct cpu *cp)
2241708Sstevel {
2251708Sstevel int (*serengeti_cpu_poweron)(struct cpu *) = NULL;
2261708Sstevel
2271708Sstevel serengeti_cpu_poweron =
2281708Sstevel (int (*)(struct cpu *))modgetsymvalue("sbdp_cpu_poweron", 0);
2291708Sstevel
2301708Sstevel if (serengeti_cpu_poweron == NULL)
2311708Sstevel return (ENOTSUP);
2321708Sstevel else
2331708Sstevel return ((serengeti_cpu_poweron)(cp));
2341708Sstevel }
2351708Sstevel
2361708Sstevel /*ARGSUSED*/
2371708Sstevel int
plat_cpu_poweroff(struct cpu * cp)2381708Sstevel plat_cpu_poweroff(struct cpu *cp)
2391708Sstevel {
2401708Sstevel int (*serengeti_cpu_poweroff)(struct cpu *) = NULL;
2411708Sstevel
2421708Sstevel serengeti_cpu_poweroff =
2431708Sstevel (int (*)(struct cpu *))modgetsymvalue("sbdp_cpu_poweroff", 0);
2441708Sstevel
2451708Sstevel if (serengeti_cpu_poweroff == NULL)
2461708Sstevel return (ENOTSUP);
2471708Sstevel else
2481708Sstevel return ((serengeti_cpu_poweroff)(cp));
2491708Sstevel }
2501708Sstevel
2511708Sstevel #ifdef DEBUG
2521708Sstevel pgcnt_t serengeti_cage_size_limit;
2531708Sstevel #endif
2541708Sstevel
2551708Sstevel /* Preferred minimum cage size (expressed in pages)... for DR */
2561708Sstevel pgcnt_t serengeti_minimum_cage_size = 0;
2571708Sstevel
2581708Sstevel void
set_platform_cage_params(void)2591708Sstevel set_platform_cage_params(void)
2601708Sstevel {
2611708Sstevel extern pgcnt_t total_pages;
2621708Sstevel extern struct memlist *phys_avail;
2631708Sstevel
2641708Sstevel if (kernel_cage_enable) {
2651708Sstevel pgcnt_t preferred_cage_size;
2661708Sstevel
2671708Sstevel preferred_cage_size =
2681708Sstevel MAX(serengeti_minimum_cage_size, total_pages / 256);
2691708Sstevel #ifdef DEBUG
2701708Sstevel if (serengeti_cage_size_limit)
2711708Sstevel preferred_cage_size = serengeti_cage_size_limit;
2721708Sstevel #endif
2731708Sstevel /*
2741708Sstevel * Post copies obp into the lowest slice. This requires the
2751708Sstevel * cage to grow upwards
2761708Sstevel */
2774266Sdp78419 kcage_range_init(phys_avail, KCAGE_UP, preferred_cage_size);
2781708Sstevel }
2791708Sstevel
2805872Ssetje kcage_startup_dir = KCAGE_UP;
2815872Ssetje
2821708Sstevel /* Only note when the cage is off since it should always be on. */
2831708Sstevel if (!kcage_on)
2841708Sstevel cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED");
2851708Sstevel }
2861708Sstevel
2871708Sstevel #define ALIGN(x, a) ((a) == 0 ? (uint64_t)(x) : \
2881708Sstevel (((uint64_t)(x) + (uint64_t)(a) - 1l) & ~((uint64_t)(a) - 1l)))
2891708Sstevel
2901708Sstevel void
update_mem_bounds(int brd,uint64_t base,uint64_t sz)2911708Sstevel update_mem_bounds(int brd, uint64_t base, uint64_t sz)
2921708Sstevel {
2931708Sstevel uint64_t end;
2941708Sstevel int mnode;
2951708Sstevel
2961708Sstevel end = base + sz - 1;
2971708Sstevel
2981708Sstevel /*
2991708Sstevel * First see if this board already has a memnode associated
3001708Sstevel * with it. If not, see if this slice has a memnode. This
3011708Sstevel * covers the cases where a single slice covers multiple
3021708Sstevel * boards (cross-board interleaving) and where a single
3031708Sstevel * board has multiple slices (1+GB DIMMs).
3041708Sstevel */
3051708Sstevel if ((mnode = plat_lgrphand_to_mem_node(brd)) == -1) {
3061708Sstevel if ((mnode = slice_to_memnode[PA_2_SLICE(base)]) == -1)
3071708Sstevel mnode = mem_node_alloc();
3081708Sstevel plat_assign_lgrphand_to_mem_node(brd, mnode);
3091708Sstevel }
3101708Sstevel
3111708Sstevel /*
3121708Sstevel * Align base at 16GB boundary
3131708Sstevel */
3141708Sstevel base = ALIGN(base, (1ul << PA_SLICE_SHIFT));
3151708Sstevel
3161708Sstevel while (base < end) {
3171708Sstevel slice_to_memnode[PA_2_SLICE(base)] = mnode;
3181708Sstevel base += (1ul << PA_SLICE_SHIFT);
3191708Sstevel }
3201708Sstevel }
3211708Sstevel
3221708Sstevel /*
3231708Sstevel * Dynamically detect memory slices in the system by decoding
3241708Sstevel * the cpu memory decoder registers at boot time.
3251708Sstevel */
3261708Sstevel void
plat_fill_mc(pnode_t nodeid)3271708Sstevel plat_fill_mc(pnode_t nodeid)
3281708Sstevel {
3291708Sstevel uint64_t mc_addr, mask;
3301708Sstevel uint64_t mc_decode[SG_MAX_BANKS_PER_MC];
3311708Sstevel uint64_t base, size;
3321708Sstevel uint32_t regs[4];
3331708Sstevel int len;
3341708Sstevel int local_mc;
3351708Sstevel int portid;
3361708Sstevel int boardid;
3371708Sstevel int i;
3381708Sstevel
3391708Sstevel if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
3401708Sstevel (portid == -1))
3411708Sstevel return;
3421708Sstevel
3431708Sstevel /*
3441708Sstevel * Decode the board number from the MC portid
3451708Sstevel */
3461708Sstevel boardid = SG_PORTID_TO_BOARD_NUM(portid);
3471708Sstevel
3481708Sstevel /*
3491708Sstevel * The "reg" property returns 4 32-bit values. The first two are
3501708Sstevel * combined to form a 64-bit address. The second two are for a
3511708Sstevel * 64-bit size, but we don't actually need to look at that value.
3521708Sstevel */
3531708Sstevel len = prom_getproplen(nodeid, "reg");
3541708Sstevel if (len != (sizeof (uint32_t) * 4)) {
3551708Sstevel prom_printf("Warning: malformed 'reg' property\n");
3561708Sstevel return;
3571708Sstevel }
3581708Sstevel if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0)
3591708Sstevel return;
3601708Sstevel mc_addr = ((uint64_t)regs[0]) << 32;
3611708Sstevel mc_addr |= (uint64_t)regs[1];
3621708Sstevel
3631708Sstevel /*
3641708Sstevel * Figure out whether the memory controller we are examining
3651708Sstevel * belongs to this CPU or a different one.
3661708Sstevel */
3671708Sstevel if (portid == cpunodes[CPU->cpu_id].portid)
3681708Sstevel local_mc = 1;
3691708Sstevel else
3701708Sstevel local_mc = 0;
3711708Sstevel
3721708Sstevel for (i = 0; i < SG_MAX_BANKS_PER_MC; i++) {
3731708Sstevel mask = SG_REG_2_OFFSET(i);
3741708Sstevel
3751708Sstevel /*
3761708Sstevel * If the memory controller is local to this CPU, we use
3771708Sstevel * the special ASI to read the decode registers.
3781708Sstevel * Otherwise, we load the values from a magic address in
3791708Sstevel * I/O space.
3801708Sstevel */
3811708Sstevel if (local_mc)
3821708Sstevel mc_decode[i] = lddmcdecode(mask & MC_OFFSET_MASK);
3831708Sstevel else
3841708Sstevel mc_decode[i] = lddphysio((mc_addr | mask));
3851708Sstevel
3861708Sstevel if (mc_decode[i] >> MC_VALID_SHIFT) {
3871708Sstevel /*
3881708Sstevel * The memory decode register is a bitmask field,
3891708Sstevel * so we can decode that into both a base and
3901708Sstevel * a span.
3911708Sstevel */
3921708Sstevel base = MC_BASE(mc_decode[i]) << PHYS2UM_SHIFT;
3931708Sstevel size = MC_UK2SPAN(mc_decode[i]);
3941708Sstevel update_mem_bounds(boardid, base, size);
3951708Sstevel }
3961708Sstevel }
3971708Sstevel }
3981708Sstevel
3991708Sstevel /*
4001708Sstevel * This routine is run midway through the boot process. By the time we get
4011708Sstevel * here, we know about all the active CPU boards in the system, and we have
4021708Sstevel * extracted information about each board's memory from the memory
4031708Sstevel * controllers. We have also figured out which ranges of memory will be
4041708Sstevel * assigned to which memnodes, so we walk the slice table to build the table
4051708Sstevel * of memnodes.
4061708Sstevel */
4071708Sstevel /* ARGSUSED */
4081708Sstevel void
plat_build_mem_nodes(prom_memlist_t * list,size_t nelems)4095648Ssetje plat_build_mem_nodes(prom_memlist_t *list, size_t nelems)
4101708Sstevel {
4111708Sstevel int slice;
4121708Sstevel pfn_t basepfn;
4131708Sstevel pgcnt_t npgs;
4141708Sstevel
4151708Sstevel mem_node_pfn_shift = PFN_SLICE_SHIFT;
4161708Sstevel mem_node_physalign = (1ull << PA_SLICE_SHIFT);
4171708Sstevel
4181708Sstevel for (slice = 0; slice < SG_MAX_SLICE; slice++) {
4191708Sstevel if (slice_to_memnode[slice] == -1)
4201708Sstevel continue;
4211708Sstevel basepfn = (uint64_t)slice << PFN_SLICE_SHIFT;
4221708Sstevel npgs = 1ull << PFN_SLICE_SHIFT;
4231708Sstevel mem_node_add_slice(basepfn, basepfn + npgs - 1);
4241708Sstevel }
4251708Sstevel }
4261708Sstevel
4271708Sstevel int
plat_pfn_to_mem_node(pfn_t pfn)4281708Sstevel plat_pfn_to_mem_node(pfn_t pfn)
4291708Sstevel {
4301708Sstevel int node;
4311708Sstevel
4321708Sstevel node = slice_to_memnode[PFN_2_SLICE(pfn)];
4331708Sstevel
4341708Sstevel return (node);
4351708Sstevel }
4361708Sstevel
4371708Sstevel /*
4381708Sstevel * Serengeti support for lgroups.
4391708Sstevel *
4401708Sstevel * On Serengeti, an lgroup platform handle == board number.
4411708Sstevel *
4421708Sstevel * Mappings between lgroup handles and memnodes are managed
4431708Sstevel * in addition to mappings between memory slices and memnodes
4441708Sstevel * to support cross-board interleaving as well as multiple
4451708Sstevel * slices per board (e.g. >1GB DIMMs). The initial mapping
4461708Sstevel * of memnodes to lgroup handles is determined at boot time.
4471708Sstevel * A DR addition of memory adds a new mapping. A DR copy-rename
4481708Sstevel * swaps mappings.
4491708Sstevel */
4501708Sstevel
4511708Sstevel /*
4521708Sstevel * Macro for extracting the board number from the CPU id
4531708Sstevel */
4541708Sstevel #define CPUID_TO_BOARD(id) (((id) >> 2) & 0x7)
4551708Sstevel
4561708Sstevel /*
4571708Sstevel * Return the platform handle for the lgroup containing the given CPU
4581708Sstevel *
4591708Sstevel * For Serengeti, lgroup platform handle == board number
4601708Sstevel */
4611708Sstevel lgrp_handle_t
plat_lgrp_cpu_to_hand(processorid_t id)4621708Sstevel plat_lgrp_cpu_to_hand(processorid_t id)
4631708Sstevel {
4641708Sstevel return (CPUID_TO_BOARD(id));
4651708Sstevel }
4661708Sstevel
4671708Sstevel /*
4681708Sstevel * Platform specific lgroup initialization
4691708Sstevel */
4701708Sstevel void
plat_lgrp_init(void)4711708Sstevel plat_lgrp_init(void)
4721708Sstevel {
4731708Sstevel int i;
4741708Sstevel extern uint32_t lgrp_expand_proc_thresh;
4751708Sstevel extern uint32_t lgrp_expand_proc_diff;
4761708Sstevel
4771708Sstevel /*
4781708Sstevel * Initialize lookup tables to invalid values so we catch
4791708Sstevel * any illegal use of them.
4801708Sstevel */
4811708Sstevel for (i = 0; i < SG_MAX_SLICE; i++) {
4821708Sstevel slice_to_memnode[i] = -1;
4831708Sstevel }
4841708Sstevel
4851708Sstevel /*
4861708Sstevel * Set tuneables for Serengeti architecture
4871708Sstevel *
4881708Sstevel * lgrp_expand_proc_thresh is the minimum load on the lgroups
4891708Sstevel * this process is currently running on before considering
4901708Sstevel * expanding threads to another lgroup.
4911708Sstevel *
4921708Sstevel * lgrp_expand_proc_diff determines how much less the remote lgroup
4931708Sstevel * must be loaded before expanding to it.
4941708Sstevel *
4951708Sstevel * Bandwidth is maximized on Serengeti by spreading load across
4961708Sstevel * the machine. The impact to inter-thread communication isn't
4971708Sstevel * too costly since remote latencies are relatively low. These
4981708Sstevel * values equate to one CPU's load and so attempt to spread the
4991708Sstevel * load out across as many lgroups as possible one CPU at a time.
5001708Sstevel */
5011708Sstevel lgrp_expand_proc_thresh = LGRP_LOADAVG_THREAD_MAX;
5021708Sstevel lgrp_expand_proc_diff = LGRP_LOADAVG_THREAD_MAX;
5031708Sstevel }
5041708Sstevel
5051708Sstevel /*
5061708Sstevel * Platform notification of lgroup (re)configuration changes
5071708Sstevel */
5081708Sstevel /*ARGSUSED*/
5091708Sstevel void
plat_lgrp_config(lgrp_config_flag_t evt,uintptr_t arg)5101708Sstevel plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg)
5111708Sstevel {
5121708Sstevel update_membounds_t *umb;
5131708Sstevel lgrp_config_mem_rename_t lmr;
5141708Sstevel lgrp_handle_t shand, thand;
5151708Sstevel int snode, tnode;
5161708Sstevel
5171708Sstevel switch (evt) {
5181708Sstevel
5191708Sstevel case LGRP_CONFIG_MEM_ADD:
5201708Sstevel umb = (update_membounds_t *)arg;
5211708Sstevel update_mem_bounds(umb->u_board, umb->u_base, umb->u_len);
5221708Sstevel
5231708Sstevel break;
5241708Sstevel
5251708Sstevel case LGRP_CONFIG_MEM_DEL:
5261708Sstevel /* We don't have to do anything */
5271708Sstevel break;
5281708Sstevel
5291708Sstevel case LGRP_CONFIG_MEM_RENAME:
5301708Sstevel /*
5311708Sstevel * During a DR copy-rename operation, all of the memory
5321708Sstevel * on one board is moved to another board -- but the
5331708Sstevel * addresses/pfns and memnodes don't change. This means
5341708Sstevel * the memory has changed locations without changing identity.
5351708Sstevel *
5361708Sstevel * Source is where we are copying from and target is where we
5371708Sstevel * are copying to. After source memnode is copied to target
5381708Sstevel * memnode, the physical addresses of the target memnode are
5391708Sstevel * renamed to match what the source memnode had. Then target
5401708Sstevel * memnode can be removed and source memnode can take its
5411708Sstevel * place.
5421708Sstevel *
5431708Sstevel * To do this, swap the lgroup handle to memnode mappings for
5441708Sstevel * the boards, so target lgroup will have source memnode and
5451708Sstevel * source lgroup will have empty target memnode which is where
5461708Sstevel * its memory will go (if any is added to it later).
5471708Sstevel *
5481708Sstevel * Then source memnode needs to be removed from its lgroup
5491708Sstevel * and added to the target lgroup where the memory was living
5501708Sstevel * but under a different name/memnode. The memory was in the
5511708Sstevel * target memnode and now lives in the source memnode with
5521708Sstevel * different physical addresses even though it is the same
5531708Sstevel * memory.
5541708Sstevel */
5551708Sstevel shand = arg & 0xffff;
5561708Sstevel thand = (arg & 0xffff0000) >> 16;
5571708Sstevel snode = plat_lgrphand_to_mem_node(shand);
5581708Sstevel tnode = plat_lgrphand_to_mem_node(thand);
5591708Sstevel
5601708Sstevel plat_assign_lgrphand_to_mem_node(thand, snode);
5611708Sstevel plat_assign_lgrphand_to_mem_node(shand, tnode);
5621708Sstevel
5631708Sstevel /*
5641708Sstevel * Remove source memnode of copy rename from its lgroup
5651708Sstevel * and add it to its new target lgroup
5661708Sstevel */
5671708Sstevel lmr.lmem_rename_from = shand;
5681708Sstevel lmr.lmem_rename_to = thand;
5691708Sstevel
5701708Sstevel lgrp_config(LGRP_CONFIG_MEM_RENAME, (uintptr_t)snode,
5711708Sstevel (uintptr_t)&lmr);
5721708Sstevel
5731708Sstevel break;
5741708Sstevel
5751708Sstevel default:
5761708Sstevel break;
5771708Sstevel }
5781708Sstevel }
5791708Sstevel
5801708Sstevel /*
5811708Sstevel * Return latency between "from" and "to" lgroups
5821708Sstevel *
5831708Sstevel * This latency number can only be used for relative comparison
5841708Sstevel * between lgroups on the running system, cannot be used across platforms,
5851708Sstevel * and may not reflect the actual latency. It is platform and implementation
5861708Sstevel * specific, so platform gets to decide its value. It would be nice if the
5871708Sstevel * number was at least proportional to make comparisons more meaningful though.
5881708Sstevel * NOTE: The numbers below are supposed to be load latencies for uncached
5891708Sstevel * memory divided by 10.
5901708Sstevel */
5911708Sstevel int
plat_lgrp_latency(lgrp_handle_t from,lgrp_handle_t to)5921708Sstevel plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to)
5931708Sstevel {
5941708Sstevel /*
5951708Sstevel * Return min remote latency when there are more than two lgroups
5961708Sstevel * (root and child) and getting latency between two different lgroups
5971708Sstevel * or root is involved
5981708Sstevel */
5991708Sstevel if (lgrp_optimizations() && (from != to ||
6001708Sstevel from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE))
6011708Sstevel return (28);
6021708Sstevel else
6031708Sstevel return (23);
6041708Sstevel }
6051708Sstevel
6061708Sstevel /* ARGSUSED */
6071708Sstevel void
plat_freelist_process(int mnode)6081708Sstevel plat_freelist_process(int mnode)
6091708Sstevel {
6101708Sstevel }
6111708Sstevel
6121708Sstevel /*
6131708Sstevel * Find dip for chosen IOSRAM
6141708Sstevel */
6151708Sstevel dev_info_t *
find_chosen_dip(void)6161708Sstevel find_chosen_dip(void)
6171708Sstevel {
6181708Sstevel dev_info_t *dip;
6191708Sstevel char master_sbbc[MAXNAMELEN];
6201708Sstevel pnode_t nodeid;
6211708Sstevel uint_t tunnel;
6221708Sstevel
6231708Sstevel /*
6241708Sstevel * find the /chosen SBBC node, prom interface will handle errors
6251708Sstevel */
6261708Sstevel nodeid = prom_chosennode();
6271708Sstevel
6281708Sstevel /*
6291708Sstevel * get the 'iosram' property from the /chosen node
6301708Sstevel */
6311708Sstevel if (prom_getprop(nodeid, IOSRAM_CHOSEN_PROP, (caddr_t)&tunnel) <= 0) {
6321708Sstevel SBBC_ERR(CE_PANIC, "No iosram property found! \n");
6331708Sstevel }
6341708Sstevel
6351708Sstevel if (prom_phandle_to_path((phandle_t)tunnel, master_sbbc,
6361708Sstevel sizeof (master_sbbc)) < 0) {
6371708Sstevel SBBC_ERR1(CE_PANIC, "prom_phandle_to_path(%d) failed\n",
6381708Sstevel tunnel);
6391708Sstevel }
6401708Sstevel
6411708Sstevel chosen_nodeid = nodeid;
6421708Sstevel
6431708Sstevel /*
6441708Sstevel * load and attach the sgsbbc driver.
6451708Sstevel * This will also attach all the sgsbbc driver instances
6461708Sstevel */
6471708Sstevel if (i_ddi_attach_hw_nodes("sgsbbc") != DDI_SUCCESS) {
6481708Sstevel cmn_err(CE_WARN, "sgsbbc failed to load\n");
6491708Sstevel }
6501708Sstevel
6511708Sstevel /* translate a path name to a dev_info_t */
6521708Sstevel dip = e_ddi_hold_devi_by_path(master_sbbc, 0);
6531708Sstevel if ((dip == NULL) || (ddi_get_nodeid(dip) != tunnel)) {
6541708Sstevel cmn_err(CE_PANIC, "i_ddi_path_to_devi(%x) failed for SBBC\n",
6551708Sstevel tunnel);
6561708Sstevel }
6571708Sstevel
6581708Sstevel /* make sure devi_ref is ZERO */
6591708Sstevel ndi_rele_devi(dip);
6601708Sstevel
6611708Sstevel DCMNERR(CE_CONT, "Chosen IOSRAM is at %s \n", master_sbbc);
6621708Sstevel
6631708Sstevel return (dip);
6641708Sstevel }
6651708Sstevel
6661708Sstevel void
load_platform_drivers(void)6671708Sstevel load_platform_drivers(void)
6681708Sstevel {
6691708Sstevel int ret;
6701708Sstevel
6711708Sstevel /*
6721708Sstevel * Load and attach the mc-us3 memory driver.
6731708Sstevel */
6741708Sstevel if (i_ddi_attach_hw_nodes("mc-us3") != DDI_SUCCESS)
6751708Sstevel cmn_err(CE_WARN, "mc-us3 failed to load");
6761708Sstevel else
6771708Sstevel (void) ddi_hold_driver(ddi_name_to_major("mc-us3"));
6781708Sstevel
6791708Sstevel /*
6801708Sstevel * Initialize the chosen IOSRAM before its clients
6811708Sstevel * are loaded.
6821708Sstevel */
6831708Sstevel (void) find_chosen_dip();
6841708Sstevel
6851708Sstevel /*
6861708Sstevel * Ideally, we'd do this in set_platform_defaults(), but
6871708Sstevel * at that point it's too early to look up symbols.
6881708Sstevel */
6891708Sstevel iosram_write_ptr = (int (*)(int, uint32_t, caddr_t, uint32_t))
6901708Sstevel modgetsymvalue("iosram_write", 0);
6911708Sstevel
6921708Sstevel if (iosram_write_ptr == NULL) {
6931708Sstevel DCMNERR(CE_WARN, "load_platform_defaults: iosram_write()"
6941708Sstevel " not found; signatures will not be updated\n");
6951708Sstevel } else {
6961708Sstevel /*
6971708Sstevel * The iosram read ptr is only needed if we can actually
6981708Sstevel * write CPU signatures, so only bother setting it if we
6991708Sstevel * set a valid write pointer, above.
7001708Sstevel */
7011708Sstevel iosram_read_ptr = (int (*)(int, uint32_t, caddr_t, uint32_t))
7021708Sstevel modgetsymvalue("iosram_read", 0);
7031708Sstevel
7041708Sstevel if (iosram_read_ptr == NULL)
7051708Sstevel DCMNERR(CE_WARN, "load_platform_defaults: iosram_read()"
7061708Sstevel " not found\n");
7071708Sstevel }
7081708Sstevel
7091708Sstevel /*
7101708Sstevel * Set todsg_use_sc to TRUE so that we will be getting date
7111708Sstevel * from the SC.
7121708Sstevel */
7131708Sstevel todsg_use_sc = TRUE;
7141708Sstevel
7151708Sstevel /*
7161708Sstevel * Now is a good time to activate hardware watchdog (if one exists).
7171708Sstevel */
7181708Sstevel mutex_enter(&tod_lock);
7191708Sstevel if (watchdog_enable)
7201708Sstevel ret = tod_ops.tod_set_watchdog_timer(watchdog_timeout_seconds);
7211708Sstevel mutex_exit(&tod_lock);
7221708Sstevel if (ret != 0)
7231708Sstevel printf("Hardware watchdog enabled\n");
7241708Sstevel
7251708Sstevel /*
7261708Sstevel * Load and attach the schizo pci bus nexus driver.
7271708Sstevel */
7281708Sstevel if (i_ddi_attach_hw_nodes("pcisch") != DDI_SUCCESS)
7291708Sstevel cmn_err(CE_WARN, "pcisch failed to load");
7301708Sstevel
7311708Sstevel plat_ecc_init();
7321708Sstevel }
7331708Sstevel
7341708Sstevel /*
7351708Sstevel * No platform drivers on this platform
7361708Sstevel */
7371708Sstevel char *platform_module_list[] = {
7381708Sstevel (char *)0
7391708Sstevel };
7401708Sstevel
7411708Sstevel /*ARGSUSED*/
7421708Sstevel void
plat_tod_fault(enum tod_fault_type tod_bad)7431708Sstevel plat_tod_fault(enum tod_fault_type tod_bad)
7441708Sstevel {
7451708Sstevel }
7461708Sstevel int
plat_max_boards()7471708Sstevel plat_max_boards()
7481708Sstevel {
7491708Sstevel return (SG_MAX_BDS);
7501708Sstevel }
7511708Sstevel int
plat_max_io_units_per_board()7521708Sstevel plat_max_io_units_per_board()
7531708Sstevel {
7541708Sstevel return (SG_MAX_IO_PER_BD);
7551708Sstevel }
7561708Sstevel int
plat_max_cmp_units_per_board()7571708Sstevel plat_max_cmp_units_per_board()
7581708Sstevel {
7591708Sstevel return (SG_MAX_CMPS_PER_BD);
7601708Sstevel }
7611708Sstevel int
plat_max_cpu_units_per_board()7621708Sstevel plat_max_cpu_units_per_board()
7631708Sstevel {
7641708Sstevel return (SG_MAX_CPUS_PER_BD);
7651708Sstevel }
7661708Sstevel
7671708Sstevel int
plat_max_mc_units_per_board()7681708Sstevel plat_max_mc_units_per_board()
7691708Sstevel {
7701708Sstevel return (SG_MAX_CMPS_PER_BD); /* each CPU die has a memory controller */
7711708Sstevel }
7721708Sstevel
7731708Sstevel int
plat_max_mem_units_per_board()7741708Sstevel plat_max_mem_units_per_board()
7751708Sstevel {
7761708Sstevel return (SG_MAX_MEM_PER_BD);
7771708Sstevel }
7781708Sstevel
7791708Sstevel int
plat_max_cpumem_boards(void)7801708Sstevel plat_max_cpumem_boards(void)
7811708Sstevel {
7821708Sstevel return (SG_MAX_CPU_BDS);
7831708Sstevel }
7841708Sstevel
7851708Sstevel int
set_platform_max_ncpus(void)7861708Sstevel set_platform_max_ncpus(void)
7871708Sstevel {
7881708Sstevel return (sg_max_ncpus);
7891708Sstevel }
7901708Sstevel
7911708Sstevel void
plat_dmv_params(uint_t * hwint,uint_t * swint)7921708Sstevel plat_dmv_params(uint_t *hwint, uint_t *swint)
7931708Sstevel {
7941708Sstevel *hwint = MAX_UPA;
7951708Sstevel *swint = 0;
7961708Sstevel }
7971708Sstevel
7981708Sstevel /*
7991708Sstevel * Our nodename has been set, pass it along to the SC.
8001708Sstevel */
8011708Sstevel void
plat_nodename_set(void)8021708Sstevel plat_nodename_set(void)
8031708Sstevel {
8041708Sstevel sbbc_msg_t req; /* request */
8051708Sstevel sbbc_msg_t resp; /* response */
8061708Sstevel int rv; /* return value from call to mbox */
8071708Sstevel struct nodename_info {
8081708Sstevel int32_t namelen;
8091708Sstevel char nodename[_SYS_NMLN];
8101708Sstevel } nni;
8111708Sstevel int (*sg_mbox)(sbbc_msg_t *, sbbc_msg_t *, time_t) = NULL;
8121708Sstevel
8131708Sstevel /*
8141708Sstevel * find the symbol for the mailbox routine
8151708Sstevel */
8161708Sstevel sg_mbox = (int (*)(sbbc_msg_t *, sbbc_msg_t *, time_t))
8175648Ssetje modgetsymvalue("sbbc_mbox_request_response", 0);
8181708Sstevel
8191708Sstevel if (sg_mbox == NULL) {
8201708Sstevel cmn_err(CE_NOTE, "!plat_nodename_set: sg_mbox not found\n");
8211708Sstevel return;
8221708Sstevel }
8231708Sstevel
8241708Sstevel /*
8251708Sstevel * construct the message telling the SC our nodename
8261708Sstevel */
8271708Sstevel (void) strcpy(nni.nodename, utsname.nodename);
8281708Sstevel nni.namelen = (int32_t)strlen(nni.nodename);
8291708Sstevel
8301708Sstevel req.msg_type.type = INFO_MBOX;
8311708Sstevel req.msg_type.sub_type = INFO_MBOX_NODENAME;
8321708Sstevel req.msg_status = 0;
8331708Sstevel req.msg_len = (int)(nni.namelen + sizeof (nni.namelen));
8341708Sstevel req.msg_bytes = 0;
8351708Sstevel req.msg_buf = (caddr_t)&nni;
8361708Sstevel req.msg_data[0] = 0;
8371708Sstevel req.msg_data[1] = 0;
8381708Sstevel
8391708Sstevel /*
8401708Sstevel * initialize the response back from the SC
8411708Sstevel */
8421708Sstevel resp.msg_type.type = INFO_MBOX;
8431708Sstevel resp.msg_type.sub_type = INFO_MBOX_NODENAME;
8441708Sstevel resp.msg_status = 0;
8451708Sstevel resp.msg_len = 0;
8461708Sstevel resp.msg_bytes = 0;
8471708Sstevel resp.msg_buf = (caddr_t)0;
8481708Sstevel resp.msg_data[0] = 0;
8491708Sstevel resp.msg_data[1] = 0;
8501708Sstevel
8511708Sstevel /*
8521708Sstevel * ship it and check for success
8531708Sstevel */
8541708Sstevel rv = (sg_mbox)(&req, &resp, sbbc_mbox_default_timeout);
8551708Sstevel
8561708Sstevel if (rv != 0) {
8571708Sstevel cmn_err(CE_NOTE, "!plat_nodename_set: sg_mbox retval %d\n", rv);
8581708Sstevel } else if (resp.msg_status != 0) {
8591708Sstevel cmn_err(CE_NOTE, "!plat_nodename_set: msg_status %d\n",
8605648Ssetje resp.msg_status);
8611708Sstevel } else {
8621708Sstevel DCMNERR(CE_NOTE, "!plat_nodename_set was successful\n");
8631708Sstevel
8641708Sstevel /*
8651708Sstevel * It is necessary to exchange the capability bitmap
8661708Sstevel * with SC before sending any ecc error information and
8671708Sstevel * indictment. We are calling the plat_ecc_capability_send()
8681708Sstevel * here just after sending the nodename successfully.
8691708Sstevel */
8701708Sstevel rv = plat_ecc_capability_send();
8711708Sstevel if (rv == 0) {
8721708Sstevel DCMNERR(CE_NOTE, "!plat_ecc_capability_send was"
8731708Sstevel " successful\n");
8741708Sstevel }
8751708Sstevel }
8761708Sstevel }
8771708Sstevel
8781708Sstevel /*
8791708Sstevel * flag to allow users switch between using OBP's
8801708Sstevel * prom_get_unum() and mc-us3 driver's p2get_mem_unum()
8811708Sstevel * (for main memory errors only).
8821708Sstevel */
8831708Sstevel int sg_use_prom_get_unum = 0;
8841708Sstevel
8851708Sstevel /*
8861708Sstevel * Debugging flag: set to 1 to call into obp for get_unum, or set it to 0
8871708Sstevel * to call into the unum cache system. This is the E$ equivalent of
8881708Sstevel * sg_use_prom_get_unum.
8891708Sstevel */
8901708Sstevel int sg_use_prom_ecache_unum = 0;
8911708Sstevel
8921708Sstevel /* used for logging ECC errors to the SC */
8931708Sstevel #define SG_MEMORY_ECC 1
8941708Sstevel #define SG_ECACHE_ECC 2
8951708Sstevel #define SG_UNKNOWN_ECC (-1)
8961708Sstevel
8971708Sstevel /*
8981708Sstevel * plat_get_mem_unum() generates a string identifying either the
8991708Sstevel * memory or E$ DIMM(s) during error logging. Depending on whether
9001708Sstevel * the error is E$ or memory related, the appropriate support
9011708Sstevel * routine is called to assist in the string generation.
9021708Sstevel *
9031708Sstevel * - For main memory errors we can use the mc-us3 drivers p2getunum()
9041708Sstevel * (or prom_get_unum() for debugging purposes).
9051708Sstevel *
9061708Sstevel * - For E$ errors we call sg_get_ecacheunum() to generate the unum (or
9071708Sstevel * prom_serengeti_get_ecacheunum() for debugging purposes).
9081708Sstevel */
9091708Sstevel
9101708Sstevel static int
sg_prom_get_unum(int synd_code,uint64_t paddr,char * buf,int buflen,int * lenp)9111708Sstevel sg_prom_get_unum(int synd_code, uint64_t paddr, char *buf, int buflen,
9121708Sstevel int *lenp)
9131708Sstevel {
9141708Sstevel if ((prom_get_unum(synd_code, (unsigned long long)paddr,
9151708Sstevel buf, buflen, lenp)) != 0)
9161708Sstevel return (EIO);
9171708Sstevel else if (*lenp <= 1)
9181708Sstevel return (EINVAL);
9191708Sstevel else
9201708Sstevel return (0);
9211708Sstevel }
9221708Sstevel
9231708Sstevel /*ARGSUSED*/
9241708Sstevel int
plat_get_mem_unum(int synd_code,uint64_t flt_addr,int flt_bus_id,int flt_in_memory,ushort_t flt_status,char * buf,int buflen,int * lenp)9251708Sstevel plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
9261708Sstevel int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
9271708Sstevel {
9281708Sstevel /*
9291708Sstevel * unum_func will either point to the memory drivers p2get_mem_unum()
9301708Sstevel * or to prom_get_unum() for memory errors.
9311708Sstevel */
9321708Sstevel int (*unum_func)(int synd_code, uint64_t paddr, char *buf,
9331708Sstevel int buflen, int *lenp) = p2get_mem_unum;
9341708Sstevel
9351708Sstevel /*
9361708Sstevel * check if it's a Memory or an Ecache error.
9371708Sstevel */
9381708Sstevel if (flt_in_memory) {
9391708Sstevel /*
9401708Sstevel * It's a main memory error.
9411708Sstevel *
9421708Sstevel * For debugging we allow the user to switch between
9431708Sstevel * using OBP's get_unum and the memory driver's get_unum
9441708Sstevel * so we create a pointer to the functions and switch
9451708Sstevel * depending on the sg_use_prom_get_unum flag.
9461708Sstevel */
9471708Sstevel if (sg_use_prom_get_unum) {
9481708Sstevel DCMNERR(CE_NOTE, "Using prom_get_unum from OBP");
9491708Sstevel return (sg_prom_get_unum(synd_code,
9501708Sstevel P2ALIGN(flt_addr, 8), buf, buflen, lenp));
9511708Sstevel } else if (unum_func != NULL) {
9521708Sstevel return (unum_func(synd_code, P2ALIGN(flt_addr, 8),
9531708Sstevel buf, buflen, lenp));
9541708Sstevel } else {
9551708Sstevel return (ENOTSUP);
9561708Sstevel }
9571708Sstevel } else if (flt_status & ECC_ECACHE) {
9581708Sstevel /*
9591708Sstevel * It's an E$ error.
9601708Sstevel */
9611708Sstevel if (sg_use_prom_ecache_unum) {
9621708Sstevel /*
9631708Sstevel * We call to OBP to handle this.
9641708Sstevel */
9651708Sstevel DCMNERR(CE_NOTE,
9661708Sstevel "Using prom_serengeti_get_ecacheunum from OBP");
9671708Sstevel if (prom_serengeti_get_ecacheunum(flt_bus_id,
9681708Sstevel P2ALIGN(flt_addr, 8), buf, buflen, lenp) != 0) {
9691708Sstevel return (EIO);
9701708Sstevel }
9711708Sstevel } else {
9721708Sstevel return (sg_get_ecacheunum(flt_bus_id, flt_addr,
9731708Sstevel buf, buflen, lenp));
9741708Sstevel }
9751708Sstevel } else {
9761708Sstevel return (ENOTSUP);
9771708Sstevel }
9781708Sstevel
9791708Sstevel return (0);
9801708Sstevel }
9811708Sstevel
9821708Sstevel /*
9831708Sstevel * This platform hook gets called from mc_add_mem_unum_label() in the mc-us3
9841708Sstevel * driver giving each platform the opportunity to add platform
9851708Sstevel * specific label information to the unum for ECC error logging purposes.
9861708Sstevel */
9871708Sstevel void
plat_add_mem_unum_label(char * unum,int mcid,int bank,int dimm)9881708Sstevel plat_add_mem_unum_label(char *unum, int mcid, int bank, int dimm)
9891708Sstevel {
9901708Sstevel char new_unum[UNUM_NAMLEN] = "";
9911708Sstevel int node = SG_PORTID_TO_NODEID(mcid);
9921708Sstevel int board = SG_CPU_BD_PORTID_TO_BD_NUM(mcid);
9931708Sstevel int position = SG_PORTID_TO_CPU_POSN(mcid);
9941708Sstevel
9951708Sstevel /*
9961708Sstevel * The mc-us3 driver deals with logical banks but for unum
9971708Sstevel * purposes we need to use physical banks so that the correct
9981708Sstevel * dimm can be physically located. Logical banks 0 and 2
9991708Sstevel * make up physical bank 0. Logical banks 1 and 3 make up
10001708Sstevel * physical bank 1. Here we do the necessary conversion.
10011708Sstevel */
10021708Sstevel bank = (bank % 2);
10031708Sstevel
10041708Sstevel if (dimm == -1) {
10051708Sstevel SG_SET_FRU_NAME_NODE(new_unum, node);
10061708Sstevel SG_SET_FRU_NAME_CPU_BOARD(new_unum, board);
10071708Sstevel SG_SET_FRU_NAME_MODULE(new_unum, position);
10081708Sstevel SG_SET_FRU_NAME_BANK(new_unum, bank);
10091708Sstevel
10101708Sstevel } else {
10111708Sstevel SG_SET_FRU_NAME_NODE(new_unum, node);
10121708Sstevel SG_SET_FRU_NAME_CPU_BOARD(new_unum, board);
10131708Sstevel SG_SET_FRU_NAME_MODULE(new_unum, position);
10141708Sstevel SG_SET_FRU_NAME_BANK(new_unum, bank);
10151708Sstevel SG_SET_FRU_NAME_DIMM(new_unum, dimm);
10161708Sstevel
1017*11311SSurya.Prakki@Sun.COM (void) strcat(new_unum, " ");
1018*11311SSurya.Prakki@Sun.COM (void) strcat(new_unum, unum);
10191708Sstevel }
10201708Sstevel
1021*11311SSurya.Prakki@Sun.COM (void) strcpy(unum, new_unum);
10221708Sstevel }
10231708Sstevel
10241708Sstevel int
plat_get_cpu_unum(int cpuid,char * buf,int buflen,int * lenp)10251708Sstevel plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
10261708Sstevel {
10271708Sstevel int node = SG_PORTID_TO_NODEID(cpuid);
10281708Sstevel int board = SG_CPU_BD_PORTID_TO_BD_NUM(cpuid);
10291708Sstevel
10301708Sstevel if (snprintf(buf, buflen, "/N%d/%s%d", node,
10311708Sstevel SG_HPU_TYPE_CPU_BOARD_ID, board) >= buflen) {
10321708Sstevel return (ENOSPC);
10331708Sstevel } else {
10341708Sstevel *lenp = strlen(buf);
10351708Sstevel return (0);
10361708Sstevel }
10371708Sstevel }
10381708Sstevel
10391708Sstevel /*
10401708Sstevel * We log all ECC events to the SC so we send a mailbox
10411708Sstevel * message to the SC passing it the relevant data.
10421708Sstevel * ECC mailbox messages are sent via a taskq mechanism to
10431708Sstevel * prevent impaired system performance during ECC floods.
10441708Sstevel * Indictments have already passed through a taskq, so they
10451708Sstevel * are not queued here.
10461708Sstevel */
10471708Sstevel int
plat_send_ecc_mailbox_msg(plat_ecc_message_type_t msg_type,void * datap)10481708Sstevel plat_send_ecc_mailbox_msg(plat_ecc_message_type_t msg_type, void *datap)
10491708Sstevel {
10501708Sstevel sbbc_ecc_mbox_t *msgp;
10511708Sstevel size_t msg_size;
10521708Sstevel uint16_t msg_subtype;
10531708Sstevel int sleep_flag, log_error;
10541708Sstevel
10551708Sstevel if (sg_ecc_taskq_func == NULL) {
10561708Sstevel sg_ecc_taskq_func = (void (*)(sbbc_ecc_mbox_t *))
10571708Sstevel modgetsymvalue("sbbc_mbox_queue_ecc_event", 0);
10581708Sstevel if (sg_ecc_taskq_func == NULL) {
10591708Sstevel cmn_err(CE_NOTE, "!plat_send_ecc_mailbox_msg: "
10601708Sstevel "sbbc_mbox_queue_ecc_event not found");
10611708Sstevel return (ENODEV);
10621708Sstevel }
10631708Sstevel }
10641708Sstevel if (sg_ecc_mbox_func == NULL) {
10651708Sstevel sg_ecc_mbox_func = (int (*)(sbbc_ecc_mbox_t *))
10661708Sstevel modgetsymvalue("sbbc_mbox_ecc_output", 0);
10671708Sstevel if (sg_ecc_mbox_func == NULL) {
10681708Sstevel cmn_err(CE_NOTE, "!plat_send_ecc_mailbox_msg: "
10691708Sstevel "sbbc_mbox_ecc_output not found");
10701708Sstevel return (ENODEV);
10711708Sstevel }
10721708Sstevel }
10731708Sstevel
10741708Sstevel /*
10751708Sstevel * Initialize the request and response structures
10761708Sstevel */
10771708Sstevel switch (msg_type) {
10781708Sstevel case PLAT_ECC_ERROR_MESSAGE:
10791708Sstevel msg_subtype = INFO_MBOX_ERROR_ECC;
10801708Sstevel msg_size = sizeof (plat_ecc_error_data_t);
10811708Sstevel sleep_flag = KM_NOSLEEP;
10821708Sstevel log_error = 1;
10831708Sstevel break;
10841708Sstevel case PLAT_ECC_ERROR2_MESSAGE:
10851708Sstevel msg_subtype = INFO_MBOX_ECC;
10861708Sstevel msg_size = sizeof (plat_ecc_error2_data_t);
10871708Sstevel sleep_flag = KM_NOSLEEP;
10881708Sstevel log_error = 1;
10891708Sstevel break;
10901708Sstevel case PLAT_ECC_INDICTMENT_MESSAGE:
10911708Sstevel msg_subtype = INFO_MBOX_ERROR_INDICT;
10921708Sstevel msg_size = sizeof (plat_ecc_indictment_data_t);
10931708Sstevel sleep_flag = KM_SLEEP;
10941708Sstevel log_error = 0;
10951708Sstevel break;
10961708Sstevel case PLAT_ECC_INDICTMENT2_MESSAGE:
10971708Sstevel msg_subtype = INFO_MBOX_ECC;
10981708Sstevel msg_size = sizeof (plat_ecc_indictment2_data_t);
10991708Sstevel sleep_flag = KM_SLEEP;
11001708Sstevel log_error = 0;
11011708Sstevel break;
11021708Sstevel case PLAT_ECC_CAPABILITY_MESSAGE:
11031708Sstevel msg_subtype = INFO_MBOX_ECC_CAP;
11041708Sstevel msg_size = sizeof (plat_capability_data_t) +
11051708Sstevel strlen(utsname.release) + strlen(utsname.version) + 2;
11061708Sstevel sleep_flag = KM_SLEEP;
11071708Sstevel log_error = 0;
11081708Sstevel break;
11091708Sstevel case PLAT_ECC_DIMM_SID_MESSAGE:
11101708Sstevel msg_subtype = INFO_MBOX_ECC;
11111708Sstevel msg_size = sizeof (plat_dimm_sid_request_data_t);
11121708Sstevel sleep_flag = KM_SLEEP;
11131708Sstevel log_error = 0;
11141708Sstevel break;
11151708Sstevel default:
11161708Sstevel return (EINVAL);
11171708Sstevel }
11181708Sstevel
11191708Sstevel msgp = (sbbc_ecc_mbox_t *)kmem_zalloc(sizeof (sbbc_ecc_mbox_t),
11205648Ssetje sleep_flag);
11211708Sstevel if (msgp == NULL) {
11221708Sstevel cmn_err(CE_NOTE, "!plat_send_ecc_mailbox_msg: "
11235648Ssetje "unable to allocate sbbc_ecc_mbox");
11241708Sstevel return (ENOMEM);
11251708Sstevel }
11261708Sstevel
11271708Sstevel msgp->ecc_log_error = log_error;
11281708Sstevel
11291708Sstevel msgp->ecc_req.msg_type.type = INFO_MBOX;
11301708Sstevel msgp->ecc_req.msg_type.sub_type = msg_subtype;
11311708Sstevel msgp->ecc_req.msg_status = 0;
11321708Sstevel msgp->ecc_req.msg_len = (int)msg_size;
11331708Sstevel msgp->ecc_req.msg_bytes = 0;
11341708Sstevel msgp->ecc_req.msg_buf = (caddr_t)kmem_zalloc(msg_size, sleep_flag);
11351708Sstevel msgp->ecc_req.msg_data[0] = 0;
11361708Sstevel msgp->ecc_req.msg_data[1] = 0;
11371708Sstevel
11381708Sstevel if (msgp->ecc_req.msg_buf == NULL) {
11391708Sstevel cmn_err(CE_NOTE, "!plat_send_ecc_mailbox_msg: "
11405648Ssetje "unable to allocate request msg_buf");
11411708Sstevel kmem_free((void *)msgp, sizeof (sbbc_ecc_mbox_t));
11421708Sstevel return (ENOMEM);
11431708Sstevel }
11441708Sstevel bcopy(datap, (void *)msgp->ecc_req.msg_buf, msg_size);
11451708Sstevel
11461708Sstevel /*
11471708Sstevel * initialize the response back from the SC
11481708Sstevel */
11491708Sstevel msgp->ecc_resp.msg_type.type = INFO_MBOX;
11501708Sstevel msgp->ecc_resp.msg_type.sub_type = msg_subtype;
11511708Sstevel msgp->ecc_resp.msg_status = 0;
11521708Sstevel msgp->ecc_resp.msg_len = 0;
11531708Sstevel msgp->ecc_resp.msg_bytes = 0;
11541708Sstevel msgp->ecc_resp.msg_buf = NULL;
11551708Sstevel msgp->ecc_resp.msg_data[0] = 0;
11561708Sstevel msgp->ecc_resp.msg_data[1] = 0;
11571708Sstevel
11581708Sstevel switch (msg_type) {
11591708Sstevel case PLAT_ECC_ERROR_MESSAGE:
11601708Sstevel case PLAT_ECC_ERROR2_MESSAGE:
11611708Sstevel /*
11621708Sstevel * For Error Messages, we go through a taskq.
11631708Sstevel * Queue up the message for processing
11641708Sstevel */
11651708Sstevel (*sg_ecc_taskq_func)(msgp);
11661708Sstevel return (0);
11671708Sstevel
11681708Sstevel case PLAT_ECC_CAPABILITY_MESSAGE:
11691708Sstevel /*
11701708Sstevel * For indictment and capability messages, we've already gone
11711708Sstevel * through the taskq, so we can call the mailbox routine
11721708Sstevel * directly. Find the symbol for the routine that sends
11731708Sstevel * the mailbox msg
11741708Sstevel */
11751708Sstevel msgp->ecc_resp.msg_len = (int)msg_size;
11761708Sstevel msgp->ecc_resp.msg_buf = (caddr_t)kmem_zalloc(msg_size,
11771708Sstevel sleep_flag);
11781708Sstevel /* FALLTHRU */
11791708Sstevel
11801708Sstevel case PLAT_ECC_INDICTMENT_MESSAGE:
11811708Sstevel case PLAT_ECC_INDICTMENT2_MESSAGE:
11821708Sstevel return ((*sg_ecc_mbox_func)(msgp));
11831708Sstevel
11841708Sstevel case PLAT_ECC_DIMM_SID_MESSAGE:
11851708Sstevel msgp->ecc_resp.msg_len = sizeof (plat_dimm_sid_board_data_t);
11861708Sstevel msgp->ecc_resp.msg_buf = (caddr_t)kmem_zalloc(
11871708Sstevel sizeof (plat_dimm_sid_board_data_t), sleep_flag);
11881708Sstevel return ((*sg_ecc_mbox_func)(msgp));
11891708Sstevel
11901708Sstevel default:
11911708Sstevel ASSERT(0);
11921708Sstevel return (EINVAL);
11931708Sstevel }
11941708Sstevel }
11951708Sstevel
11961708Sstevel /*
11971708Sstevel * m is redundant on serengeti as the multiplier is always 4
11981708Sstevel */
11991708Sstevel /*ARGSUSED*/
12001708Sstevel int
plat_make_fru_cpuid(int sb,int m,int proc)12011708Sstevel plat_make_fru_cpuid(int sb, int m, int proc)
12021708Sstevel {
12031708Sstevel return (MAKE_CPUID(sb, proc));
12041708Sstevel }
12051708Sstevel
12061708Sstevel /*
12071708Sstevel * board number for a given proc
12081708Sstevel */
12091708Sstevel int
plat_make_fru_boardnum(int proc)12101708Sstevel plat_make_fru_boardnum(int proc)
12111708Sstevel {
12121708Sstevel return (SG_CPU_BD_PORTID_TO_BD_NUM(proc));
12131708Sstevel }
12141708Sstevel
12151708Sstevel static
12161708Sstevel void
cpu_sgn_update(ushort_t sig,uchar_t state,uchar_t sub_state,int cpuid)12171708Sstevel cpu_sgn_update(ushort_t sig, uchar_t state, uchar_t sub_state, int cpuid)
12181708Sstevel {
12191708Sstevel uint32_t signature = CPU_SIG_BLD(sig, state, sub_state);
12201708Sstevel sig_state_t current_sgn;
12211708Sstevel int i;
12221708Sstevel
12231708Sstevel if (iosram_write_ptr == NULL) {
12241708Sstevel /*
12251708Sstevel * If the IOSRAM write pointer isn't set, we won't be able
12261708Sstevel * to write signatures to ANYTHING, so we may as well just
12271708Sstevel * write out an error message (if desired) and exit this
12281708Sstevel * routine now...
12291708Sstevel */
12301708Sstevel DCMNERR(CE_WARN,
12311708Sstevel "cpu_sgn_update: iosram_write() not found;"
12321708Sstevel " cannot write signature 0x%x for CPU(s) or domain\n",
12331708Sstevel signature);
12341708Sstevel return;
12351708Sstevel }
12361708Sstevel
12371708Sstevel
12381708Sstevel /*
12391708Sstevel * Differentiate a panic reboot from a non-panic reboot in the
12401708Sstevel * setting of the substate of the signature.
12411708Sstevel *
12421708Sstevel * If the new substate is REBOOT and we're rebooting due to a panic,
12431708Sstevel * then set the new substate to a special value indicating a panic
12441708Sstevel * reboot, SIGSUBST_PANIC_REBOOT.
12451708Sstevel *
12461708Sstevel * A panic reboot is detected by a current (previous) domain signature
12471708Sstevel * state of SIGST_EXIT, and a new signature substate of SIGSUBST_REBOOT.
12481708Sstevel * The domain signature state SIGST_EXIT is used as the panic flow
12491708Sstevel * progresses.
12501708Sstevel *
12511708Sstevel * At the end of the panic flow, the reboot occurs but we should now
12521708Sstevel * one that was involuntary, something that may be quite useful to know
12531708Sstevel * at OBP level.
12541708Sstevel */
12551708Sstevel if (sub_state == SIGSUBST_REBOOT) {
12561708Sstevel if (iosram_read_ptr == NULL) {
12571708Sstevel DCMNERR(CE_WARN,
12581708Sstevel "cpu_sgn_update: iosram_read() not found;"
12591708Sstevel " could not check current domain signature\n");
12601708Sstevel } else {
12611708Sstevel (void) (*iosram_read_ptr)(SBBC_SIGBLCK_KEY,
12625648Ssetje SG_SGNBLK_DOMAINSIG_OFFSET,
12635648Ssetje (char *)¤t_sgn, sizeof (current_sgn));
12641708Sstevel if (current_sgn.state_t.state == SIGST_EXIT)
12651708Sstevel signature = CPU_SIG_BLD(sig, state,
12665648Ssetje SIGSUBST_PANIC_REBOOT);
12671708Sstevel }
12681708Sstevel }
12691708Sstevel
12701708Sstevel /*
12711708Sstevel * cpuid == -1 indicates that the operation applies to all cpus.
12721708Sstevel */
12731708Sstevel if (cpuid >= 0) {
12741708Sstevel (void) (*iosram_write_ptr)(SBBC_SIGBLCK_KEY,
12755648Ssetje SG_SGNBLK_CPUSIG_OFFSET(cpuid), (char *)&signature,
12765648Ssetje sizeof (signature));
12771708Sstevel } else {
12781708Sstevel for (i = 0; i < NCPU; i++) {
12791708Sstevel if (cpu[i] == NULL || !(cpu[i]->cpu_flags &
12805648Ssetje (CPU_EXISTS|CPU_QUIESCED))) {
12811708Sstevel continue;
12821708Sstevel }
12831708Sstevel (void) (*iosram_write_ptr)(SBBC_SIGBLCK_KEY,
12845648Ssetje SG_SGNBLK_CPUSIG_OFFSET(i), (char *)&signature,
12855648Ssetje sizeof (signature));
12861708Sstevel }
12871708Sstevel }
12881708Sstevel
12891708Sstevel if (state == SIGST_OFFLINE || state == SIGST_DETACHED) {
12901708Sstevel return;
12911708Sstevel }
12921708Sstevel
12931708Sstevel (void) (*iosram_write_ptr)(SBBC_SIGBLCK_KEY,
12945648Ssetje SG_SGNBLK_DOMAINSIG_OFFSET, (char *)&signature,
12955648Ssetje sizeof (signature));
12961708Sstevel }
12971708Sstevel
12981708Sstevel void
startup_platform(void)12991708Sstevel startup_platform(void)
13001708Sstevel {
13015834Spt157919 /* set per-platform constants for mutex backoff */
13025834Spt157919 mutex_backoff_base = 1;
13035834Spt157919 mutex_cap_factor = 32;
13041708Sstevel }
13051708Sstevel
13061708Sstevel /*
13071708Sstevel * A routine to convert a number (represented as a string) to
13081708Sstevel * the integer value it represents.
13091708Sstevel */
13101708Sstevel
13111708Sstevel static int
isdigit(int ch)13121708Sstevel isdigit(int ch)
13131708Sstevel {
13141708Sstevel return (ch >= '0' && ch <= '9');
13151708Sstevel }
13161708Sstevel
13171708Sstevel #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
13181708Sstevel
13191708Sstevel static int
strtoi(char * p,char ** pos)13201708Sstevel strtoi(char *p, char **pos)
13211708Sstevel {
13221708Sstevel int n;
13231708Sstevel int c, neg = 0;
13241708Sstevel
13251708Sstevel if (!isdigit(c = *p)) {
13261708Sstevel while (isspace(c))
13271708Sstevel c = *++p;
13281708Sstevel switch (c) {
13291708Sstevel case '-':
13301708Sstevel neg++;
13311708Sstevel /* FALLTHROUGH */
13321708Sstevel case '+':
13331708Sstevel c = *++p;
13341708Sstevel }
13351708Sstevel if (!isdigit(c)) {
13361708Sstevel if (pos != NULL)
13371708Sstevel *pos = p;
13381708Sstevel return (0);
13391708Sstevel }
13401708Sstevel }
13411708Sstevel for (n = '0' - c; isdigit(c = *++p); ) {
13421708Sstevel n *= 10; /* two steps to avoid unnecessary overflow */
13431708Sstevel n += '0' - c; /* accum neg to avoid surprises at MAX */
13441708Sstevel }
13451708Sstevel if (pos != NULL)
13461708Sstevel *pos = p;
13471708Sstevel return (neg ? n : -n);
13481708Sstevel }
13491708Sstevel
13501708Sstevel /*
13511708Sstevel * Get the three parts of the Serengeti PROM version.
13521708Sstevel * Used for feature readiness tests.
13531708Sstevel *
13541708Sstevel * Return 0 if version extracted successfully, -1 otherwise.
13551708Sstevel */
13561708Sstevel
13571708Sstevel int
sg_get_prom_version(int * sysp,int * intfp,int * bldp)13581708Sstevel sg_get_prom_version(int *sysp, int *intfp, int *bldp)
13591708Sstevel {
13601708Sstevel int plen;
13611708Sstevel char vers[512];
13621708Sstevel static pnode_t node;
13631708Sstevel static char version[] = "version";
13641708Sstevel char *verp, *ep;
13651708Sstevel
13661708Sstevel node = prom_finddevice("/openprom");
13671708Sstevel if (node == OBP_BADNODE)
13681708Sstevel return (-1);
13691708Sstevel
13701708Sstevel plen = prom_getproplen(node, version);
13711708Sstevel if (plen <= 0 || plen >= sizeof (vers))
13721708Sstevel return (-1);
13731708Sstevel (void) prom_getprop(node, version, vers);
13741708Sstevel vers[plen] = '\0';
13751708Sstevel
13761708Sstevel /* Make sure it's an OBP flashprom */
13771708Sstevel if (vers[0] != 'O' && vers[1] != 'B' && vers[2] != 'P') {
13781708Sstevel cmn_err(CE_WARN, "sg_get_prom_version: "
13791708Sstevel "unknown <version> string in </openprom>\n");
13801708Sstevel return (-1);
13811708Sstevel }
13821708Sstevel verp = &vers[4];
13831708Sstevel
13841708Sstevel *sysp = strtoi(verp, &ep);
13851708Sstevel if (ep == verp || *ep != '.')
13861708Sstevel return (-1);
13871708Sstevel verp = ep + 1;
13881708Sstevel
13891708Sstevel *intfp = strtoi(verp, &ep);
13901708Sstevel if (ep == verp || *ep != '.')
13911708Sstevel return (-1);
13921708Sstevel verp = ep + 1;
13931708Sstevel
13941708Sstevel *bldp = strtoi(verp, &ep);
13951708Sstevel if (ep == verp || (*ep != '\0' && !isspace(*ep)))
13961708Sstevel return (-1);
13971708Sstevel return (0);
13981708Sstevel }
13991708Sstevel
14001708Sstevel /*
14011708Sstevel * Return 0 if system board Dynamic Reconfiguration
14021708Sstevel * is supported by the firmware, -1 otherwise.
14031708Sstevel */
14041708Sstevel int
sg_prom_sb_dr_check(void)14051708Sstevel sg_prom_sb_dr_check(void)
14061708Sstevel {
14071708Sstevel static int prom_res = 1;
14081708Sstevel
14091708Sstevel if (prom_res == 1) {
14101708Sstevel int sys, intf, bld;
14111708Sstevel int rv;
14121708Sstevel
14131708Sstevel rv = sg_get_prom_version(&sys, &intf, &bld);
14141708Sstevel if (rv == 0 && sys == 5 &&
14151708Sstevel (intf >= 12 || (intf == 11 && bld >= 200))) {
14161708Sstevel prom_res = 0;
14171708Sstevel } else {
14181708Sstevel prom_res = -1;
14191708Sstevel }
14201708Sstevel }
14211708Sstevel return (prom_res);
14221708Sstevel }
14231708Sstevel
14241708Sstevel /*
14251708Sstevel * Return 0 if cPCI Dynamic Reconfiguration
14261708Sstevel * is supported by the firmware, -1 otherwise.
14271708Sstevel */
14281708Sstevel int
sg_prom_cpci_dr_check(void)14291708Sstevel sg_prom_cpci_dr_check(void)
14301708Sstevel {
14311708Sstevel /*
14321708Sstevel * The version check is currently the same as for
14331708Sstevel * system boards. Since the two DR sub-systems are
14341708Sstevel * independent, this could change.
14351708Sstevel */
14361708Sstevel return (sg_prom_sb_dr_check());
14371708Sstevel }
14381708Sstevel
14391708Sstevel /*
14401708Sstevel * KDI functions - used by the in-situ kernel debugger (kmdb) to perform
14411708Sstevel * platform-specific operations. These functions execute when the world is
14421708Sstevel * stopped, and as such cannot make any blocking calls, hold locks, etc.
14431708Sstevel * promif functions are a special case, and may be used.
14441708Sstevel */
14451708Sstevel
14461708Sstevel /*
14471708Sstevel * Our implementation of this KDI op updates the CPU signature in the system
14481708Sstevel * controller. Note that we set the signature to OBP_SIG, rather than DBG_SIG.
14491708Sstevel * The Forth words we execute will, among other things, transform our OBP_SIG
14501708Sstevel * into DBG_SIG. They won't function properly if we try to use DBG_SIG.
14511708Sstevel */
14521708Sstevel static void
sg_system_claim(void)14531708Sstevel sg_system_claim(void)
14541708Sstevel {
145511066Srafael.vanoni@sun.com lbolt_debug_entry();
145611066Srafael.vanoni@sun.com
14571708Sstevel prom_interpret("sigb-sig! my-sigb-sig!", OBP_SIG, OBP_SIG, 0, 0, 0);
14581708Sstevel }
14591708Sstevel
14601708Sstevel static void
sg_system_release(void)14611708Sstevel sg_system_release(void)
14621708Sstevel {
14631708Sstevel prom_interpret("sigb-sig! my-sigb-sig!", OS_SIG, OS_SIG, 0, 0, 0);
146411066Srafael.vanoni@sun.com
146511066Srafael.vanoni@sun.com lbolt_debug_return();
14661708Sstevel }
14671708Sstevel
14681708Sstevel static void
sg_console_claim(void)14691708Sstevel sg_console_claim(void)
14701708Sstevel {
1471*11311SSurya.Prakki@Sun.COM (void) prom_serengeti_set_console_input(SGCN_OBP_STR);
14721708Sstevel }
14731708Sstevel
14741708Sstevel static void
sg_console_release(void)14751708Sstevel sg_console_release(void)
14761708Sstevel {
1477*11311SSurya.Prakki@Sun.COM (void) prom_serengeti_set_console_input(SGCN_CLNT_STR);
14781708Sstevel }
14791708Sstevel
14801708Sstevel void
plat_kdi_init(kdi_t * kdi)14811708Sstevel plat_kdi_init(kdi_t *kdi)
14821708Sstevel {
14831708Sstevel kdi->pkdi_system_claim = sg_system_claim;
14841708Sstevel kdi->pkdi_system_release = sg_system_release;
14851708Sstevel kdi->pkdi_console_claim = sg_console_claim;
14861708Sstevel kdi->pkdi_console_release = sg_console_release;
14871708Sstevel }
1488