125cf1a30Sjl /* 225cf1a30Sjl * CDDL HEADER START 325cf1a30Sjl * 425cf1a30Sjl * The contents of this file are subject to the terms of the 525cf1a30Sjl * Common Development and Distribution License (the "License"). 625cf1a30Sjl * You may not use this file except in compliance with the License. 725cf1a30Sjl * 825cf1a30Sjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 925cf1a30Sjl * or http://www.opensolaris.org/os/licensing. 1025cf1a30Sjl * See the License for the specific language governing permissions 1125cf1a30Sjl * and limitations under the License. 1225cf1a30Sjl * 1325cf1a30Sjl * When distributing Covered Code, include this CDDL HEADER in each 1425cf1a30Sjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1525cf1a30Sjl * If applicable, add the following below this CDDL HEADER, with the 1625cf1a30Sjl * fields enclosed by brackets "[]" replaced with your own identifying 1725cf1a30Sjl * information: Portions Copyright [yyyy] [name of copyright owner] 1825cf1a30Sjl * 1925cf1a30Sjl * CDDL HEADER END 2025cf1a30Sjl */ 2125cf1a30Sjl /* 2225cf1a30Sjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2325cf1a30Sjl * Use is subject to license terms. 2425cf1a30Sjl */ 2525cf1a30Sjl 2625cf1a30Sjl #pragma ident "%Z%%M% %I% %E% SMI" 2725cf1a30Sjl 2825cf1a30Sjl #include <sys/cpuvar.h> 2925cf1a30Sjl #include <sys/systm.h> 3025cf1a30Sjl #include <sys/sysmacros.h> 3125cf1a30Sjl #include <sys/promif.h> 3225cf1a30Sjl #include <sys/platform_module.h> 3325cf1a30Sjl #include <sys/cmn_err.h> 3425cf1a30Sjl #include <sys/errno.h> 3525cf1a30Sjl #include <sys/machsystm.h> 3625cf1a30Sjl #include <sys/bootconf.h> 3725cf1a30Sjl #include <sys/nvpair.h> 3825cf1a30Sjl #include <sys/kobj.h> 3925cf1a30Sjl #include <sys/mem_cage.h> 4025cf1a30Sjl #include <sys/opl.h> 4125cf1a30Sjl #include <sys/scfd/scfostoescf.h> 4225cf1a30Sjl #include <sys/cpu_sgnblk_defs.h> 4325cf1a30Sjl #include <sys/utsname.h> 4425cf1a30Sjl #include <sys/ddi.h> 4525cf1a30Sjl #include <sys/sunndi.h> 4625cf1a30Sjl #include <sys/lgrp.h> 4725cf1a30Sjl #include <sys/memnode.h> 4825cf1a30Sjl #include <sys/sysmacros.h> 4925cf1a30Sjl #include <vm/vm_dep.h> 5025cf1a30Sjl 5125cf1a30Sjl int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *); 520cc8ae86Sav int (*opl_get_mem_sid)(char *unum, char *buf, int buflen, int *lenp); 530cc8ae86Sav int (*opl_get_mem_offset)(uint64_t paddr, uint64_t *offp); 540cc8ae86Sav int (*opl_get_mem_addr)(char *unum, char *sid, 550cc8ae86Sav uint64_t offset, uint64_t *paddr); 5625cf1a30Sjl 5725cf1a30Sjl /* Memory for fcode claims. 16k times # maximum possible IO units */ 5825cf1a30Sjl #define EFCODE_SIZE (OPL_MAX_BOARDS * OPL_MAX_IO_UNITS_PER_BOARD * 0x4000) 5925cf1a30Sjl int efcode_size = EFCODE_SIZE; 6025cf1a30Sjl 6125cf1a30Sjl #define OPL_MC_MEMBOARD_SHIFT 38 /* Boards on 256BG boundary */ 6225cf1a30Sjl 6325cf1a30Sjl /* Set the maximum number of boards for DR */ 6425cf1a30Sjl int opl_boards = OPL_MAX_BOARDS; 6525cf1a30Sjl 6625cf1a30Sjl void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t); 6725cf1a30Sjl 6825cf1a30Sjl extern int tsb_lgrp_affinity; 6925cf1a30Sjl 7025cf1a30Sjl int opl_tsb_spares = (OPL_MAX_BOARDS) * (OPL_MAX_PCICH_UNITS_PER_BOARD) * 7125cf1a30Sjl (OPL_MAX_TSBS_PER_PCICH); 7225cf1a30Sjl 7325cf1a30Sjl pgcnt_t opl_startup_cage_size = 0; 7425cf1a30Sjl 75*1e2e7a75Shuah static opl_model_info_t opl_models[] = { 76*1e2e7a75Shuah { "FF1", OPL_MAX_BOARDS_FF1 }, 77*1e2e7a75Shuah { "FF2", OPL_MAX_BOARDS_FF2 }, 78*1e2e7a75Shuah { "DC1", OPL_MAX_BOARDS_DC1 }, 79*1e2e7a75Shuah { "DC2", OPL_MAX_BOARDS_DC2 }, 80*1e2e7a75Shuah { "DC3", OPL_MAX_BOARDS_DC3 }, 81*1e2e7a75Shuah }; 82*1e2e7a75Shuah static int opl_num_models = sizeof (opl_models)/sizeof (opl_model_info_t); 83*1e2e7a75Shuah 84*1e2e7a75Shuah static opl_model_info_t *opl_cur_model = NULL; 85*1e2e7a75Shuah 8625cf1a30Sjl static struct memlist *opl_memlist_per_board(struct memlist *ml); 8725cf1a30Sjl 880cc8ae86Sav static enum { 890cc8ae86Sav MODEL_FF1 = 0, 900cc8ae86Sav MODEL_FF2 = 1, 910cc8ae86Sav MODEL_DC = 2 920cc8ae86Sav } plat_model = -1; 930cc8ae86Sav 9425cf1a30Sjl int 9525cf1a30Sjl set_platform_max_ncpus(void) 9625cf1a30Sjl { 9725cf1a30Sjl return (OPL_MAX_CPU_PER_BOARD * OPL_MAX_BOARDS); 9825cf1a30Sjl } 9925cf1a30Sjl 10025cf1a30Sjl int 10125cf1a30Sjl set_platform_tsb_spares(void) 10225cf1a30Sjl { 10325cf1a30Sjl return (MIN(opl_tsb_spares, MAX_UPA)); 10425cf1a30Sjl } 10525cf1a30Sjl 106*1e2e7a75Shuah static void 107*1e2e7a75Shuah set_model_info() 108*1e2e7a75Shuah { 109*1e2e7a75Shuah char name[MAXSYSNAME]; 110*1e2e7a75Shuah int i; 111*1e2e7a75Shuah 112*1e2e7a75Shuah /* 113*1e2e7a75Shuah * Get model name from the root node. 114*1e2e7a75Shuah * 115*1e2e7a75Shuah * We are using the prom device tree since, at this point, 116*1e2e7a75Shuah * the Solaris device tree is not yet setup. 117*1e2e7a75Shuah */ 118*1e2e7a75Shuah (void) prom_getprop(prom_rootnode(), "model", (caddr_t)name); 119*1e2e7a75Shuah 120*1e2e7a75Shuah for (i = 0; i < opl_num_models; i++) { 121*1e2e7a75Shuah if (strncmp(name, opl_models[i].model_name, MAXSYSNAME) == 0) { 122*1e2e7a75Shuah opl_cur_model = &opl_models[i]; 123*1e2e7a75Shuah break; 124*1e2e7a75Shuah } 125*1e2e7a75Shuah } 126*1e2e7a75Shuah if (i == opl_num_models) 127*1e2e7a75Shuah cmn_err(CE_WARN, "No valid OPL model is found!" 128*1e2e7a75Shuah "Set max_mmu_ctxdoms to the default."); 129*1e2e7a75Shuah } 130*1e2e7a75Shuah 131*1e2e7a75Shuah static void 132*1e2e7a75Shuah set_max_mmu_ctxdoms() 133*1e2e7a75Shuah { 134*1e2e7a75Shuah extern uint_t max_mmu_ctxdoms; 135*1e2e7a75Shuah int max_boards; 136*1e2e7a75Shuah 137*1e2e7a75Shuah /* 138*1e2e7a75Shuah * From the model, get the maximum number of boards 139*1e2e7a75Shuah * supported and set the value accordingly. If the model 140*1e2e7a75Shuah * could not be determined or recognized, we assume the max value. 141*1e2e7a75Shuah */ 142*1e2e7a75Shuah if (opl_cur_model == NULL) 143*1e2e7a75Shuah max_boards = OPL_MAX_BOARDS; 144*1e2e7a75Shuah else 145*1e2e7a75Shuah max_boards = opl_cur_model->model_max_boards; 146*1e2e7a75Shuah 147*1e2e7a75Shuah /* 148*1e2e7a75Shuah * On OPL, cores and MMUs are one-to-one. 149*1e2e7a75Shuah */ 150*1e2e7a75Shuah max_mmu_ctxdoms = OPL_MAX_CORE_UNITS_PER_BOARD * max_boards; 151*1e2e7a75Shuah } 152*1e2e7a75Shuah 15325cf1a30Sjl #pragma weak mmu_init_large_pages 15425cf1a30Sjl 15525cf1a30Sjl void 15625cf1a30Sjl set_platform_defaults(void) 15725cf1a30Sjl { 15825cf1a30Sjl extern char *tod_module_name; 15925cf1a30Sjl extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); 16025cf1a30Sjl extern int ts_dispatch_extended; 16125cf1a30Sjl extern void mmu_init_large_pages(size_t); 16225cf1a30Sjl 16325cf1a30Sjl /* Set the CPU signature function pointer */ 16425cf1a30Sjl cpu_sgn_func = cpu_sgn_update; 16525cf1a30Sjl 16625cf1a30Sjl /* Set appropriate tod module for OPL platform */ 16725cf1a30Sjl ASSERT(tod_module_name == NULL); 16825cf1a30Sjl tod_module_name = "todopl"; 16925cf1a30Sjl 17025cf1a30Sjl /* 17125cf1a30Sjl * Use the alternate TS dispatch table, which is better tuned 17225cf1a30Sjl * for large servers. 17325cf1a30Sjl */ 17425cf1a30Sjl if (ts_dispatch_extended == -1) 17525cf1a30Sjl ts_dispatch_extended = 1; 17625cf1a30Sjl 17725cf1a30Sjl if ((mmu_page_sizes == max_mmu_page_sizes) && 17825cf1a30Sjl (mmu_ism_pagesize != MMU_PAGESIZE32M)) { 17925cf1a30Sjl if (&mmu_init_large_pages) 18025cf1a30Sjl mmu_init_large_pages(mmu_ism_pagesize); 18125cf1a30Sjl } 18225cf1a30Sjl 18325cf1a30Sjl tsb_lgrp_affinity = 1; 184*1e2e7a75Shuah 185*1e2e7a75Shuah set_model_info(); 186*1e2e7a75Shuah set_max_mmu_ctxdoms(); 18725cf1a30Sjl } 18825cf1a30Sjl 18925cf1a30Sjl /* 19025cf1a30Sjl * Convert logical a board number to a physical one. 19125cf1a30Sjl */ 19225cf1a30Sjl 19325cf1a30Sjl #define LSBPROP "board#" 19425cf1a30Sjl #define PSBPROP "physical-board#" 19525cf1a30Sjl 19625cf1a30Sjl int 19725cf1a30Sjl opl_get_physical_board(int id) 19825cf1a30Sjl { 19925cf1a30Sjl dev_info_t *root_dip, *dip = NULL; 20025cf1a30Sjl char *dname = NULL; 20125cf1a30Sjl int circ; 20225cf1a30Sjl 20325cf1a30Sjl pnode_t pnode; 20425cf1a30Sjl char pname[MAXSYSNAME] = {0}; 20525cf1a30Sjl 20625cf1a30Sjl int lsb_id; /* Logical System Board ID */ 20725cf1a30Sjl int psb_id; /* Physical System Board ID */ 20825cf1a30Sjl 20925cf1a30Sjl 21025cf1a30Sjl /* 21125cf1a30Sjl * This function is called on early stage of bootup when the 21225cf1a30Sjl * kernel device tree is not initialized yet, and also 21325cf1a30Sjl * later on when the device tree is up. We want to try 21425cf1a30Sjl * the fast track first. 21525cf1a30Sjl */ 21625cf1a30Sjl root_dip = ddi_root_node(); 21725cf1a30Sjl if (root_dip) { 21825cf1a30Sjl /* Get from devinfo node */ 21925cf1a30Sjl ndi_devi_enter(root_dip, &circ); 22025cf1a30Sjl for (dip = ddi_get_child(root_dip); dip; 22125cf1a30Sjl dip = ddi_get_next_sibling(dip)) { 22225cf1a30Sjl 22325cf1a30Sjl dname = ddi_node_name(dip); 22425cf1a30Sjl if (strncmp(dname, "pseudo-mc", 9) != 0) 22525cf1a30Sjl continue; 22625cf1a30Sjl 22725cf1a30Sjl if ((lsb_id = (int)ddi_getprop(DDI_DEV_T_ANY, dip, 22825cf1a30Sjl DDI_PROP_DONTPASS, LSBPROP, -1)) == -1) 22925cf1a30Sjl continue; 23025cf1a30Sjl 23125cf1a30Sjl if (id == lsb_id) { 23225cf1a30Sjl if ((psb_id = (int)ddi_getprop(DDI_DEV_T_ANY, 23325cf1a30Sjl dip, DDI_PROP_DONTPASS, PSBPROP, -1)) 23425cf1a30Sjl == -1) { 23525cf1a30Sjl ndi_devi_exit(root_dip, circ); 23625cf1a30Sjl return (-1); 23725cf1a30Sjl } else { 23825cf1a30Sjl ndi_devi_exit(root_dip, circ); 23925cf1a30Sjl return (psb_id); 24025cf1a30Sjl } 24125cf1a30Sjl } 24225cf1a30Sjl } 24325cf1a30Sjl ndi_devi_exit(root_dip, circ); 24425cf1a30Sjl } 24525cf1a30Sjl 24625cf1a30Sjl /* 24725cf1a30Sjl * We do not have the kernel device tree, or we did not 24825cf1a30Sjl * find the node for some reason (let's say the kernel 24925cf1a30Sjl * device tree was modified), let's try the OBP tree. 25025cf1a30Sjl */ 25125cf1a30Sjl pnode = prom_rootnode(); 25225cf1a30Sjl for (pnode = prom_childnode(pnode); pnode; 25325cf1a30Sjl pnode = prom_nextnode(pnode)) { 25425cf1a30Sjl 25525cf1a30Sjl if ((prom_getprop(pnode, "name", (caddr_t)pname) == -1) || 25625cf1a30Sjl (strncmp(pname, "pseudo-mc", 9) != 0)) 25725cf1a30Sjl continue; 25825cf1a30Sjl 25925cf1a30Sjl if (prom_getprop(pnode, LSBPROP, (caddr_t)&lsb_id) == -1) 26025cf1a30Sjl continue; 26125cf1a30Sjl 26225cf1a30Sjl if (id == lsb_id) { 26325cf1a30Sjl if (prom_getprop(pnode, PSBPROP, 26425cf1a30Sjl (caddr_t)&psb_id) == -1) { 26525cf1a30Sjl return (-1); 26625cf1a30Sjl } else { 26725cf1a30Sjl return (psb_id); 26825cf1a30Sjl } 26925cf1a30Sjl } 27025cf1a30Sjl } 27125cf1a30Sjl 27225cf1a30Sjl return (-1); 27325cf1a30Sjl } 27425cf1a30Sjl 27525cf1a30Sjl /* 27625cf1a30Sjl * For OPL it's possible that memory from two or more successive boards 27725cf1a30Sjl * will be contiguous across the boards, and therefore represented as a 27825cf1a30Sjl * single chunk. 27925cf1a30Sjl * This function splits such chunks down the board boundaries. 28025cf1a30Sjl */ 28125cf1a30Sjl static struct memlist * 28225cf1a30Sjl opl_memlist_per_board(struct memlist *ml) 28325cf1a30Sjl { 28425cf1a30Sjl uint64_t ssize, low, high, boundary; 28525cf1a30Sjl struct memlist *head, *tail, *new; 28625cf1a30Sjl 28725cf1a30Sjl ssize = (1ull << OPL_MC_MEMBOARD_SHIFT); 28825cf1a30Sjl 28925cf1a30Sjl head = tail = NULL; 29025cf1a30Sjl 29125cf1a30Sjl for (; ml; ml = ml->next) { 29225cf1a30Sjl low = (uint64_t)ml->address; 29325cf1a30Sjl high = low+(uint64_t)(ml->size); 29425cf1a30Sjl while (low < high) { 29525cf1a30Sjl boundary = roundup(low+1, ssize); 29625cf1a30Sjl boundary = MIN(high, boundary); 29725cf1a30Sjl new = kmem_zalloc(sizeof (struct memlist), KM_SLEEP); 29825cf1a30Sjl new->address = low; 29925cf1a30Sjl new->size = boundary - low; 30025cf1a30Sjl if (head == NULL) 30125cf1a30Sjl head = new; 30225cf1a30Sjl if (tail) { 30325cf1a30Sjl tail->next = new; 30425cf1a30Sjl new->prev = tail; 30525cf1a30Sjl } 30625cf1a30Sjl tail = new; 30725cf1a30Sjl low = boundary; 30825cf1a30Sjl } 30925cf1a30Sjl } 31025cf1a30Sjl return (head); 31125cf1a30Sjl } 31225cf1a30Sjl 31325cf1a30Sjl void 31425cf1a30Sjl set_platform_cage_params(void) 31525cf1a30Sjl { 31625cf1a30Sjl extern pgcnt_t total_pages; 31725cf1a30Sjl extern struct memlist *phys_avail; 31825cf1a30Sjl struct memlist *ml, *tml; 31925cf1a30Sjl int ret; 32025cf1a30Sjl 32125cf1a30Sjl if (kernel_cage_enable) { 32225cf1a30Sjl pgcnt_t preferred_cage_size; 32325cf1a30Sjl 32425cf1a30Sjl preferred_cage_size = 32525cf1a30Sjl MAX(opl_startup_cage_size, total_pages / 256); 32625cf1a30Sjl 32725cf1a30Sjl ml = opl_memlist_per_board(phys_avail); 32825cf1a30Sjl 32925cf1a30Sjl kcage_range_lock(); 33025cf1a30Sjl /* 33125cf1a30Sjl * Note: we are assuming that post has load the 33225cf1a30Sjl * whole show in to the high end of memory. Having 33325cf1a30Sjl * taken this leap, we copy the whole of phys_avail 33425cf1a30Sjl * the glist and arrange for the cage to grow 33525cf1a30Sjl * downward (descending pfns). 33625cf1a30Sjl */ 33725cf1a30Sjl ret = kcage_range_init(ml, 1); 33825cf1a30Sjl 33925cf1a30Sjl /* free the memlist */ 34025cf1a30Sjl do { 34125cf1a30Sjl tml = ml->next; 34225cf1a30Sjl kmem_free(ml, sizeof (struct memlist)); 34325cf1a30Sjl ml = tml; 34425cf1a30Sjl } while (ml != NULL); 34525cf1a30Sjl 34625cf1a30Sjl if (ret == 0) 34725cf1a30Sjl kcage_init(preferred_cage_size); 34825cf1a30Sjl kcage_range_unlock(); 34925cf1a30Sjl } 35025cf1a30Sjl 35125cf1a30Sjl if (kcage_on) 35225cf1a30Sjl cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED"); 35325cf1a30Sjl else 35425cf1a30Sjl cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED"); 35525cf1a30Sjl } 35625cf1a30Sjl 35725cf1a30Sjl /*ARGSUSED*/ 35825cf1a30Sjl int 35925cf1a30Sjl plat_cpu_poweron(struct cpu *cp) 36025cf1a30Sjl { 36125cf1a30Sjl int (*opl_cpu_poweron)(struct cpu *) = NULL; 36225cf1a30Sjl 36325cf1a30Sjl opl_cpu_poweron = 36425cf1a30Sjl (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0); 36525cf1a30Sjl 36625cf1a30Sjl if (opl_cpu_poweron == NULL) 36725cf1a30Sjl return (ENOTSUP); 36825cf1a30Sjl else 36925cf1a30Sjl return ((opl_cpu_poweron)(cp)); 37025cf1a30Sjl 37125cf1a30Sjl } 37225cf1a30Sjl 37325cf1a30Sjl /*ARGSUSED*/ 37425cf1a30Sjl int 37525cf1a30Sjl plat_cpu_poweroff(struct cpu *cp) 37625cf1a30Sjl { 37725cf1a30Sjl int (*opl_cpu_poweroff)(struct cpu *) = NULL; 37825cf1a30Sjl 37925cf1a30Sjl opl_cpu_poweroff = 38025cf1a30Sjl (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0); 38125cf1a30Sjl 38225cf1a30Sjl if (opl_cpu_poweroff == NULL) 38325cf1a30Sjl return (ENOTSUP); 38425cf1a30Sjl else 38525cf1a30Sjl return ((opl_cpu_poweroff)(cp)); 38625cf1a30Sjl 38725cf1a30Sjl } 38825cf1a30Sjl 38925cf1a30Sjl int 39025cf1a30Sjl plat_max_boards(void) 39125cf1a30Sjl { 39225cf1a30Sjl return (OPL_MAX_BOARDS); 39325cf1a30Sjl } 39425cf1a30Sjl 39525cf1a30Sjl int 39625cf1a30Sjl plat_max_cpu_units_per_board(void) 39725cf1a30Sjl { 39825cf1a30Sjl return (OPL_MAX_CPU_PER_BOARD); 39925cf1a30Sjl } 40025cf1a30Sjl 40125cf1a30Sjl int 40225cf1a30Sjl plat_max_mem_units_per_board(void) 40325cf1a30Sjl { 40425cf1a30Sjl return (OPL_MAX_MEM_UNITS_PER_BOARD); 40525cf1a30Sjl } 40625cf1a30Sjl 40725cf1a30Sjl int 40825cf1a30Sjl plat_max_io_units_per_board(void) 40925cf1a30Sjl { 41025cf1a30Sjl return (OPL_MAX_IO_UNITS_PER_BOARD); 41125cf1a30Sjl } 41225cf1a30Sjl 41325cf1a30Sjl int 41425cf1a30Sjl plat_max_cmp_units_per_board(void) 41525cf1a30Sjl { 41625cf1a30Sjl return (OPL_MAX_CMP_UNITS_PER_BOARD); 41725cf1a30Sjl } 41825cf1a30Sjl 41925cf1a30Sjl int 42025cf1a30Sjl plat_max_core_units_per_board(void) 42125cf1a30Sjl { 42225cf1a30Sjl return (OPL_MAX_CORE_UNITS_PER_BOARD); 42325cf1a30Sjl } 42425cf1a30Sjl 42525cf1a30Sjl int 42625cf1a30Sjl plat_pfn_to_mem_node(pfn_t pfn) 42725cf1a30Sjl { 42825cf1a30Sjl return (pfn >> mem_node_pfn_shift); 42925cf1a30Sjl } 43025cf1a30Sjl 43125cf1a30Sjl /* ARGSUSED */ 43225cf1a30Sjl void 43325cf1a30Sjl plat_build_mem_nodes(u_longlong_t *list, size_t nelems) 43425cf1a30Sjl { 43525cf1a30Sjl size_t elem; 43625cf1a30Sjl pfn_t basepfn; 43725cf1a30Sjl pgcnt_t npgs; 43825cf1a30Sjl uint64_t boundary, ssize; 43925cf1a30Sjl uint64_t low, high; 44025cf1a30Sjl 44125cf1a30Sjl /* 44225cf1a30Sjl * OPL mem slices are always aligned on a 256GB boundary. 44325cf1a30Sjl */ 44425cf1a30Sjl mem_node_pfn_shift = OPL_MC_MEMBOARD_SHIFT - MMU_PAGESHIFT; 44525cf1a30Sjl mem_node_physalign = 0; 44625cf1a30Sjl 44725cf1a30Sjl /* 44825cf1a30Sjl * Boot install lists are arranged <addr, len>, <addr, len>, ... 44925cf1a30Sjl */ 45025cf1a30Sjl ssize = (1ull << OPL_MC_MEMBOARD_SHIFT); 45125cf1a30Sjl for (elem = 0; elem < nelems; elem += 2) { 45225cf1a30Sjl low = (uint64_t)list[elem]; 45325cf1a30Sjl high = low+(uint64_t)(list[elem+1]); 45425cf1a30Sjl while (low < high) { 45525cf1a30Sjl boundary = roundup(low+1, ssize); 45625cf1a30Sjl boundary = MIN(high, boundary); 45725cf1a30Sjl basepfn = btop(low); 45825cf1a30Sjl npgs = btop(boundary - low); 45925cf1a30Sjl mem_node_add_slice(basepfn, basepfn + npgs - 1); 46025cf1a30Sjl low = boundary; 46125cf1a30Sjl } 46225cf1a30Sjl } 46325cf1a30Sjl } 46425cf1a30Sjl 46525cf1a30Sjl /* 46625cf1a30Sjl * Find the CPU associated with a slice at boot-time. 46725cf1a30Sjl */ 46825cf1a30Sjl void 46925cf1a30Sjl plat_fill_mc(pnode_t nodeid) 47025cf1a30Sjl { 47125cf1a30Sjl int board; 47225cf1a30Sjl int memnode; 47325cf1a30Sjl struct { 47425cf1a30Sjl uint64_t addr; 47525cf1a30Sjl uint64_t size; 47625cf1a30Sjl } mem_range; 47725cf1a30Sjl 47825cf1a30Sjl if (prom_getprop(nodeid, "board#", (caddr_t)&board) < 0) { 47925cf1a30Sjl panic("Can not find board# property in mc node %x", nodeid); 48025cf1a30Sjl } 48125cf1a30Sjl if (prom_getprop(nodeid, "sb-mem-ranges", (caddr_t)&mem_range) < 0) { 48225cf1a30Sjl panic("Can not find sb-mem-ranges property in mc node %x", 48325cf1a30Sjl nodeid); 48425cf1a30Sjl } 48525cf1a30Sjl memnode = mem_range.addr >> OPL_MC_MEMBOARD_SHIFT; 48625cf1a30Sjl plat_assign_lgrphand_to_mem_node(board, memnode); 48725cf1a30Sjl } 48825cf1a30Sjl 48925cf1a30Sjl /* 49025cf1a30Sjl * Return the platform handle for the lgroup containing the given CPU 49125cf1a30Sjl * 49225cf1a30Sjl * For OPL, lgroup platform handle == board #. 49325cf1a30Sjl */ 49425cf1a30Sjl 49525cf1a30Sjl extern int mpo_disabled; 49625cf1a30Sjl extern lgrp_handle_t lgrp_default_handle; 49725cf1a30Sjl 49825cf1a30Sjl lgrp_handle_t 49925cf1a30Sjl plat_lgrp_cpu_to_hand(processorid_t id) 50025cf1a30Sjl { 50125cf1a30Sjl lgrp_handle_t plathand; 50225cf1a30Sjl 50325cf1a30Sjl /* 50425cf1a30Sjl * Return the real platform handle for the CPU until 50525cf1a30Sjl * such time as we know that MPO should be disabled. 50625cf1a30Sjl * At that point, we set the "mpo_disabled" flag to true, 50725cf1a30Sjl * and from that point on, return the default handle. 50825cf1a30Sjl * 50925cf1a30Sjl * By the time we know that MPO should be disabled, the 51025cf1a30Sjl * first CPU will have already been added to a leaf 51125cf1a30Sjl * lgroup, but that's ok. The common lgroup code will 51225cf1a30Sjl * double check that the boot CPU is in the correct place, 51325cf1a30Sjl * and in the case where mpo should be disabled, will move 51425cf1a30Sjl * it to the root if necessary. 51525cf1a30Sjl */ 51625cf1a30Sjl if (mpo_disabled) { 51725cf1a30Sjl /* If MPO is disabled, return the default (UMA) handle */ 51825cf1a30Sjl plathand = lgrp_default_handle; 51925cf1a30Sjl } else 52025cf1a30Sjl plathand = (lgrp_handle_t)LSB_ID(id); 52125cf1a30Sjl return (plathand); 52225cf1a30Sjl } 52325cf1a30Sjl 52425cf1a30Sjl /* 52525cf1a30Sjl * Platform specific lgroup initialization 52625cf1a30Sjl */ 52725cf1a30Sjl void 52825cf1a30Sjl plat_lgrp_init(void) 52925cf1a30Sjl { 53025cf1a30Sjl extern uint32_t lgrp_expand_proc_thresh; 53125cf1a30Sjl extern uint32_t lgrp_expand_proc_diff; 53225cf1a30Sjl 53325cf1a30Sjl /* 53425cf1a30Sjl * Set tuneables for the OPL architecture 53525cf1a30Sjl * 53625cf1a30Sjl * lgrp_expand_proc_thresh is the minimum load on the lgroups 53725cf1a30Sjl * this process is currently running on before considering 53825cf1a30Sjl * expanding threads to another lgroup. 53925cf1a30Sjl * 54025cf1a30Sjl * lgrp_expand_proc_diff determines how much less the remote lgroup 54125cf1a30Sjl * must be loaded before expanding to it. 54225cf1a30Sjl * 54325cf1a30Sjl * Since remote latencies can be costly, attempt to keep 3 threads 54425cf1a30Sjl * within the same lgroup before expanding to the next lgroup. 54525cf1a30Sjl */ 54625cf1a30Sjl lgrp_expand_proc_thresh = LGRP_LOADAVG_THREAD_MAX * 3; 54725cf1a30Sjl lgrp_expand_proc_diff = LGRP_LOADAVG_THREAD_MAX; 54825cf1a30Sjl } 54925cf1a30Sjl 55025cf1a30Sjl /* 55125cf1a30Sjl * Platform notification of lgroup (re)configuration changes 55225cf1a30Sjl */ 55325cf1a30Sjl /*ARGSUSED*/ 55425cf1a30Sjl void 55525cf1a30Sjl plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg) 55625cf1a30Sjl { 55725cf1a30Sjl update_membounds_t *umb; 55825cf1a30Sjl lgrp_config_mem_rename_t lmr; 55925cf1a30Sjl int sbd, tbd; 56025cf1a30Sjl lgrp_handle_t hand, shand, thand; 56125cf1a30Sjl int mnode, snode, tnode; 56225cf1a30Sjl pfn_t start, end; 56325cf1a30Sjl 56425cf1a30Sjl if (mpo_disabled) 56525cf1a30Sjl return; 56625cf1a30Sjl 56725cf1a30Sjl switch (evt) { 56825cf1a30Sjl 56925cf1a30Sjl case LGRP_CONFIG_MEM_ADD: 57025cf1a30Sjl /* 57125cf1a30Sjl * Establish the lgroup handle to memnode translation. 57225cf1a30Sjl */ 57325cf1a30Sjl umb = (update_membounds_t *)arg; 57425cf1a30Sjl 57525cf1a30Sjl hand = umb->u_board; 57625cf1a30Sjl mnode = plat_pfn_to_mem_node(umb->u_base >> MMU_PAGESHIFT); 57725cf1a30Sjl plat_assign_lgrphand_to_mem_node(hand, mnode); 57825cf1a30Sjl 57925cf1a30Sjl break; 58025cf1a30Sjl 58125cf1a30Sjl case LGRP_CONFIG_MEM_DEL: 58225cf1a30Sjl /* 58325cf1a30Sjl * Special handling for possible memory holes. 58425cf1a30Sjl */ 58525cf1a30Sjl umb = (update_membounds_t *)arg; 58625cf1a30Sjl hand = umb->u_board; 58725cf1a30Sjl if ((mnode = plat_lgrphand_to_mem_node(hand)) != -1) { 58825cf1a30Sjl if (mem_node_config[mnode].exists) { 58925cf1a30Sjl start = mem_node_config[mnode].physbase; 59025cf1a30Sjl end = mem_node_config[mnode].physmax; 59125cf1a30Sjl mem_node_pre_del_slice(start, end); 59225cf1a30Sjl mem_node_post_del_slice(start, end, 0); 59325cf1a30Sjl } 59425cf1a30Sjl } 59525cf1a30Sjl 59625cf1a30Sjl break; 59725cf1a30Sjl 59825cf1a30Sjl case LGRP_CONFIG_MEM_RENAME: 59925cf1a30Sjl /* 60025cf1a30Sjl * During a DR copy-rename operation, all of the memory 60125cf1a30Sjl * on one board is moved to another board -- but the 60225cf1a30Sjl * addresses/pfns and memnodes don't change. This means 60325cf1a30Sjl * the memory has changed locations without changing identity. 60425cf1a30Sjl * 60525cf1a30Sjl * Source is where we are copying from and target is where we 60625cf1a30Sjl * are copying to. After source memnode is copied to target 60725cf1a30Sjl * memnode, the physical addresses of the target memnode are 60825cf1a30Sjl * renamed to match what the source memnode had. Then target 60925cf1a30Sjl * memnode can be removed and source memnode can take its 61025cf1a30Sjl * place. 61125cf1a30Sjl * 61225cf1a30Sjl * To do this, swap the lgroup handle to memnode mappings for 61325cf1a30Sjl * the boards, so target lgroup will have source memnode and 61425cf1a30Sjl * source lgroup will have empty target memnode which is where 61525cf1a30Sjl * its memory will go (if any is added to it later). 61625cf1a30Sjl * 61725cf1a30Sjl * Then source memnode needs to be removed from its lgroup 61825cf1a30Sjl * and added to the target lgroup where the memory was living 61925cf1a30Sjl * but under a different name/memnode. The memory was in the 62025cf1a30Sjl * target memnode and now lives in the source memnode with 62125cf1a30Sjl * different physical addresses even though it is the same 62225cf1a30Sjl * memory. 62325cf1a30Sjl */ 62425cf1a30Sjl sbd = arg & 0xffff; 62525cf1a30Sjl tbd = (arg & 0xffff0000) >> 16; 62625cf1a30Sjl shand = sbd; 62725cf1a30Sjl thand = tbd; 62825cf1a30Sjl snode = plat_lgrphand_to_mem_node(shand); 62925cf1a30Sjl tnode = plat_lgrphand_to_mem_node(thand); 63025cf1a30Sjl 63125cf1a30Sjl /* 63225cf1a30Sjl * Special handling for possible memory holes. 63325cf1a30Sjl */ 63425cf1a30Sjl if (tnode != -1 && mem_node_config[tnode].exists) { 63525cf1a30Sjl start = mem_node_config[mnode].physbase; 63625cf1a30Sjl end = mem_node_config[mnode].physmax; 63725cf1a30Sjl mem_node_pre_del_slice(start, end); 63825cf1a30Sjl mem_node_post_del_slice(start, end, 0); 63925cf1a30Sjl } 64025cf1a30Sjl 64125cf1a30Sjl plat_assign_lgrphand_to_mem_node(thand, snode); 64225cf1a30Sjl plat_assign_lgrphand_to_mem_node(shand, tnode); 64325cf1a30Sjl 64425cf1a30Sjl lmr.lmem_rename_from = shand; 64525cf1a30Sjl lmr.lmem_rename_to = thand; 64625cf1a30Sjl 64725cf1a30Sjl /* 64825cf1a30Sjl * Remove source memnode of copy rename from its lgroup 64925cf1a30Sjl * and add it to its new target lgroup 65025cf1a30Sjl */ 65125cf1a30Sjl lgrp_config(LGRP_CONFIG_MEM_RENAME, (uintptr_t)snode, 65225cf1a30Sjl (uintptr_t)&lmr); 65325cf1a30Sjl 65425cf1a30Sjl break; 65525cf1a30Sjl 65625cf1a30Sjl default: 65725cf1a30Sjl break; 65825cf1a30Sjl } 65925cf1a30Sjl } 66025cf1a30Sjl 66125cf1a30Sjl /* 66225cf1a30Sjl * Return latency between "from" and "to" lgroups 66325cf1a30Sjl * 66425cf1a30Sjl * This latency number can only be used for relative comparison 66525cf1a30Sjl * between lgroups on the running system, cannot be used across platforms, 66625cf1a30Sjl * and may not reflect the actual latency. It is platform and implementation 66725cf1a30Sjl * specific, so platform gets to decide its value. It would be nice if the 66825cf1a30Sjl * number was at least proportional to make comparisons more meaningful though. 66925cf1a30Sjl * NOTE: The numbers below are supposed to be load latencies for uncached 67025cf1a30Sjl * memory divided by 10. 67125cf1a30Sjl * 67225cf1a30Sjl * XXX latency values for Columbus, not Columbus2. Should be fixed later when 67325cf1a30Sjl * we know the actual numbers for Columbus2. 67425cf1a30Sjl */ 67525cf1a30Sjl int 67625cf1a30Sjl plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to) 67725cf1a30Sjl { 67825cf1a30Sjl /* 67925cf1a30Sjl * Return min remote latency when there are more than two lgroups 68025cf1a30Sjl * (root and child) and getting latency between two different lgroups 68125cf1a30Sjl * or root is involved 68225cf1a30Sjl */ 68325cf1a30Sjl if (lgrp_optimizations() && (from != to || 68425cf1a30Sjl from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE)) 68525cf1a30Sjl return (27); 68625cf1a30Sjl else 68725cf1a30Sjl return (25); 68825cf1a30Sjl } 68925cf1a30Sjl 69025cf1a30Sjl /* 69125cf1a30Sjl * Return platform handle for root lgroup 69225cf1a30Sjl */ 69325cf1a30Sjl lgrp_handle_t 69425cf1a30Sjl plat_lgrp_root_hand(void) 69525cf1a30Sjl { 69625cf1a30Sjl if (mpo_disabled) 69725cf1a30Sjl return (lgrp_default_handle); 69825cf1a30Sjl 69925cf1a30Sjl return (LGRP_DEFAULT_HANDLE); 70025cf1a30Sjl } 70125cf1a30Sjl 70225cf1a30Sjl /*ARGSUSED*/ 70325cf1a30Sjl void 70425cf1a30Sjl plat_freelist_process(int mnode) 70525cf1a30Sjl { 70625cf1a30Sjl } 70725cf1a30Sjl 70825cf1a30Sjl void 70925cf1a30Sjl load_platform_drivers(void) 71025cf1a30Sjl { 71125cf1a30Sjl (void) i_ddi_attach_pseudo_node("dr"); 71225cf1a30Sjl } 71325cf1a30Sjl 71425cf1a30Sjl /* 71525cf1a30Sjl * No platform drivers on this platform 71625cf1a30Sjl */ 71725cf1a30Sjl char *platform_module_list[] = { 71825cf1a30Sjl (char *)0 71925cf1a30Sjl }; 72025cf1a30Sjl 72125cf1a30Sjl /*ARGSUSED*/ 72225cf1a30Sjl void 72325cf1a30Sjl plat_tod_fault(enum tod_fault_type tod_bad) 72425cf1a30Sjl { 72525cf1a30Sjl } 72625cf1a30Sjl 72725cf1a30Sjl /*ARGSUSED*/ 72825cf1a30Sjl void 72925cf1a30Sjl cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid) 73025cf1a30Sjl { 73125cf1a30Sjl static void (*scf_panic_callback)(int); 73225cf1a30Sjl static void (*scf_shutdown_callback)(int); 73325cf1a30Sjl 73425cf1a30Sjl /* 73525cf1a30Sjl * This is for notifing system panic/shutdown to SCF. 73625cf1a30Sjl * In case of shutdown and panic, SCF call back 73725cf1a30Sjl * function should be called. 73825cf1a30Sjl * <SCF call back functions> 73925cf1a30Sjl * scf_panic_callb() : panicsys()->panic_quiesce_hw() 74025cf1a30Sjl * scf_shutdown_callb(): halt() or power_down() or reboot_machine() 74125cf1a30Sjl * cpuid should be -1 and state should be SIGST_EXIT. 74225cf1a30Sjl */ 74325cf1a30Sjl if (state == SIGST_EXIT && cpuid == -1) { 74425cf1a30Sjl 74525cf1a30Sjl /* 74625cf1a30Sjl * find the symbol for the SCF panic callback routine in driver 74725cf1a30Sjl */ 74825cf1a30Sjl if (scf_panic_callback == NULL) 74925cf1a30Sjl scf_panic_callback = (void (*)(int)) 75025cf1a30Sjl modgetsymvalue("scf_panic_callb", 0); 75125cf1a30Sjl if (scf_shutdown_callback == NULL) 75225cf1a30Sjl scf_shutdown_callback = (void (*)(int)) 75325cf1a30Sjl modgetsymvalue("scf_shutdown_callb", 0); 75425cf1a30Sjl 75525cf1a30Sjl switch (sub_state) { 75625cf1a30Sjl case SIGSUBST_PANIC: 75725cf1a30Sjl if (scf_panic_callback == NULL) { 75825cf1a30Sjl cmn_err(CE_NOTE, "!cpu_sgn_update: " 75925cf1a30Sjl "scf_panic_callb not found\n"); 76025cf1a30Sjl return; 76125cf1a30Sjl } 76225cf1a30Sjl scf_panic_callback(SIGSUBST_PANIC); 76325cf1a30Sjl break; 76425cf1a30Sjl 76525cf1a30Sjl case SIGSUBST_HALT: 76625cf1a30Sjl if (scf_shutdown_callback == NULL) { 76725cf1a30Sjl cmn_err(CE_NOTE, "!cpu_sgn_update: " 76825cf1a30Sjl "scf_shutdown_callb not found\n"); 76925cf1a30Sjl return; 77025cf1a30Sjl } 77125cf1a30Sjl scf_shutdown_callback(SIGSUBST_HALT); 77225cf1a30Sjl break; 77325cf1a30Sjl 77425cf1a30Sjl case SIGSUBST_ENVIRON: 77525cf1a30Sjl if (scf_shutdown_callback == NULL) { 77625cf1a30Sjl cmn_err(CE_NOTE, "!cpu_sgn_update: " 77725cf1a30Sjl "scf_shutdown_callb not found\n"); 77825cf1a30Sjl return; 77925cf1a30Sjl } 78025cf1a30Sjl scf_shutdown_callback(SIGSUBST_ENVIRON); 78125cf1a30Sjl break; 78225cf1a30Sjl 78325cf1a30Sjl case SIGSUBST_REBOOT: 78425cf1a30Sjl if (scf_shutdown_callback == NULL) { 78525cf1a30Sjl cmn_err(CE_NOTE, "!cpu_sgn_update: " 78625cf1a30Sjl "scf_shutdown_callb not found\n"); 78725cf1a30Sjl return; 78825cf1a30Sjl } 78925cf1a30Sjl scf_shutdown_callback(SIGSUBST_REBOOT); 79025cf1a30Sjl break; 79125cf1a30Sjl } 79225cf1a30Sjl } 79325cf1a30Sjl } 79425cf1a30Sjl 79525cf1a30Sjl /*ARGSUSED*/ 79625cf1a30Sjl int 79725cf1a30Sjl plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id, 79825cf1a30Sjl int flt_in_memory, ushort_t flt_status, 79925cf1a30Sjl char *buf, int buflen, int *lenp) 80025cf1a30Sjl { 80125cf1a30Sjl /* 80225cf1a30Sjl * check if it's a Memory error. 80325cf1a30Sjl */ 80425cf1a30Sjl if (flt_in_memory) { 80525cf1a30Sjl if (opl_get_mem_unum != NULL) { 80625cf1a30Sjl return (opl_get_mem_unum(synd_code, flt_addr, 80725cf1a30Sjl buf, buflen, lenp)); 80825cf1a30Sjl } else { 80925cf1a30Sjl return (ENOTSUP); 81025cf1a30Sjl } 81125cf1a30Sjl } else { 81225cf1a30Sjl return (ENOTSUP); 81325cf1a30Sjl } 81425cf1a30Sjl } 81525cf1a30Sjl 81625cf1a30Sjl /*ARGSUSED*/ 81725cf1a30Sjl int 81825cf1a30Sjl plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp) 81925cf1a30Sjl { 8200cc8ae86Sav int plen; 8210cc8ae86Sav int ret = 0; 8220cc8ae86Sav char model[20]; 8230cc8ae86Sav uint_t sb; 8240cc8ae86Sav pnode_t node; 8250cc8ae86Sav 8260cc8ae86Sav /* determine the platform model once */ 8270cc8ae86Sav if (plat_model == -1) { 8280cc8ae86Sav plat_model = MODEL_DC; /* Default model */ 8290cc8ae86Sav node = prom_rootnode(); 8300cc8ae86Sav plen = prom_getproplen(node, "model"); 8310cc8ae86Sav if (plen > 0 && plen < sizeof (model)) { 8320cc8ae86Sav (void) prom_getprop(node, "model", model); 8330cc8ae86Sav model[plen] = '\0'; 8340cc8ae86Sav if (strcmp(model, "FF1") == 0) 8350cc8ae86Sav plat_model = MODEL_FF1; 8360cc8ae86Sav else if (strcmp(model, "FF2") == 0) 8370cc8ae86Sav plat_model = MODEL_FF2; 8380cc8ae86Sav else if (strncmp(model, "DC", 2) == 0) 8390cc8ae86Sav plat_model = MODEL_DC; 8400cc8ae86Sav } 8410cc8ae86Sav } 84225cf1a30Sjl 84325cf1a30Sjl sb = opl_get_physical_board(LSB_ID(cpuid)); 84425cf1a30Sjl if (sb == -1) { 84525cf1a30Sjl return (ENXIO); 84625cf1a30Sjl } 84725cf1a30Sjl 8480cc8ae86Sav switch (plat_model) { 8490cc8ae86Sav case MODEL_FF1: 8500cc8ae86Sav plen = snprintf(buf, buflen, "/%s/CPUM%d", "MBU_A", 8510cc8ae86Sav CHIP_ID(cpuid) / 2); 8520cc8ae86Sav break; 8530cc8ae86Sav 8540cc8ae86Sav case MODEL_FF2: 8550cc8ae86Sav plen = snprintf(buf, buflen, "/%s/CPUM%d", "MBU_B", 8560cc8ae86Sav CHIP_ID(cpuid) / 2); 8570cc8ae86Sav break; 8580cc8ae86Sav 8590cc8ae86Sav case MODEL_DC: 8600cc8ae86Sav plen = snprintf(buf, buflen, "/%s%02d/CPUM%d", "CMU", sb, 8610cc8ae86Sav CHIP_ID(cpuid)); 8620cc8ae86Sav break; 8630cc8ae86Sav 8640cc8ae86Sav default: 8650cc8ae86Sav /* This should never happen */ 8660cc8ae86Sav return (ENODEV); 8670cc8ae86Sav } 8680cc8ae86Sav 8690cc8ae86Sav if (plen >= buflen) { 8700cc8ae86Sav ret = ENOSPC; 87125cf1a30Sjl } else { 87225cf1a30Sjl if (lenp) 87325cf1a30Sjl *lenp = strlen(buf); 87425cf1a30Sjl } 8750cc8ae86Sav return (ret); 87625cf1a30Sjl } 87725cf1a30Sjl 87825cf1a30Sjl #define SCF_PUTINFO(f, s, p) \ 87925cf1a30Sjl f(KEY_ESCF, 0x01, 0, s, p) 88025cf1a30Sjl void 88125cf1a30Sjl plat_nodename_set(void) 88225cf1a30Sjl { 88325cf1a30Sjl void *datap; 88425cf1a30Sjl static int (*scf_service_function)(uint32_t, uint8_t, 88525cf1a30Sjl uint32_t, uint32_t, void *); 88625cf1a30Sjl int counter = 5; 88725cf1a30Sjl 88825cf1a30Sjl /* 88925cf1a30Sjl * find the symbol for the SCF put routine in driver 89025cf1a30Sjl */ 89125cf1a30Sjl if (scf_service_function == NULL) 89225cf1a30Sjl scf_service_function = 89325cf1a30Sjl (int (*)(uint32_t, uint8_t, uint32_t, uint32_t, void *)) 89425cf1a30Sjl modgetsymvalue("scf_service_putinfo", 0); 89525cf1a30Sjl 89625cf1a30Sjl /* 89725cf1a30Sjl * If the symbol was found, call it. Otherwise, log a note (but not to 89825cf1a30Sjl * the console). 89925cf1a30Sjl */ 90025cf1a30Sjl 90125cf1a30Sjl if (scf_service_function == NULL) { 90225cf1a30Sjl cmn_err(CE_NOTE, 90325cf1a30Sjl "!plat_nodename_set: scf_service_putinfo not found\n"); 90425cf1a30Sjl return; 90525cf1a30Sjl } 90625cf1a30Sjl 90725cf1a30Sjl datap = 90825cf1a30Sjl (struct utsname *)kmem_zalloc(sizeof (struct utsname), KM_SLEEP); 90925cf1a30Sjl 91025cf1a30Sjl if (datap == NULL) { 91125cf1a30Sjl return; 91225cf1a30Sjl } 91325cf1a30Sjl 91425cf1a30Sjl bcopy((struct utsname *)&utsname, 91525cf1a30Sjl (struct utsname *)datap, sizeof (struct utsname)); 91625cf1a30Sjl 91725cf1a30Sjl while ((SCF_PUTINFO(scf_service_function, 91825cf1a30Sjl sizeof (struct utsname), datap) == EBUSY) && (counter-- > 0)) { 91925cf1a30Sjl delay(10 * drv_usectohz(1000000)); 92025cf1a30Sjl } 92125cf1a30Sjl if (counter == 0) 92225cf1a30Sjl cmn_err(CE_NOTE, 92325cf1a30Sjl "!plat_nodename_set: " 92425cf1a30Sjl "scf_service_putinfo not responding\n"); 92525cf1a30Sjl 92625cf1a30Sjl kmem_free(datap, sizeof (struct utsname)); 92725cf1a30Sjl } 92825cf1a30Sjl 92925cf1a30Sjl caddr_t efcode_vaddr = NULL; 93025cf1a30Sjl 93125cf1a30Sjl /* 93225cf1a30Sjl * Preallocate enough memory for fcode claims. 93325cf1a30Sjl */ 93425cf1a30Sjl 93525cf1a30Sjl caddr_t 93625cf1a30Sjl efcode_alloc(caddr_t alloc_base) 93725cf1a30Sjl { 93825cf1a30Sjl caddr_t efcode_alloc_base = (caddr_t)roundup((uintptr_t)alloc_base, 93925cf1a30Sjl MMU_PAGESIZE); 94025cf1a30Sjl caddr_t vaddr; 94125cf1a30Sjl 94225cf1a30Sjl /* 94325cf1a30Sjl * allocate the physical memory for the Oberon fcode. 94425cf1a30Sjl */ 94525cf1a30Sjl if ((vaddr = (caddr_t)BOP_ALLOC(bootops, efcode_alloc_base, 94625cf1a30Sjl efcode_size, MMU_PAGESIZE)) == NULL) 94725cf1a30Sjl cmn_err(CE_PANIC, "Cannot allocate Efcode Memory"); 94825cf1a30Sjl 94925cf1a30Sjl efcode_vaddr = vaddr; 95025cf1a30Sjl 95125cf1a30Sjl return (efcode_alloc_base + efcode_size); 95225cf1a30Sjl } 95325cf1a30Sjl 95425cf1a30Sjl caddr_t 95525cf1a30Sjl plat_startup_memlist(caddr_t alloc_base) 95625cf1a30Sjl { 95725cf1a30Sjl caddr_t tmp_alloc_base; 95825cf1a30Sjl 95925cf1a30Sjl tmp_alloc_base = efcode_alloc(alloc_base); 96025cf1a30Sjl tmp_alloc_base = 96125cf1a30Sjl (caddr_t)roundup((uintptr_t)tmp_alloc_base, ecache_alignsize); 96225cf1a30Sjl return (tmp_alloc_base); 96325cf1a30Sjl } 96425cf1a30Sjl 96525cf1a30Sjl void 96625cf1a30Sjl startup_platform(void) 96725cf1a30Sjl { 96825cf1a30Sjl } 9690cc8ae86Sav 970*1e2e7a75Shuah void 971*1e2e7a75Shuah plat_cpuid_to_mmu_ctx_info(processorid_t cpuid, mmu_ctx_info_t *info) 972*1e2e7a75Shuah { 973*1e2e7a75Shuah int impl; 974*1e2e7a75Shuah 975*1e2e7a75Shuah impl = cpunodes[cpuid].implementation; 976*1e2e7a75Shuah if (IS_OLYMPUS_C(impl)) { 977*1e2e7a75Shuah /* 978*1e2e7a75Shuah * Olympus-C processor supports 2 strands per core. 979*1e2e7a75Shuah */ 980*1e2e7a75Shuah info->mmu_idx = cpuid >> 1; 981*1e2e7a75Shuah info->mmu_nctxs = 8192; 982*1e2e7a75Shuah } else { 983*1e2e7a75Shuah cmn_err(CE_PANIC, "Unknown processor %d", impl); 984*1e2e7a75Shuah } 985*1e2e7a75Shuah } 986*1e2e7a75Shuah 9870cc8ae86Sav int 9880cc8ae86Sav plat_get_mem_sid(char *unum, char *buf, int buflen, int *lenp) 9890cc8ae86Sav { 9900cc8ae86Sav if (opl_get_mem_sid == NULL) { 9910cc8ae86Sav return (ENOTSUP); 9920cc8ae86Sav } 9930cc8ae86Sav return (opl_get_mem_sid(unum, buf, buflen, lenp)); 9940cc8ae86Sav } 9950cc8ae86Sav 9960cc8ae86Sav int 9970cc8ae86Sav plat_get_mem_offset(uint64_t paddr, uint64_t *offp) 9980cc8ae86Sav { 9990cc8ae86Sav if (opl_get_mem_offset == NULL) { 10000cc8ae86Sav return (ENOTSUP); 10010cc8ae86Sav } 10020cc8ae86Sav return (opl_get_mem_offset(paddr, offp)); 10030cc8ae86Sav } 10040cc8ae86Sav 10050cc8ae86Sav int 10060cc8ae86Sav plat_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *addrp) 10070cc8ae86Sav { 10080cc8ae86Sav if (opl_get_mem_addr == NULL) { 10090cc8ae86Sav return (ENOTSUP); 10100cc8ae86Sav } 10110cc8ae86Sav return (opl_get_mem_addr(unum, sid, offset, addrp)); 10120cc8ae86Sav } 1013