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 *); 52*0cc8ae86Sav int (*opl_get_mem_sid)(char *unum, char *buf, int buflen, int *lenp); 53*0cc8ae86Sav int (*opl_get_mem_offset)(uint64_t paddr, uint64_t *offp); 54*0cc8ae86Sav int (*opl_get_mem_addr)(char *unum, char *sid, 55*0cc8ae86Sav 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 7525cf1a30Sjl static struct memlist *opl_memlist_per_board(struct memlist *ml); 7625cf1a30Sjl 77*0cc8ae86Sav static enum { 78*0cc8ae86Sav MODEL_FF1 = 0, 79*0cc8ae86Sav MODEL_FF2 = 1, 80*0cc8ae86Sav MODEL_DC = 2 81*0cc8ae86Sav } plat_model = -1; 82*0cc8ae86Sav 8325cf1a30Sjl int 8425cf1a30Sjl set_platform_max_ncpus(void) 8525cf1a30Sjl { 8625cf1a30Sjl return (OPL_MAX_CPU_PER_BOARD * OPL_MAX_BOARDS); 8725cf1a30Sjl } 8825cf1a30Sjl 8925cf1a30Sjl int 9025cf1a30Sjl set_platform_tsb_spares(void) 9125cf1a30Sjl { 9225cf1a30Sjl return (MIN(opl_tsb_spares, MAX_UPA)); 9325cf1a30Sjl } 9425cf1a30Sjl 9525cf1a30Sjl #pragma weak mmu_init_large_pages 9625cf1a30Sjl 9725cf1a30Sjl void 9825cf1a30Sjl set_platform_defaults(void) 9925cf1a30Sjl { 10025cf1a30Sjl extern char *tod_module_name; 10125cf1a30Sjl extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); 10225cf1a30Sjl extern int ts_dispatch_extended; 10325cf1a30Sjl extern void mmu_init_large_pages(size_t); 10425cf1a30Sjl 10525cf1a30Sjl /* Set the CPU signature function pointer */ 10625cf1a30Sjl cpu_sgn_func = cpu_sgn_update; 10725cf1a30Sjl 10825cf1a30Sjl /* Set appropriate tod module for OPL platform */ 10925cf1a30Sjl ASSERT(tod_module_name == NULL); 11025cf1a30Sjl tod_module_name = "todopl"; 11125cf1a30Sjl 11225cf1a30Sjl /* 11325cf1a30Sjl * Use the alternate TS dispatch table, which is better tuned 11425cf1a30Sjl * for large servers. 11525cf1a30Sjl */ 11625cf1a30Sjl if (ts_dispatch_extended == -1) 11725cf1a30Sjl ts_dispatch_extended = 1; 11825cf1a30Sjl 11925cf1a30Sjl if ((mmu_page_sizes == max_mmu_page_sizes) && 12025cf1a30Sjl (mmu_ism_pagesize != MMU_PAGESIZE32M)) { 12125cf1a30Sjl if (&mmu_init_large_pages) 12225cf1a30Sjl mmu_init_large_pages(mmu_ism_pagesize); 12325cf1a30Sjl } 12425cf1a30Sjl 12525cf1a30Sjl tsb_lgrp_affinity = 1; 12625cf1a30Sjl } 12725cf1a30Sjl 12825cf1a30Sjl /* 12925cf1a30Sjl * Convert logical a board number to a physical one. 13025cf1a30Sjl */ 13125cf1a30Sjl 13225cf1a30Sjl #define LSBPROP "board#" 13325cf1a30Sjl #define PSBPROP "physical-board#" 13425cf1a30Sjl 13525cf1a30Sjl int 13625cf1a30Sjl opl_get_physical_board(int id) 13725cf1a30Sjl { 13825cf1a30Sjl dev_info_t *root_dip, *dip = NULL; 13925cf1a30Sjl char *dname = NULL; 14025cf1a30Sjl int circ; 14125cf1a30Sjl 14225cf1a30Sjl pnode_t pnode; 14325cf1a30Sjl char pname[MAXSYSNAME] = {0}; 14425cf1a30Sjl 14525cf1a30Sjl int lsb_id; /* Logical System Board ID */ 14625cf1a30Sjl int psb_id; /* Physical System Board ID */ 14725cf1a30Sjl 14825cf1a30Sjl 14925cf1a30Sjl /* 15025cf1a30Sjl * This function is called on early stage of bootup when the 15125cf1a30Sjl * kernel device tree is not initialized yet, and also 15225cf1a30Sjl * later on when the device tree is up. We want to try 15325cf1a30Sjl * the fast track first. 15425cf1a30Sjl */ 15525cf1a30Sjl root_dip = ddi_root_node(); 15625cf1a30Sjl if (root_dip) { 15725cf1a30Sjl /* Get from devinfo node */ 15825cf1a30Sjl ndi_devi_enter(root_dip, &circ); 15925cf1a30Sjl for (dip = ddi_get_child(root_dip); dip; 16025cf1a30Sjl dip = ddi_get_next_sibling(dip)) { 16125cf1a30Sjl 16225cf1a30Sjl dname = ddi_node_name(dip); 16325cf1a30Sjl if (strncmp(dname, "pseudo-mc", 9) != 0) 16425cf1a30Sjl continue; 16525cf1a30Sjl 16625cf1a30Sjl if ((lsb_id = (int)ddi_getprop(DDI_DEV_T_ANY, dip, 16725cf1a30Sjl DDI_PROP_DONTPASS, LSBPROP, -1)) == -1) 16825cf1a30Sjl continue; 16925cf1a30Sjl 17025cf1a30Sjl if (id == lsb_id) { 17125cf1a30Sjl if ((psb_id = (int)ddi_getprop(DDI_DEV_T_ANY, 17225cf1a30Sjl dip, DDI_PROP_DONTPASS, PSBPROP, -1)) 17325cf1a30Sjl == -1) { 17425cf1a30Sjl ndi_devi_exit(root_dip, circ); 17525cf1a30Sjl return (-1); 17625cf1a30Sjl } else { 17725cf1a30Sjl ndi_devi_exit(root_dip, circ); 17825cf1a30Sjl return (psb_id); 17925cf1a30Sjl } 18025cf1a30Sjl } 18125cf1a30Sjl } 18225cf1a30Sjl ndi_devi_exit(root_dip, circ); 18325cf1a30Sjl } 18425cf1a30Sjl 18525cf1a30Sjl /* 18625cf1a30Sjl * We do not have the kernel device tree, or we did not 18725cf1a30Sjl * find the node for some reason (let's say the kernel 18825cf1a30Sjl * device tree was modified), let's try the OBP tree. 18925cf1a30Sjl */ 19025cf1a30Sjl pnode = prom_rootnode(); 19125cf1a30Sjl for (pnode = prom_childnode(pnode); pnode; 19225cf1a30Sjl pnode = prom_nextnode(pnode)) { 19325cf1a30Sjl 19425cf1a30Sjl if ((prom_getprop(pnode, "name", (caddr_t)pname) == -1) || 19525cf1a30Sjl (strncmp(pname, "pseudo-mc", 9) != 0)) 19625cf1a30Sjl continue; 19725cf1a30Sjl 19825cf1a30Sjl if (prom_getprop(pnode, LSBPROP, (caddr_t)&lsb_id) == -1) 19925cf1a30Sjl continue; 20025cf1a30Sjl 20125cf1a30Sjl if (id == lsb_id) { 20225cf1a30Sjl if (prom_getprop(pnode, PSBPROP, 20325cf1a30Sjl (caddr_t)&psb_id) == -1) { 20425cf1a30Sjl return (-1); 20525cf1a30Sjl } else { 20625cf1a30Sjl return (psb_id); 20725cf1a30Sjl } 20825cf1a30Sjl } 20925cf1a30Sjl } 21025cf1a30Sjl 21125cf1a30Sjl return (-1); 21225cf1a30Sjl } 21325cf1a30Sjl 21425cf1a30Sjl /* 21525cf1a30Sjl * For OPL it's possible that memory from two or more successive boards 21625cf1a30Sjl * will be contiguous across the boards, and therefore represented as a 21725cf1a30Sjl * single chunk. 21825cf1a30Sjl * This function splits such chunks down the board boundaries. 21925cf1a30Sjl */ 22025cf1a30Sjl static struct memlist * 22125cf1a30Sjl opl_memlist_per_board(struct memlist *ml) 22225cf1a30Sjl { 22325cf1a30Sjl uint64_t ssize, low, high, boundary; 22425cf1a30Sjl struct memlist *head, *tail, *new; 22525cf1a30Sjl 22625cf1a30Sjl ssize = (1ull << OPL_MC_MEMBOARD_SHIFT); 22725cf1a30Sjl 22825cf1a30Sjl head = tail = NULL; 22925cf1a30Sjl 23025cf1a30Sjl for (; ml; ml = ml->next) { 23125cf1a30Sjl low = (uint64_t)ml->address; 23225cf1a30Sjl high = low+(uint64_t)(ml->size); 23325cf1a30Sjl while (low < high) { 23425cf1a30Sjl boundary = roundup(low+1, ssize); 23525cf1a30Sjl boundary = MIN(high, boundary); 23625cf1a30Sjl new = kmem_zalloc(sizeof (struct memlist), KM_SLEEP); 23725cf1a30Sjl new->address = low; 23825cf1a30Sjl new->size = boundary - low; 23925cf1a30Sjl if (head == NULL) 24025cf1a30Sjl head = new; 24125cf1a30Sjl if (tail) { 24225cf1a30Sjl tail->next = new; 24325cf1a30Sjl new->prev = tail; 24425cf1a30Sjl } 24525cf1a30Sjl tail = new; 24625cf1a30Sjl low = boundary; 24725cf1a30Sjl } 24825cf1a30Sjl } 24925cf1a30Sjl return (head); 25025cf1a30Sjl } 25125cf1a30Sjl 25225cf1a30Sjl void 25325cf1a30Sjl set_platform_cage_params(void) 25425cf1a30Sjl { 25525cf1a30Sjl extern pgcnt_t total_pages; 25625cf1a30Sjl extern struct memlist *phys_avail; 25725cf1a30Sjl struct memlist *ml, *tml; 25825cf1a30Sjl int ret; 25925cf1a30Sjl 26025cf1a30Sjl if (kernel_cage_enable) { 26125cf1a30Sjl pgcnt_t preferred_cage_size; 26225cf1a30Sjl 26325cf1a30Sjl preferred_cage_size = 26425cf1a30Sjl MAX(opl_startup_cage_size, total_pages / 256); 26525cf1a30Sjl 26625cf1a30Sjl ml = opl_memlist_per_board(phys_avail); 26725cf1a30Sjl 26825cf1a30Sjl kcage_range_lock(); 26925cf1a30Sjl /* 27025cf1a30Sjl * Note: we are assuming that post has load the 27125cf1a30Sjl * whole show in to the high end of memory. Having 27225cf1a30Sjl * taken this leap, we copy the whole of phys_avail 27325cf1a30Sjl * the glist and arrange for the cage to grow 27425cf1a30Sjl * downward (descending pfns). 27525cf1a30Sjl */ 27625cf1a30Sjl ret = kcage_range_init(ml, 1); 27725cf1a30Sjl 27825cf1a30Sjl /* free the memlist */ 27925cf1a30Sjl do { 28025cf1a30Sjl tml = ml->next; 28125cf1a30Sjl kmem_free(ml, sizeof (struct memlist)); 28225cf1a30Sjl ml = tml; 28325cf1a30Sjl } while (ml != NULL); 28425cf1a30Sjl 28525cf1a30Sjl if (ret == 0) 28625cf1a30Sjl kcage_init(preferred_cage_size); 28725cf1a30Sjl kcage_range_unlock(); 28825cf1a30Sjl } 28925cf1a30Sjl 29025cf1a30Sjl if (kcage_on) 29125cf1a30Sjl cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED"); 29225cf1a30Sjl else 29325cf1a30Sjl cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED"); 29425cf1a30Sjl } 29525cf1a30Sjl 29625cf1a30Sjl /*ARGSUSED*/ 29725cf1a30Sjl int 29825cf1a30Sjl plat_cpu_poweron(struct cpu *cp) 29925cf1a30Sjl { 30025cf1a30Sjl int (*opl_cpu_poweron)(struct cpu *) = NULL; 30125cf1a30Sjl 30225cf1a30Sjl opl_cpu_poweron = 30325cf1a30Sjl (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0); 30425cf1a30Sjl 30525cf1a30Sjl if (opl_cpu_poweron == NULL) 30625cf1a30Sjl return (ENOTSUP); 30725cf1a30Sjl else 30825cf1a30Sjl return ((opl_cpu_poweron)(cp)); 30925cf1a30Sjl 31025cf1a30Sjl } 31125cf1a30Sjl 31225cf1a30Sjl /*ARGSUSED*/ 31325cf1a30Sjl int 31425cf1a30Sjl plat_cpu_poweroff(struct cpu *cp) 31525cf1a30Sjl { 31625cf1a30Sjl int (*opl_cpu_poweroff)(struct cpu *) = NULL; 31725cf1a30Sjl 31825cf1a30Sjl opl_cpu_poweroff = 31925cf1a30Sjl (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0); 32025cf1a30Sjl 32125cf1a30Sjl if (opl_cpu_poweroff == NULL) 32225cf1a30Sjl return (ENOTSUP); 32325cf1a30Sjl else 32425cf1a30Sjl return ((opl_cpu_poweroff)(cp)); 32525cf1a30Sjl 32625cf1a30Sjl } 32725cf1a30Sjl 32825cf1a30Sjl int 32925cf1a30Sjl plat_max_boards(void) 33025cf1a30Sjl { 33125cf1a30Sjl return (OPL_MAX_BOARDS); 33225cf1a30Sjl } 33325cf1a30Sjl 33425cf1a30Sjl int 33525cf1a30Sjl plat_max_cpu_units_per_board(void) 33625cf1a30Sjl { 33725cf1a30Sjl return (OPL_MAX_CPU_PER_BOARD); 33825cf1a30Sjl } 33925cf1a30Sjl 34025cf1a30Sjl int 34125cf1a30Sjl plat_max_mem_units_per_board(void) 34225cf1a30Sjl { 34325cf1a30Sjl return (OPL_MAX_MEM_UNITS_PER_BOARD); 34425cf1a30Sjl } 34525cf1a30Sjl 34625cf1a30Sjl int 34725cf1a30Sjl plat_max_io_units_per_board(void) 34825cf1a30Sjl { 34925cf1a30Sjl return (OPL_MAX_IO_UNITS_PER_BOARD); 35025cf1a30Sjl } 35125cf1a30Sjl 35225cf1a30Sjl int 35325cf1a30Sjl plat_max_cmp_units_per_board(void) 35425cf1a30Sjl { 35525cf1a30Sjl return (OPL_MAX_CMP_UNITS_PER_BOARD); 35625cf1a30Sjl } 35725cf1a30Sjl 35825cf1a30Sjl int 35925cf1a30Sjl plat_max_core_units_per_board(void) 36025cf1a30Sjl { 36125cf1a30Sjl return (OPL_MAX_CORE_UNITS_PER_BOARD); 36225cf1a30Sjl } 36325cf1a30Sjl 36425cf1a30Sjl int 36525cf1a30Sjl plat_pfn_to_mem_node(pfn_t pfn) 36625cf1a30Sjl { 36725cf1a30Sjl return (pfn >> mem_node_pfn_shift); 36825cf1a30Sjl } 36925cf1a30Sjl 37025cf1a30Sjl /* ARGSUSED */ 37125cf1a30Sjl void 37225cf1a30Sjl plat_build_mem_nodes(u_longlong_t *list, size_t nelems) 37325cf1a30Sjl { 37425cf1a30Sjl size_t elem; 37525cf1a30Sjl pfn_t basepfn; 37625cf1a30Sjl pgcnt_t npgs; 37725cf1a30Sjl uint64_t boundary, ssize; 37825cf1a30Sjl uint64_t low, high; 37925cf1a30Sjl 38025cf1a30Sjl /* 38125cf1a30Sjl * OPL mem slices are always aligned on a 256GB boundary. 38225cf1a30Sjl */ 38325cf1a30Sjl mem_node_pfn_shift = OPL_MC_MEMBOARD_SHIFT - MMU_PAGESHIFT; 38425cf1a30Sjl mem_node_physalign = 0; 38525cf1a30Sjl 38625cf1a30Sjl /* 38725cf1a30Sjl * Boot install lists are arranged <addr, len>, <addr, len>, ... 38825cf1a30Sjl */ 38925cf1a30Sjl ssize = (1ull << OPL_MC_MEMBOARD_SHIFT); 39025cf1a30Sjl for (elem = 0; elem < nelems; elem += 2) { 39125cf1a30Sjl low = (uint64_t)list[elem]; 39225cf1a30Sjl high = low+(uint64_t)(list[elem+1]); 39325cf1a30Sjl while (low < high) { 39425cf1a30Sjl boundary = roundup(low+1, ssize); 39525cf1a30Sjl boundary = MIN(high, boundary); 39625cf1a30Sjl basepfn = btop(low); 39725cf1a30Sjl npgs = btop(boundary - low); 39825cf1a30Sjl mem_node_add_slice(basepfn, basepfn + npgs - 1); 39925cf1a30Sjl low = boundary; 40025cf1a30Sjl } 40125cf1a30Sjl } 40225cf1a30Sjl } 40325cf1a30Sjl 40425cf1a30Sjl /* 40525cf1a30Sjl * Find the CPU associated with a slice at boot-time. 40625cf1a30Sjl */ 40725cf1a30Sjl void 40825cf1a30Sjl plat_fill_mc(pnode_t nodeid) 40925cf1a30Sjl { 41025cf1a30Sjl int board; 41125cf1a30Sjl int memnode; 41225cf1a30Sjl struct { 41325cf1a30Sjl uint64_t addr; 41425cf1a30Sjl uint64_t size; 41525cf1a30Sjl } mem_range; 41625cf1a30Sjl 41725cf1a30Sjl if (prom_getprop(nodeid, "board#", (caddr_t)&board) < 0) { 41825cf1a30Sjl panic("Can not find board# property in mc node %x", nodeid); 41925cf1a30Sjl } 42025cf1a30Sjl if (prom_getprop(nodeid, "sb-mem-ranges", (caddr_t)&mem_range) < 0) { 42125cf1a30Sjl panic("Can not find sb-mem-ranges property in mc node %x", 42225cf1a30Sjl nodeid); 42325cf1a30Sjl } 42425cf1a30Sjl memnode = mem_range.addr >> OPL_MC_MEMBOARD_SHIFT; 42525cf1a30Sjl plat_assign_lgrphand_to_mem_node(board, memnode); 42625cf1a30Sjl } 42725cf1a30Sjl 42825cf1a30Sjl /* 42925cf1a30Sjl * Return the platform handle for the lgroup containing the given CPU 43025cf1a30Sjl * 43125cf1a30Sjl * For OPL, lgroup platform handle == board #. 43225cf1a30Sjl */ 43325cf1a30Sjl 43425cf1a30Sjl extern int mpo_disabled; 43525cf1a30Sjl extern lgrp_handle_t lgrp_default_handle; 43625cf1a30Sjl 43725cf1a30Sjl lgrp_handle_t 43825cf1a30Sjl plat_lgrp_cpu_to_hand(processorid_t id) 43925cf1a30Sjl { 44025cf1a30Sjl lgrp_handle_t plathand; 44125cf1a30Sjl 44225cf1a30Sjl /* 44325cf1a30Sjl * Return the real platform handle for the CPU until 44425cf1a30Sjl * such time as we know that MPO should be disabled. 44525cf1a30Sjl * At that point, we set the "mpo_disabled" flag to true, 44625cf1a30Sjl * and from that point on, return the default handle. 44725cf1a30Sjl * 44825cf1a30Sjl * By the time we know that MPO should be disabled, the 44925cf1a30Sjl * first CPU will have already been added to a leaf 45025cf1a30Sjl * lgroup, but that's ok. The common lgroup code will 45125cf1a30Sjl * double check that the boot CPU is in the correct place, 45225cf1a30Sjl * and in the case where mpo should be disabled, will move 45325cf1a30Sjl * it to the root if necessary. 45425cf1a30Sjl */ 45525cf1a30Sjl if (mpo_disabled) { 45625cf1a30Sjl /* If MPO is disabled, return the default (UMA) handle */ 45725cf1a30Sjl plathand = lgrp_default_handle; 45825cf1a30Sjl } else 45925cf1a30Sjl plathand = (lgrp_handle_t)LSB_ID(id); 46025cf1a30Sjl return (plathand); 46125cf1a30Sjl } 46225cf1a30Sjl 46325cf1a30Sjl /* 46425cf1a30Sjl * Platform specific lgroup initialization 46525cf1a30Sjl */ 46625cf1a30Sjl void 46725cf1a30Sjl plat_lgrp_init(void) 46825cf1a30Sjl { 46925cf1a30Sjl extern uint32_t lgrp_expand_proc_thresh; 47025cf1a30Sjl extern uint32_t lgrp_expand_proc_diff; 47125cf1a30Sjl 47225cf1a30Sjl /* 47325cf1a30Sjl * Set tuneables for the OPL architecture 47425cf1a30Sjl * 47525cf1a30Sjl * lgrp_expand_proc_thresh is the minimum load on the lgroups 47625cf1a30Sjl * this process is currently running on before considering 47725cf1a30Sjl * expanding threads to another lgroup. 47825cf1a30Sjl * 47925cf1a30Sjl * lgrp_expand_proc_diff determines how much less the remote lgroup 48025cf1a30Sjl * must be loaded before expanding to it. 48125cf1a30Sjl * 48225cf1a30Sjl * Since remote latencies can be costly, attempt to keep 3 threads 48325cf1a30Sjl * within the same lgroup before expanding to the next lgroup. 48425cf1a30Sjl */ 48525cf1a30Sjl lgrp_expand_proc_thresh = LGRP_LOADAVG_THREAD_MAX * 3; 48625cf1a30Sjl lgrp_expand_proc_diff = LGRP_LOADAVG_THREAD_MAX; 48725cf1a30Sjl } 48825cf1a30Sjl 48925cf1a30Sjl /* 49025cf1a30Sjl * Platform notification of lgroup (re)configuration changes 49125cf1a30Sjl */ 49225cf1a30Sjl /*ARGSUSED*/ 49325cf1a30Sjl void 49425cf1a30Sjl plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg) 49525cf1a30Sjl { 49625cf1a30Sjl update_membounds_t *umb; 49725cf1a30Sjl lgrp_config_mem_rename_t lmr; 49825cf1a30Sjl int sbd, tbd; 49925cf1a30Sjl lgrp_handle_t hand, shand, thand; 50025cf1a30Sjl int mnode, snode, tnode; 50125cf1a30Sjl pfn_t start, end; 50225cf1a30Sjl 50325cf1a30Sjl if (mpo_disabled) 50425cf1a30Sjl return; 50525cf1a30Sjl 50625cf1a30Sjl switch (evt) { 50725cf1a30Sjl 50825cf1a30Sjl case LGRP_CONFIG_MEM_ADD: 50925cf1a30Sjl /* 51025cf1a30Sjl * Establish the lgroup handle to memnode translation. 51125cf1a30Sjl */ 51225cf1a30Sjl umb = (update_membounds_t *)arg; 51325cf1a30Sjl 51425cf1a30Sjl hand = umb->u_board; 51525cf1a30Sjl mnode = plat_pfn_to_mem_node(umb->u_base >> MMU_PAGESHIFT); 51625cf1a30Sjl plat_assign_lgrphand_to_mem_node(hand, mnode); 51725cf1a30Sjl 51825cf1a30Sjl break; 51925cf1a30Sjl 52025cf1a30Sjl case LGRP_CONFIG_MEM_DEL: 52125cf1a30Sjl /* 52225cf1a30Sjl * Special handling for possible memory holes. 52325cf1a30Sjl */ 52425cf1a30Sjl umb = (update_membounds_t *)arg; 52525cf1a30Sjl hand = umb->u_board; 52625cf1a30Sjl if ((mnode = plat_lgrphand_to_mem_node(hand)) != -1) { 52725cf1a30Sjl if (mem_node_config[mnode].exists) { 52825cf1a30Sjl start = mem_node_config[mnode].physbase; 52925cf1a30Sjl end = mem_node_config[mnode].physmax; 53025cf1a30Sjl mem_node_pre_del_slice(start, end); 53125cf1a30Sjl mem_node_post_del_slice(start, end, 0); 53225cf1a30Sjl } 53325cf1a30Sjl } 53425cf1a30Sjl 53525cf1a30Sjl break; 53625cf1a30Sjl 53725cf1a30Sjl case LGRP_CONFIG_MEM_RENAME: 53825cf1a30Sjl /* 53925cf1a30Sjl * During a DR copy-rename operation, all of the memory 54025cf1a30Sjl * on one board is moved to another board -- but the 54125cf1a30Sjl * addresses/pfns and memnodes don't change. This means 54225cf1a30Sjl * the memory has changed locations without changing identity. 54325cf1a30Sjl * 54425cf1a30Sjl * Source is where we are copying from and target is where we 54525cf1a30Sjl * are copying to. After source memnode is copied to target 54625cf1a30Sjl * memnode, the physical addresses of the target memnode are 54725cf1a30Sjl * renamed to match what the source memnode had. Then target 54825cf1a30Sjl * memnode can be removed and source memnode can take its 54925cf1a30Sjl * place. 55025cf1a30Sjl * 55125cf1a30Sjl * To do this, swap the lgroup handle to memnode mappings for 55225cf1a30Sjl * the boards, so target lgroup will have source memnode and 55325cf1a30Sjl * source lgroup will have empty target memnode which is where 55425cf1a30Sjl * its memory will go (if any is added to it later). 55525cf1a30Sjl * 55625cf1a30Sjl * Then source memnode needs to be removed from its lgroup 55725cf1a30Sjl * and added to the target lgroup where the memory was living 55825cf1a30Sjl * but under a different name/memnode. The memory was in the 55925cf1a30Sjl * target memnode and now lives in the source memnode with 56025cf1a30Sjl * different physical addresses even though it is the same 56125cf1a30Sjl * memory. 56225cf1a30Sjl */ 56325cf1a30Sjl sbd = arg & 0xffff; 56425cf1a30Sjl tbd = (arg & 0xffff0000) >> 16; 56525cf1a30Sjl shand = sbd; 56625cf1a30Sjl thand = tbd; 56725cf1a30Sjl snode = plat_lgrphand_to_mem_node(shand); 56825cf1a30Sjl tnode = plat_lgrphand_to_mem_node(thand); 56925cf1a30Sjl 57025cf1a30Sjl /* 57125cf1a30Sjl * Special handling for possible memory holes. 57225cf1a30Sjl */ 57325cf1a30Sjl if (tnode != -1 && mem_node_config[tnode].exists) { 57425cf1a30Sjl start = mem_node_config[mnode].physbase; 57525cf1a30Sjl end = mem_node_config[mnode].physmax; 57625cf1a30Sjl mem_node_pre_del_slice(start, end); 57725cf1a30Sjl mem_node_post_del_slice(start, end, 0); 57825cf1a30Sjl } 57925cf1a30Sjl 58025cf1a30Sjl plat_assign_lgrphand_to_mem_node(thand, snode); 58125cf1a30Sjl plat_assign_lgrphand_to_mem_node(shand, tnode); 58225cf1a30Sjl 58325cf1a30Sjl lmr.lmem_rename_from = shand; 58425cf1a30Sjl lmr.lmem_rename_to = thand; 58525cf1a30Sjl 58625cf1a30Sjl /* 58725cf1a30Sjl * Remove source memnode of copy rename from its lgroup 58825cf1a30Sjl * and add it to its new target lgroup 58925cf1a30Sjl */ 59025cf1a30Sjl lgrp_config(LGRP_CONFIG_MEM_RENAME, (uintptr_t)snode, 59125cf1a30Sjl (uintptr_t)&lmr); 59225cf1a30Sjl 59325cf1a30Sjl break; 59425cf1a30Sjl 59525cf1a30Sjl default: 59625cf1a30Sjl break; 59725cf1a30Sjl } 59825cf1a30Sjl } 59925cf1a30Sjl 60025cf1a30Sjl /* 60125cf1a30Sjl * Return latency between "from" and "to" lgroups 60225cf1a30Sjl * 60325cf1a30Sjl * This latency number can only be used for relative comparison 60425cf1a30Sjl * between lgroups on the running system, cannot be used across platforms, 60525cf1a30Sjl * and may not reflect the actual latency. It is platform and implementation 60625cf1a30Sjl * specific, so platform gets to decide its value. It would be nice if the 60725cf1a30Sjl * number was at least proportional to make comparisons more meaningful though. 60825cf1a30Sjl * NOTE: The numbers below are supposed to be load latencies for uncached 60925cf1a30Sjl * memory divided by 10. 61025cf1a30Sjl * 61125cf1a30Sjl * XXX latency values for Columbus, not Columbus2. Should be fixed later when 61225cf1a30Sjl * we know the actual numbers for Columbus2. 61325cf1a30Sjl */ 61425cf1a30Sjl int 61525cf1a30Sjl plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to) 61625cf1a30Sjl { 61725cf1a30Sjl /* 61825cf1a30Sjl * Return min remote latency when there are more than two lgroups 61925cf1a30Sjl * (root and child) and getting latency between two different lgroups 62025cf1a30Sjl * or root is involved 62125cf1a30Sjl */ 62225cf1a30Sjl if (lgrp_optimizations() && (from != to || 62325cf1a30Sjl from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE)) 62425cf1a30Sjl return (27); 62525cf1a30Sjl else 62625cf1a30Sjl return (25); 62725cf1a30Sjl } 62825cf1a30Sjl 62925cf1a30Sjl /* 63025cf1a30Sjl * Return platform handle for root lgroup 63125cf1a30Sjl */ 63225cf1a30Sjl lgrp_handle_t 63325cf1a30Sjl plat_lgrp_root_hand(void) 63425cf1a30Sjl { 63525cf1a30Sjl if (mpo_disabled) 63625cf1a30Sjl return (lgrp_default_handle); 63725cf1a30Sjl 63825cf1a30Sjl return (LGRP_DEFAULT_HANDLE); 63925cf1a30Sjl } 64025cf1a30Sjl 64125cf1a30Sjl /*ARGSUSED*/ 64225cf1a30Sjl void 64325cf1a30Sjl plat_freelist_process(int mnode) 64425cf1a30Sjl { 64525cf1a30Sjl } 64625cf1a30Sjl 64725cf1a30Sjl void 64825cf1a30Sjl load_platform_drivers(void) 64925cf1a30Sjl { 65025cf1a30Sjl (void) i_ddi_attach_pseudo_node("dr"); 65125cf1a30Sjl } 65225cf1a30Sjl 65325cf1a30Sjl /* 65425cf1a30Sjl * No platform drivers on this platform 65525cf1a30Sjl */ 65625cf1a30Sjl char *platform_module_list[] = { 65725cf1a30Sjl (char *)0 65825cf1a30Sjl }; 65925cf1a30Sjl 66025cf1a30Sjl /*ARGSUSED*/ 66125cf1a30Sjl void 66225cf1a30Sjl plat_tod_fault(enum tod_fault_type tod_bad) 66325cf1a30Sjl { 66425cf1a30Sjl } 66525cf1a30Sjl 66625cf1a30Sjl /*ARGSUSED*/ 66725cf1a30Sjl void 66825cf1a30Sjl cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid) 66925cf1a30Sjl { 67025cf1a30Sjl static void (*scf_panic_callback)(int); 67125cf1a30Sjl static void (*scf_shutdown_callback)(int); 67225cf1a30Sjl 67325cf1a30Sjl /* 67425cf1a30Sjl * This is for notifing system panic/shutdown to SCF. 67525cf1a30Sjl * In case of shutdown and panic, SCF call back 67625cf1a30Sjl * function should be called. 67725cf1a30Sjl * <SCF call back functions> 67825cf1a30Sjl * scf_panic_callb() : panicsys()->panic_quiesce_hw() 67925cf1a30Sjl * scf_shutdown_callb(): halt() or power_down() or reboot_machine() 68025cf1a30Sjl * cpuid should be -1 and state should be SIGST_EXIT. 68125cf1a30Sjl */ 68225cf1a30Sjl if (state == SIGST_EXIT && cpuid == -1) { 68325cf1a30Sjl 68425cf1a30Sjl /* 68525cf1a30Sjl * find the symbol for the SCF panic callback routine in driver 68625cf1a30Sjl */ 68725cf1a30Sjl if (scf_panic_callback == NULL) 68825cf1a30Sjl scf_panic_callback = (void (*)(int)) 68925cf1a30Sjl modgetsymvalue("scf_panic_callb", 0); 69025cf1a30Sjl if (scf_shutdown_callback == NULL) 69125cf1a30Sjl scf_shutdown_callback = (void (*)(int)) 69225cf1a30Sjl modgetsymvalue("scf_shutdown_callb", 0); 69325cf1a30Sjl 69425cf1a30Sjl switch (sub_state) { 69525cf1a30Sjl case SIGSUBST_PANIC: 69625cf1a30Sjl if (scf_panic_callback == NULL) { 69725cf1a30Sjl cmn_err(CE_NOTE, "!cpu_sgn_update: " 69825cf1a30Sjl "scf_panic_callb not found\n"); 69925cf1a30Sjl return; 70025cf1a30Sjl } 70125cf1a30Sjl scf_panic_callback(SIGSUBST_PANIC); 70225cf1a30Sjl break; 70325cf1a30Sjl 70425cf1a30Sjl case SIGSUBST_HALT: 70525cf1a30Sjl if (scf_shutdown_callback == NULL) { 70625cf1a30Sjl cmn_err(CE_NOTE, "!cpu_sgn_update: " 70725cf1a30Sjl "scf_shutdown_callb not found\n"); 70825cf1a30Sjl return; 70925cf1a30Sjl } 71025cf1a30Sjl scf_shutdown_callback(SIGSUBST_HALT); 71125cf1a30Sjl break; 71225cf1a30Sjl 71325cf1a30Sjl case SIGSUBST_ENVIRON: 71425cf1a30Sjl if (scf_shutdown_callback == NULL) { 71525cf1a30Sjl cmn_err(CE_NOTE, "!cpu_sgn_update: " 71625cf1a30Sjl "scf_shutdown_callb not found\n"); 71725cf1a30Sjl return; 71825cf1a30Sjl } 71925cf1a30Sjl scf_shutdown_callback(SIGSUBST_ENVIRON); 72025cf1a30Sjl break; 72125cf1a30Sjl 72225cf1a30Sjl case SIGSUBST_REBOOT: 72325cf1a30Sjl if (scf_shutdown_callback == NULL) { 72425cf1a30Sjl cmn_err(CE_NOTE, "!cpu_sgn_update: " 72525cf1a30Sjl "scf_shutdown_callb not found\n"); 72625cf1a30Sjl return; 72725cf1a30Sjl } 72825cf1a30Sjl scf_shutdown_callback(SIGSUBST_REBOOT); 72925cf1a30Sjl break; 73025cf1a30Sjl } 73125cf1a30Sjl } 73225cf1a30Sjl } 73325cf1a30Sjl 73425cf1a30Sjl /*ARGSUSED*/ 73525cf1a30Sjl int 73625cf1a30Sjl plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id, 73725cf1a30Sjl int flt_in_memory, ushort_t flt_status, 73825cf1a30Sjl char *buf, int buflen, int *lenp) 73925cf1a30Sjl { 74025cf1a30Sjl /* 74125cf1a30Sjl * check if it's a Memory error. 74225cf1a30Sjl */ 74325cf1a30Sjl if (flt_in_memory) { 74425cf1a30Sjl if (opl_get_mem_unum != NULL) { 74525cf1a30Sjl return (opl_get_mem_unum(synd_code, flt_addr, 74625cf1a30Sjl buf, buflen, lenp)); 74725cf1a30Sjl } else { 74825cf1a30Sjl return (ENOTSUP); 74925cf1a30Sjl } 75025cf1a30Sjl } else { 75125cf1a30Sjl return (ENOTSUP); 75225cf1a30Sjl } 75325cf1a30Sjl } 75425cf1a30Sjl 75525cf1a30Sjl /*ARGSUSED*/ 75625cf1a30Sjl int 75725cf1a30Sjl plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp) 75825cf1a30Sjl { 759*0cc8ae86Sav int plen; 760*0cc8ae86Sav int ret = 0; 761*0cc8ae86Sav char model[20]; 762*0cc8ae86Sav uint_t sb; 763*0cc8ae86Sav pnode_t node; 764*0cc8ae86Sav 765*0cc8ae86Sav /* determine the platform model once */ 766*0cc8ae86Sav if (plat_model == -1) { 767*0cc8ae86Sav plat_model = MODEL_DC; /* Default model */ 768*0cc8ae86Sav node = prom_rootnode(); 769*0cc8ae86Sav plen = prom_getproplen(node, "model"); 770*0cc8ae86Sav if (plen > 0 && plen < sizeof (model)) { 771*0cc8ae86Sav (void) prom_getprop(node, "model", model); 772*0cc8ae86Sav model[plen] = '\0'; 773*0cc8ae86Sav if (strcmp(model, "FF1") == 0) 774*0cc8ae86Sav plat_model = MODEL_FF1; 775*0cc8ae86Sav else if (strcmp(model, "FF2") == 0) 776*0cc8ae86Sav plat_model = MODEL_FF2; 777*0cc8ae86Sav else if (strncmp(model, "DC", 2) == 0) 778*0cc8ae86Sav plat_model = MODEL_DC; 779*0cc8ae86Sav } 780*0cc8ae86Sav } 78125cf1a30Sjl 78225cf1a30Sjl sb = opl_get_physical_board(LSB_ID(cpuid)); 78325cf1a30Sjl if (sb == -1) { 78425cf1a30Sjl return (ENXIO); 78525cf1a30Sjl } 78625cf1a30Sjl 787*0cc8ae86Sav switch (plat_model) { 788*0cc8ae86Sav case MODEL_FF1: 789*0cc8ae86Sav plen = snprintf(buf, buflen, "/%s/CPUM%d", "MBU_A", 790*0cc8ae86Sav CHIP_ID(cpuid) / 2); 791*0cc8ae86Sav break; 792*0cc8ae86Sav 793*0cc8ae86Sav case MODEL_FF2: 794*0cc8ae86Sav plen = snprintf(buf, buflen, "/%s/CPUM%d", "MBU_B", 795*0cc8ae86Sav CHIP_ID(cpuid) / 2); 796*0cc8ae86Sav break; 797*0cc8ae86Sav 798*0cc8ae86Sav case MODEL_DC: 799*0cc8ae86Sav plen = snprintf(buf, buflen, "/%s%02d/CPUM%d", "CMU", sb, 800*0cc8ae86Sav CHIP_ID(cpuid)); 801*0cc8ae86Sav break; 802*0cc8ae86Sav 803*0cc8ae86Sav default: 804*0cc8ae86Sav /* This should never happen */ 805*0cc8ae86Sav return (ENODEV); 806*0cc8ae86Sav } 807*0cc8ae86Sav 808*0cc8ae86Sav if (plen >= buflen) { 809*0cc8ae86Sav ret = ENOSPC; 81025cf1a30Sjl } else { 81125cf1a30Sjl if (lenp) 81225cf1a30Sjl *lenp = strlen(buf); 81325cf1a30Sjl } 814*0cc8ae86Sav return (ret); 81525cf1a30Sjl } 81625cf1a30Sjl 81725cf1a30Sjl #define SCF_PUTINFO(f, s, p) \ 81825cf1a30Sjl f(KEY_ESCF, 0x01, 0, s, p) 81925cf1a30Sjl void 82025cf1a30Sjl plat_nodename_set(void) 82125cf1a30Sjl { 82225cf1a30Sjl void *datap; 82325cf1a30Sjl static int (*scf_service_function)(uint32_t, uint8_t, 82425cf1a30Sjl uint32_t, uint32_t, void *); 82525cf1a30Sjl int counter = 5; 82625cf1a30Sjl 82725cf1a30Sjl /* 82825cf1a30Sjl * find the symbol for the SCF put routine in driver 82925cf1a30Sjl */ 83025cf1a30Sjl if (scf_service_function == NULL) 83125cf1a30Sjl scf_service_function = 83225cf1a30Sjl (int (*)(uint32_t, uint8_t, uint32_t, uint32_t, void *)) 83325cf1a30Sjl modgetsymvalue("scf_service_putinfo", 0); 83425cf1a30Sjl 83525cf1a30Sjl /* 83625cf1a30Sjl * If the symbol was found, call it. Otherwise, log a note (but not to 83725cf1a30Sjl * the console). 83825cf1a30Sjl */ 83925cf1a30Sjl 84025cf1a30Sjl if (scf_service_function == NULL) { 84125cf1a30Sjl cmn_err(CE_NOTE, 84225cf1a30Sjl "!plat_nodename_set: scf_service_putinfo not found\n"); 84325cf1a30Sjl return; 84425cf1a30Sjl } 84525cf1a30Sjl 84625cf1a30Sjl datap = 84725cf1a30Sjl (struct utsname *)kmem_zalloc(sizeof (struct utsname), KM_SLEEP); 84825cf1a30Sjl 84925cf1a30Sjl if (datap == NULL) { 85025cf1a30Sjl return; 85125cf1a30Sjl } 85225cf1a30Sjl 85325cf1a30Sjl bcopy((struct utsname *)&utsname, 85425cf1a30Sjl (struct utsname *)datap, sizeof (struct utsname)); 85525cf1a30Sjl 85625cf1a30Sjl while ((SCF_PUTINFO(scf_service_function, 85725cf1a30Sjl sizeof (struct utsname), datap) == EBUSY) && (counter-- > 0)) { 85825cf1a30Sjl delay(10 * drv_usectohz(1000000)); 85925cf1a30Sjl } 86025cf1a30Sjl if (counter == 0) 86125cf1a30Sjl cmn_err(CE_NOTE, 86225cf1a30Sjl "!plat_nodename_set: " 86325cf1a30Sjl "scf_service_putinfo not responding\n"); 86425cf1a30Sjl 86525cf1a30Sjl kmem_free(datap, sizeof (struct utsname)); 86625cf1a30Sjl } 86725cf1a30Sjl 86825cf1a30Sjl caddr_t efcode_vaddr = NULL; 86925cf1a30Sjl 87025cf1a30Sjl /* 87125cf1a30Sjl * Preallocate enough memory for fcode claims. 87225cf1a30Sjl */ 87325cf1a30Sjl 87425cf1a30Sjl caddr_t 87525cf1a30Sjl efcode_alloc(caddr_t alloc_base) 87625cf1a30Sjl { 87725cf1a30Sjl caddr_t efcode_alloc_base = (caddr_t)roundup((uintptr_t)alloc_base, 87825cf1a30Sjl MMU_PAGESIZE); 87925cf1a30Sjl caddr_t vaddr; 88025cf1a30Sjl 88125cf1a30Sjl /* 88225cf1a30Sjl * allocate the physical memory for the Oberon fcode. 88325cf1a30Sjl */ 88425cf1a30Sjl if ((vaddr = (caddr_t)BOP_ALLOC(bootops, efcode_alloc_base, 88525cf1a30Sjl efcode_size, MMU_PAGESIZE)) == NULL) 88625cf1a30Sjl cmn_err(CE_PANIC, "Cannot allocate Efcode Memory"); 88725cf1a30Sjl 88825cf1a30Sjl efcode_vaddr = vaddr; 88925cf1a30Sjl 89025cf1a30Sjl return (efcode_alloc_base + efcode_size); 89125cf1a30Sjl } 89225cf1a30Sjl 89325cf1a30Sjl caddr_t 89425cf1a30Sjl plat_startup_memlist(caddr_t alloc_base) 89525cf1a30Sjl { 89625cf1a30Sjl caddr_t tmp_alloc_base; 89725cf1a30Sjl 89825cf1a30Sjl tmp_alloc_base = efcode_alloc(alloc_base); 89925cf1a30Sjl tmp_alloc_base = 90025cf1a30Sjl (caddr_t)roundup((uintptr_t)tmp_alloc_base, ecache_alignsize); 90125cf1a30Sjl return (tmp_alloc_base); 90225cf1a30Sjl } 90325cf1a30Sjl 90425cf1a30Sjl void 90525cf1a30Sjl startup_platform(void) 90625cf1a30Sjl { 90725cf1a30Sjl } 908*0cc8ae86Sav 909*0cc8ae86Sav int 910*0cc8ae86Sav plat_get_mem_sid(char *unum, char *buf, int buflen, int *lenp) 911*0cc8ae86Sav { 912*0cc8ae86Sav if (opl_get_mem_sid == NULL) { 913*0cc8ae86Sav return (ENOTSUP); 914*0cc8ae86Sav } 915*0cc8ae86Sav return (opl_get_mem_sid(unum, buf, buflen, lenp)); 916*0cc8ae86Sav } 917*0cc8ae86Sav 918*0cc8ae86Sav int 919*0cc8ae86Sav plat_get_mem_offset(uint64_t paddr, uint64_t *offp) 920*0cc8ae86Sav { 921*0cc8ae86Sav if (opl_get_mem_offset == NULL) { 922*0cc8ae86Sav return (ENOTSUP); 923*0cc8ae86Sav } 924*0cc8ae86Sav return (opl_get_mem_offset(paddr, offp)); 925*0cc8ae86Sav } 926*0cc8ae86Sav 927*0cc8ae86Sav int 928*0cc8ae86Sav plat_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *addrp) 929*0cc8ae86Sav { 930*0cc8ae86Sav if (opl_get_mem_addr == NULL) { 931*0cc8ae86Sav return (ENOTSUP); 932*0cc8ae86Sav } 933*0cc8ae86Sav return (opl_get_mem_addr(unum, sid, offset, addrp)); 934*0cc8ae86Sav } 935