11772Sjl139090 /* 21772Sjl139090 * CDDL HEADER START 31772Sjl139090 * 41772Sjl139090 * The contents of this file are subject to the terms of the 51772Sjl139090 * Common Development and Distribution License (the "License"). 61772Sjl139090 * You may not use this file except in compliance with the License. 71772Sjl139090 * 81772Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91772Sjl139090 * or http://www.opensolaris.org/os/licensing. 101772Sjl139090 * See the License for the specific language governing permissions 111772Sjl139090 * and limitations under the License. 121772Sjl139090 * 131772Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each 141772Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151772Sjl139090 * If applicable, add the following below this CDDL HEADER, with the 161772Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying 171772Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner] 181772Sjl139090 * 191772Sjl139090 * CDDL HEADER END 201772Sjl139090 */ 211772Sjl139090 /* 2210106SJason.Beloro@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 231772Sjl139090 * Use is subject to license terms. 241772Sjl139090 */ 251772Sjl139090 261772Sjl139090 #include <sys/cpuvar.h> 271772Sjl139090 #include <sys/systm.h> 281772Sjl139090 #include <sys/sysmacros.h> 291772Sjl139090 #include <sys/promif.h> 301772Sjl139090 #include <sys/platform_module.h> 311772Sjl139090 #include <sys/cmn_err.h> 321772Sjl139090 #include <sys/errno.h> 331772Sjl139090 #include <sys/machsystm.h> 341772Sjl139090 #include <sys/bootconf.h> 351772Sjl139090 #include <sys/nvpair.h> 361772Sjl139090 #include <sys/kobj.h> 371772Sjl139090 #include <sys/mem_cage.h> 381772Sjl139090 #include <sys/opl.h> 391772Sjl139090 #include <sys/scfd/scfostoescf.h> 401772Sjl139090 #include <sys/cpu_sgnblk_defs.h> 411772Sjl139090 #include <sys/utsname.h> 421772Sjl139090 #include <sys/ddi.h> 431772Sjl139090 #include <sys/sunndi.h> 441772Sjl139090 #include <sys/lgrp.h> 451772Sjl139090 #include <sys/memnode.h> 461772Sjl139090 #include <sys/sysmacros.h> 473914Spm145316 #include <sys/time.h> 483914Spm145316 #include <sys/cpu.h> 49*10843SDave.Plauger@Sun.COM #include <sys/dumphdr.h> 501772Sjl139090 #include <vm/vm_dep.h> 511772Sjl139090 521772Sjl139090 int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *); 532214Sav145390 int (*opl_get_mem_sid)(char *unum, char *buf, int buflen, int *lenp); 542214Sav145390 int (*opl_get_mem_offset)(uint64_t paddr, uint64_t *offp); 552214Sav145390 int (*opl_get_mem_addr)(char *unum, char *sid, 562214Sav145390 uint64_t offset, uint64_t *paddr); 571772Sjl139090 581772Sjl139090 /* Memory for fcode claims. 16k times # maximum possible IO units */ 591772Sjl139090 #define EFCODE_SIZE (OPL_MAX_BOARDS * OPL_MAX_IO_UNITS_PER_BOARD * 0x4000) 601772Sjl139090 int efcode_size = EFCODE_SIZE; 611772Sjl139090 621772Sjl139090 #define OPL_MC_MEMBOARD_SHIFT 38 /* Boards on 256BG boundary */ 631772Sjl139090 641772Sjl139090 /* Set the maximum number of boards for DR */ 651772Sjl139090 int opl_boards = OPL_MAX_BOARDS; 661772Sjl139090 671772Sjl139090 void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t); 681772Sjl139090 691772Sjl139090 extern int tsb_lgrp_affinity; 701772Sjl139090 711772Sjl139090 int opl_tsb_spares = (OPL_MAX_BOARDS) * (OPL_MAX_PCICH_UNITS_PER_BOARD) * 721772Sjl139090 (OPL_MAX_TSBS_PER_PCICH); 731772Sjl139090 741772Sjl139090 pgcnt_t opl_startup_cage_size = 0; 751772Sjl139090 765347Sjfrank /* 775347Sjfrank * The length of the delay in seconds in communication with XSCF after 785347Sjfrank * which the warning message will be logged. 795347Sjfrank */ 805347Sjfrank uint_t xscf_connect_delay = 60 * 15; 815347Sjfrank 822241Shuah static opl_model_info_t opl_models[] = { 833123Ssubhan { "FF1", OPL_MAX_BOARDS_FF1, FF1, STD_DISPATCH_TABLE }, 843123Ssubhan { "FF2", OPL_MAX_BOARDS_FF2, FF2, STD_DISPATCH_TABLE }, 853123Ssubhan { "DC1", OPL_MAX_BOARDS_DC1, DC1, STD_DISPATCH_TABLE }, 863123Ssubhan { "DC2", OPL_MAX_BOARDS_DC2, DC2, EXT_DISPATCH_TABLE }, 873123Ssubhan { "DC3", OPL_MAX_BOARDS_DC3, DC3, EXT_DISPATCH_TABLE }, 886297Sjl139090 { "IKKAKU", OPL_MAX_BOARDS_IKKAKU, IKKAKU, STD_DISPATCH_TABLE }, 892241Shuah }; 902241Shuah static int opl_num_models = sizeof (opl_models)/sizeof (opl_model_info_t); 912241Shuah 923123Ssubhan /* 933627Ssubhan * opl_cur_model 943123Ssubhan */ 953627Ssubhan static opl_model_info_t *opl_cur_model = NULL; 962241Shuah 971772Sjl139090 static struct memlist *opl_memlist_per_board(struct memlist *ml); 985347Sjfrank static void post_xscf_msg(char *, int); 995347Sjfrank static void pass2xscf_thread(); 1001772Sjl139090 1013914Spm145316 /* 1023914Spm145316 * Note FF/DC out-of-order instruction engine takes only a 1033914Spm145316 * single cycle to execute each spin loop 1043914Spm145316 * for comparison, Panther takes 6 cycles for same loop 1055834Spt157919 * OPL_BOFF_SPIN = base spin loop, roughly one memory reference time 1065834Spt157919 * OPL_BOFF_TM = approx nsec for OPL sleep instruction (1600 for OPL-C) 1075834Spt157919 * OPL_BOFF_SLEEP = approx number of SPIN iterations to equal one sleep 1085834Spt157919 * OPL_BOFF_MAX_SCALE - scaling factor for max backoff based on active cpus 1095834Spt157919 * Listed values tuned for 2.15GHz to 2.64GHz systems 1103914Spm145316 * Value may change for future systems 1113914Spm145316 */ 1125834Spt157919 #define OPL_BOFF_SPIN 7 1135834Spt157919 #define OPL_BOFF_SLEEP 4 1145834Spt157919 #define OPL_BOFF_TM 1600 1155834Spt157919 #define OPL_BOFF_MAX_SCALE 8 1163914Spm145316 1175788Smv143129 #define OPL_CLOCK_TICK_THRESHOLD 128 1185788Smv143129 #define OPL_CLOCK_TICK_NCPUS 64 1195788Smv143129 1205788Smv143129 extern int clock_tick_threshold; 1215788Smv143129 extern int clock_tick_ncpus; 1225788Smv143129 1231772Sjl139090 int 1241772Sjl139090 set_platform_max_ncpus(void) 1251772Sjl139090 { 1261772Sjl139090 return (OPL_MAX_CPU_PER_BOARD * OPL_MAX_BOARDS); 1271772Sjl139090 } 1281772Sjl139090 1291772Sjl139090 int 1301772Sjl139090 set_platform_tsb_spares(void) 1311772Sjl139090 { 1321772Sjl139090 return (MIN(opl_tsb_spares, MAX_UPA)); 1331772Sjl139090 } 1341772Sjl139090 1352241Shuah static void 1362241Shuah set_model_info() 1372241Shuah { 1383123Ssubhan extern int ts_dispatch_extended; 1392241Shuah char name[MAXSYSNAME]; 1402241Shuah int i; 1412241Shuah 1422241Shuah /* 1432241Shuah * Get model name from the root node. 1442241Shuah * 1452241Shuah * We are using the prom device tree since, at this point, 1462241Shuah * the Solaris device tree is not yet setup. 1472241Shuah */ 1482241Shuah (void) prom_getprop(prom_rootnode(), "model", (caddr_t)name); 1492241Shuah 1502241Shuah for (i = 0; i < opl_num_models; i++) { 1512241Shuah if (strncmp(name, opl_models[i].model_name, MAXSYSNAME) == 0) { 1522241Shuah opl_cur_model = &opl_models[i]; 1532241Shuah break; 1542241Shuah } 1552241Shuah } 1563123Ssubhan 1575539Swh31274 /* 1585539Swh31274 * If model not matched, it's an unknown model. 1596297Sjl139090 * Just return. It will default to standard dispatch tables. 1605539Swh31274 */ 1612241Shuah if (i == opl_num_models) 1625539Swh31274 return; 1633123Ssubhan 1643123Ssubhan if ((opl_cur_model->model_cmds & EXT_DISPATCH_TABLE) && 1655037Sjl139090 (ts_dispatch_extended == -1)) { 1663123Ssubhan /* 1673123Ssubhan * Based on a platform model, select a dispatch table. 1683123Ssubhan * Only DC2 and DC3 systems uses the alternate/extended 1693123Ssubhan * TS dispatch table. 1706297Sjl139090 * IKKAKU, FF1, FF2 and DC1 systems use standard dispatch 1716297Sjl139090 * tables. 1723123Ssubhan */ 1733123Ssubhan ts_dispatch_extended = 1; 1743123Ssubhan } 1753123Ssubhan 1762241Shuah } 1772241Shuah 1782241Shuah static void 1792241Shuah set_max_mmu_ctxdoms() 1802241Shuah { 1812241Shuah extern uint_t max_mmu_ctxdoms; 1822241Shuah int max_boards; 1832241Shuah 1842241Shuah /* 1852241Shuah * From the model, get the maximum number of boards 1862241Shuah * supported and set the value accordingly. If the model 1872241Shuah * could not be determined or recognized, we assume the max value. 1882241Shuah */ 1892241Shuah if (opl_cur_model == NULL) 1902241Shuah max_boards = OPL_MAX_BOARDS; 1912241Shuah else 1922241Shuah max_boards = opl_cur_model->model_max_boards; 1932241Shuah 1942241Shuah /* 1952241Shuah * On OPL, cores and MMUs are one-to-one. 1962241Shuah */ 1972241Shuah max_mmu_ctxdoms = OPL_MAX_CORE_UNITS_PER_BOARD * max_boards; 1982241Shuah } 1992241Shuah 2001772Sjl139090 #pragma weak mmu_init_large_pages 2011772Sjl139090 2021772Sjl139090 void 2031772Sjl139090 set_platform_defaults(void) 2041772Sjl139090 { 2051772Sjl139090 extern char *tod_module_name; 2061772Sjl139090 extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); 2071772Sjl139090 extern void mmu_init_large_pages(size_t); 2081772Sjl139090 2091772Sjl139090 /* Set the CPU signature function pointer */ 2101772Sjl139090 cpu_sgn_func = cpu_sgn_update; 2111772Sjl139090 2121772Sjl139090 /* Set appropriate tod module for OPL platform */ 2131772Sjl139090 ASSERT(tod_module_name == NULL); 2141772Sjl139090 tod_module_name = "todopl"; 2151772Sjl139090 2161772Sjl139090 if ((mmu_page_sizes == max_mmu_page_sizes) && 2172659Ssusans (mmu_ism_pagesize != DEFAULT_ISM_PAGESIZE)) { 2181772Sjl139090 if (&mmu_init_large_pages) 2191772Sjl139090 mmu_init_large_pages(mmu_ism_pagesize); 2201772Sjl139090 } 2211772Sjl139090 2221772Sjl139090 tsb_lgrp_affinity = 1; 2232241Shuah 2242241Shuah set_max_mmu_ctxdoms(); 225*10843SDave.Plauger@Sun.COM 226*10843SDave.Plauger@Sun.COM /* set OPL threshold for compressed dumps */ 227*10843SDave.Plauger@Sun.COM dump_plat_mincpu = DUMP_PLAT_SUN4U_OPL_MINCPU; 2281772Sjl139090 } 2291772Sjl139090 2301772Sjl139090 /* 2311772Sjl139090 * Convert logical a board number to a physical one. 2321772Sjl139090 */ 2331772Sjl139090 2341772Sjl139090 #define LSBPROP "board#" 2351772Sjl139090 #define PSBPROP "physical-board#" 2361772Sjl139090 2371772Sjl139090 int 2381772Sjl139090 opl_get_physical_board(int id) 2391772Sjl139090 { 2401772Sjl139090 dev_info_t *root_dip, *dip = NULL; 2411772Sjl139090 char *dname = NULL; 2421772Sjl139090 int circ; 2431772Sjl139090 2441772Sjl139090 pnode_t pnode; 2451772Sjl139090 char pname[MAXSYSNAME] = {0}; 2461772Sjl139090 2471772Sjl139090 int lsb_id; /* Logical System Board ID */ 2481772Sjl139090 int psb_id; /* Physical System Board ID */ 2491772Sjl139090 2501772Sjl139090 2511772Sjl139090 /* 2521772Sjl139090 * This function is called on early stage of bootup when the 2531772Sjl139090 * kernel device tree is not initialized yet, and also 2541772Sjl139090 * later on when the device tree is up. We want to try 2551772Sjl139090 * the fast track first. 2561772Sjl139090 */ 2571772Sjl139090 root_dip = ddi_root_node(); 2581772Sjl139090 if (root_dip) { 2591772Sjl139090 /* Get from devinfo node */ 2601772Sjl139090 ndi_devi_enter(root_dip, &circ); 2611772Sjl139090 for (dip = ddi_get_child(root_dip); dip; 2621772Sjl139090 dip = ddi_get_next_sibling(dip)) { 2631772Sjl139090 2641772Sjl139090 dname = ddi_node_name(dip); 2651772Sjl139090 if (strncmp(dname, "pseudo-mc", 9) != 0) 2661772Sjl139090 continue; 2671772Sjl139090 2681772Sjl139090 if ((lsb_id = (int)ddi_getprop(DDI_DEV_T_ANY, dip, 2691772Sjl139090 DDI_PROP_DONTPASS, LSBPROP, -1)) == -1) 2701772Sjl139090 continue; 2711772Sjl139090 2721772Sjl139090 if (id == lsb_id) { 2731772Sjl139090 if ((psb_id = (int)ddi_getprop(DDI_DEV_T_ANY, 2741772Sjl139090 dip, DDI_PROP_DONTPASS, PSBPROP, -1)) 2751772Sjl139090 == -1) { 2761772Sjl139090 ndi_devi_exit(root_dip, circ); 2771772Sjl139090 return (-1); 2781772Sjl139090 } else { 2791772Sjl139090 ndi_devi_exit(root_dip, circ); 2801772Sjl139090 return (psb_id); 2811772Sjl139090 } 2821772Sjl139090 } 2831772Sjl139090 } 2841772Sjl139090 ndi_devi_exit(root_dip, circ); 2851772Sjl139090 } 2861772Sjl139090 2871772Sjl139090 /* 2881772Sjl139090 * We do not have the kernel device tree, or we did not 2891772Sjl139090 * find the node for some reason (let's say the kernel 2901772Sjl139090 * device tree was modified), let's try the OBP tree. 2911772Sjl139090 */ 2921772Sjl139090 pnode = prom_rootnode(); 2931772Sjl139090 for (pnode = prom_childnode(pnode); pnode; 2941772Sjl139090 pnode = prom_nextnode(pnode)) { 2951772Sjl139090 2961772Sjl139090 if ((prom_getprop(pnode, "name", (caddr_t)pname) == -1) || 2971772Sjl139090 (strncmp(pname, "pseudo-mc", 9) != 0)) 2981772Sjl139090 continue; 2991772Sjl139090 3001772Sjl139090 if (prom_getprop(pnode, LSBPROP, (caddr_t)&lsb_id) == -1) 3011772Sjl139090 continue; 3021772Sjl139090 3031772Sjl139090 if (id == lsb_id) { 3041772Sjl139090 if (prom_getprop(pnode, PSBPROP, 3051772Sjl139090 (caddr_t)&psb_id) == -1) { 3061772Sjl139090 return (-1); 3071772Sjl139090 } else { 3081772Sjl139090 return (psb_id); 3091772Sjl139090 } 3101772Sjl139090 } 3111772Sjl139090 } 3121772Sjl139090 3131772Sjl139090 return (-1); 3141772Sjl139090 } 3151772Sjl139090 3161772Sjl139090 /* 3171772Sjl139090 * For OPL it's possible that memory from two or more successive boards 3181772Sjl139090 * will be contiguous across the boards, and therefore represented as a 3191772Sjl139090 * single chunk. 3201772Sjl139090 * This function splits such chunks down the board boundaries. 3211772Sjl139090 */ 3221772Sjl139090 static struct memlist * 3231772Sjl139090 opl_memlist_per_board(struct memlist *ml) 3241772Sjl139090 { 3251772Sjl139090 uint64_t ssize, low, high, boundary; 3261772Sjl139090 struct memlist *head, *tail, *new; 3271772Sjl139090 3281772Sjl139090 ssize = (1ull << OPL_MC_MEMBOARD_SHIFT); 3291772Sjl139090 3301772Sjl139090 head = tail = NULL; 3311772Sjl139090 3321772Sjl139090 for (; ml; ml = ml->next) { 3331772Sjl139090 low = (uint64_t)ml->address; 3341772Sjl139090 high = low+(uint64_t)(ml->size); 3351772Sjl139090 while (low < high) { 3361772Sjl139090 boundary = roundup(low+1, ssize); 3371772Sjl139090 boundary = MIN(high, boundary); 3381772Sjl139090 new = kmem_zalloc(sizeof (struct memlist), KM_SLEEP); 3391772Sjl139090 new->address = low; 3401772Sjl139090 new->size = boundary - low; 3411772Sjl139090 if (head == NULL) 3421772Sjl139090 head = new; 3431772Sjl139090 if (tail) { 3441772Sjl139090 tail->next = new; 3451772Sjl139090 new->prev = tail; 3461772Sjl139090 } 3471772Sjl139090 tail = new; 3481772Sjl139090 low = boundary; 3491772Sjl139090 } 3501772Sjl139090 } 3511772Sjl139090 return (head); 3521772Sjl139090 } 3531772Sjl139090 3541772Sjl139090 void 3551772Sjl139090 set_platform_cage_params(void) 3561772Sjl139090 { 3571772Sjl139090 extern pgcnt_t total_pages; 3581772Sjl139090 extern struct memlist *phys_avail; 3591772Sjl139090 struct memlist *ml, *tml; 3601772Sjl139090 3611772Sjl139090 if (kernel_cage_enable) { 3621772Sjl139090 pgcnt_t preferred_cage_size; 3631772Sjl139090 3645037Sjl139090 preferred_cage_size = MAX(opl_startup_cage_size, 3655037Sjl139090 total_pages / 256); 3661772Sjl139090 3671772Sjl139090 ml = opl_memlist_per_board(phys_avail); 3681772Sjl139090 3691772Sjl139090 /* 3701772Sjl139090 * Note: we are assuming that post has load the 3711772Sjl139090 * whole show in to the high end of memory. Having 3721772Sjl139090 * taken this leap, we copy the whole of phys_avail 3731772Sjl139090 * the glist and arrange for the cage to grow 3741772Sjl139090 * downward (descending pfns). 3751772Sjl139090 */ 3764266Sdp78419 kcage_range_init(ml, KCAGE_DOWN, preferred_cage_size); 3771772Sjl139090 3781772Sjl139090 /* free the memlist */ 3791772Sjl139090 do { 3801772Sjl139090 tml = ml->next; 3811772Sjl139090 kmem_free(ml, sizeof (struct memlist)); 3821772Sjl139090 ml = tml; 3831772Sjl139090 } while (ml != NULL); 3841772Sjl139090 } 3851772Sjl139090 3861772Sjl139090 if (kcage_on) 3871772Sjl139090 cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED"); 3881772Sjl139090 else 3891772Sjl139090 cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED"); 3901772Sjl139090 } 3911772Sjl139090 3921772Sjl139090 /*ARGSUSED*/ 3931772Sjl139090 int 3941772Sjl139090 plat_cpu_poweron(struct cpu *cp) 3951772Sjl139090 { 3961772Sjl139090 int (*opl_cpu_poweron)(struct cpu *) = NULL; 3971772Sjl139090 3981772Sjl139090 opl_cpu_poweron = 3991772Sjl139090 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0); 4001772Sjl139090 4011772Sjl139090 if (opl_cpu_poweron == NULL) 4021772Sjl139090 return (ENOTSUP); 4031772Sjl139090 else 4041772Sjl139090 return ((opl_cpu_poweron)(cp)); 4051772Sjl139090 4061772Sjl139090 } 4071772Sjl139090 4081772Sjl139090 /*ARGSUSED*/ 4091772Sjl139090 int 4101772Sjl139090 plat_cpu_poweroff(struct cpu *cp) 4111772Sjl139090 { 4121772Sjl139090 int (*opl_cpu_poweroff)(struct cpu *) = NULL; 4131772Sjl139090 4141772Sjl139090 opl_cpu_poweroff = 4151772Sjl139090 (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0); 4161772Sjl139090 4171772Sjl139090 if (opl_cpu_poweroff == NULL) 4181772Sjl139090 return (ENOTSUP); 4191772Sjl139090 else 4201772Sjl139090 return ((opl_cpu_poweroff)(cp)); 4211772Sjl139090 4221772Sjl139090 } 4231772Sjl139090 4241772Sjl139090 int 4251772Sjl139090 plat_max_boards(void) 4261772Sjl139090 { 4277206Swh31274 /* 4287206Swh31274 * If the model cannot be determined, default to the max value. 4297206Swh31274 * Otherwise, Ikkaku model only supports 1 system board. 4307206Swh31274 */ 4317206Swh31274 if ((opl_cur_model != NULL) && (opl_cur_model->model_type == IKKAKU)) 4327206Swh31274 return (OPL_MAX_BOARDS_IKKAKU); 4337206Swh31274 else 4347206Swh31274 return (OPL_MAX_BOARDS); 4351772Sjl139090 } 4361772Sjl139090 4371772Sjl139090 int 4381772Sjl139090 plat_max_cpu_units_per_board(void) 4391772Sjl139090 { 4401772Sjl139090 return (OPL_MAX_CPU_PER_BOARD); 4411772Sjl139090 } 4421772Sjl139090 4431772Sjl139090 int 4441772Sjl139090 plat_max_mem_units_per_board(void) 4451772Sjl139090 { 4461772Sjl139090 return (OPL_MAX_MEM_UNITS_PER_BOARD); 4471772Sjl139090 } 4481772Sjl139090 4491772Sjl139090 int 4501772Sjl139090 plat_max_io_units_per_board(void) 4511772Sjl139090 { 4521772Sjl139090 return (OPL_MAX_IO_UNITS_PER_BOARD); 4531772Sjl139090 } 4541772Sjl139090 4551772Sjl139090 int 4561772Sjl139090 plat_max_cmp_units_per_board(void) 4571772Sjl139090 { 4581772Sjl139090 return (OPL_MAX_CMP_UNITS_PER_BOARD); 4591772Sjl139090 } 4601772Sjl139090 4611772Sjl139090 int 4621772Sjl139090 plat_max_core_units_per_board(void) 4631772Sjl139090 { 4641772Sjl139090 return (OPL_MAX_CORE_UNITS_PER_BOARD); 4651772Sjl139090 } 4661772Sjl139090 4671772Sjl139090 int 4681772Sjl139090 plat_pfn_to_mem_node(pfn_t pfn) 4691772Sjl139090 { 4701772Sjl139090 return (pfn >> mem_node_pfn_shift); 4711772Sjl139090 } 4721772Sjl139090 4731772Sjl139090 /* ARGSUSED */ 4741772Sjl139090 void 4755648Ssetje plat_build_mem_nodes(prom_memlist_t *list, size_t nelems) 4761772Sjl139090 { 4771772Sjl139090 size_t elem; 4781772Sjl139090 pfn_t basepfn; 4791772Sjl139090 pgcnt_t npgs; 4801772Sjl139090 uint64_t boundary, ssize; 4811772Sjl139090 uint64_t low, high; 4821772Sjl139090 4831772Sjl139090 /* 4841772Sjl139090 * OPL mem slices are always aligned on a 256GB boundary. 4851772Sjl139090 */ 4861772Sjl139090 mem_node_pfn_shift = OPL_MC_MEMBOARD_SHIFT - MMU_PAGESHIFT; 4871772Sjl139090 mem_node_physalign = 0; 4881772Sjl139090 4891772Sjl139090 /* 4901772Sjl139090 * Boot install lists are arranged <addr, len>, <addr, len>, ... 4911772Sjl139090 */ 4921772Sjl139090 ssize = (1ull << OPL_MC_MEMBOARD_SHIFT); 4935648Ssetje for (elem = 0; elem < nelems; list++, elem++) { 4945648Ssetje low = list->addr; 4955648Ssetje high = low + list->size; 4961772Sjl139090 while (low < high) { 4971772Sjl139090 boundary = roundup(low+1, ssize); 4981772Sjl139090 boundary = MIN(high, boundary); 4991772Sjl139090 basepfn = btop(low); 5001772Sjl139090 npgs = btop(boundary - low); 5011772Sjl139090 mem_node_add_slice(basepfn, basepfn + npgs - 1); 5021772Sjl139090 low = boundary; 5031772Sjl139090 } 5041772Sjl139090 } 5051772Sjl139090 } 5061772Sjl139090 5071772Sjl139090 /* 5081772Sjl139090 * Find the CPU associated with a slice at boot-time. 5091772Sjl139090 */ 5101772Sjl139090 void 5111772Sjl139090 plat_fill_mc(pnode_t nodeid) 5121772Sjl139090 { 5131772Sjl139090 int board; 5141772Sjl139090 int memnode; 5151772Sjl139090 struct { 5161772Sjl139090 uint64_t addr; 5171772Sjl139090 uint64_t size; 5181772Sjl139090 } mem_range; 5191772Sjl139090 5201772Sjl139090 if (prom_getprop(nodeid, "board#", (caddr_t)&board) < 0) { 5211772Sjl139090 panic("Can not find board# property in mc node %x", nodeid); 5221772Sjl139090 } 5231772Sjl139090 if (prom_getprop(nodeid, "sb-mem-ranges", (caddr_t)&mem_range) < 0) { 5241772Sjl139090 panic("Can not find sb-mem-ranges property in mc node %x", 5255037Sjl139090 nodeid); 5261772Sjl139090 } 5271772Sjl139090 memnode = mem_range.addr >> OPL_MC_MEMBOARD_SHIFT; 5281772Sjl139090 plat_assign_lgrphand_to_mem_node(board, memnode); 5291772Sjl139090 } 5301772Sjl139090 5311772Sjl139090 /* 5321772Sjl139090 * Return the platform handle for the lgroup containing the given CPU 5331772Sjl139090 * 5341772Sjl139090 * For OPL, lgroup platform handle == board #. 5351772Sjl139090 */ 5361772Sjl139090 5371772Sjl139090 extern int mpo_disabled; 5381772Sjl139090 extern lgrp_handle_t lgrp_default_handle; 5391772Sjl139090 5401772Sjl139090 lgrp_handle_t 5411772Sjl139090 plat_lgrp_cpu_to_hand(processorid_t id) 5421772Sjl139090 { 5431772Sjl139090 lgrp_handle_t plathand; 5441772Sjl139090 5451772Sjl139090 /* 5461772Sjl139090 * Return the real platform handle for the CPU until 5471772Sjl139090 * such time as we know that MPO should be disabled. 5481772Sjl139090 * At that point, we set the "mpo_disabled" flag to true, 5491772Sjl139090 * and from that point on, return the default handle. 5501772Sjl139090 * 5511772Sjl139090 * By the time we know that MPO should be disabled, the 5521772Sjl139090 * first CPU will have already been added to a leaf 5531772Sjl139090 * lgroup, but that's ok. The common lgroup code will 5541772Sjl139090 * double check that the boot CPU is in the correct place, 5551772Sjl139090 * and in the case where mpo should be disabled, will move 5561772Sjl139090 * it to the root if necessary. 5571772Sjl139090 */ 5581772Sjl139090 if (mpo_disabled) { 5591772Sjl139090 /* If MPO is disabled, return the default (UMA) handle */ 5601772Sjl139090 plathand = lgrp_default_handle; 5611772Sjl139090 } else 5621772Sjl139090 plathand = (lgrp_handle_t)LSB_ID(id); 5631772Sjl139090 return (plathand); 5641772Sjl139090 } 5651772Sjl139090 5661772Sjl139090 /* 5671772Sjl139090 * Platform specific lgroup initialization 5681772Sjl139090 */ 5691772Sjl139090 void 5701772Sjl139090 plat_lgrp_init(void) 5711772Sjl139090 { 5721772Sjl139090 extern uint32_t lgrp_expand_proc_thresh; 5731772Sjl139090 extern uint32_t lgrp_expand_proc_diff; 5746641Spm145316 const uint_t m = LGRP_LOADAVG_THREAD_MAX; 5751772Sjl139090 5761772Sjl139090 /* 5771772Sjl139090 * Set tuneables for the OPL architecture 5781772Sjl139090 * 5796641Spm145316 * lgrp_expand_proc_thresh is the threshold load on the set of 5806641Spm145316 * lgroups a process is currently using on before considering 5816641Spm145316 * adding another lgroup to the set. For Oly-C and Jupiter 5826641Spm145316 * systems, there are four sockets per lgroup. Setting 5836641Spm145316 * lgrp_expand_proc_thresh to add lgroups when the load reaches 5846641Spm145316 * four threads will spread the load when it exceeds one thread 5856641Spm145316 * per socket, optimizing memory bandwidth and L2 cache space. 5866641Spm145316 * 5876641Spm145316 * lgrp_expand_proc_diff determines how much less another lgroup 5886641Spm145316 * must be loaded before shifting the start location of a thread 5896641Spm145316 * to it. 5906641Spm145316 * 5916641Spm145316 * lgrp_loadavg_tolerance is the threshold where two lgroups are 5926641Spm145316 * considered to have different loads. It is set to be less than 5936641Spm145316 * 1% so that even a small residual load will be considered different 5946641Spm145316 * from no residual load. 5951772Sjl139090 * 5966641Spm145316 * We note loadavg values are not precise. 5976641Spm145316 * Every 1/10 of a second loadavg values are reduced by 5%. 5986641Spm145316 * This adjustment can come in the middle of the lgroup selection 5996641Spm145316 * process, and for larger parallel apps with many threads can 6006641Spm145316 * frequently occur between the start of the second thread 6016641Spm145316 * placement and the finish of the last thread placement. 6026641Spm145316 * We also must be careful to not use too small of a threshold 6036641Spm145316 * since the cumulative decay for 1 second idle time is 40%. 6046641Spm145316 * That is, the residual load from completed threads will still 6056641Spm145316 * be 60% one second after the proc goes idle or 8% after 5 seconds. 6061772Sjl139090 * 6076641Spm145316 * To allow for lag time in loadavg calculations 6086641Spm145316 * remote thresh = 3.75 * LGRP_LOADAVG_THREAD_MAX 6096641Spm145316 * local thresh = 0.75 * LGRP_LOADAVG_THREAD_MAX 6106641Spm145316 * tolerance = 0.0078 * LGRP_LOADAVG_THREAD_MAX 6116641Spm145316 * 6126641Spm145316 * The load placement algorithms consider LGRP_LOADAVG_THREAD_MAX 6136641Spm145316 * as the equivalent of a load of 1. To make the code more compact, 6146641Spm145316 * we set m = LGRP_LOADAVG_THREAD_MAX. 6151772Sjl139090 */ 6166641Spm145316 lgrp_expand_proc_thresh = (m * 3) + (m >> 1) + (m >> 2); 6176641Spm145316 lgrp_expand_proc_diff = (m >> 1) + (m >> 2); 6186641Spm145316 lgrp_loadavg_tolerance = (m >> 7); 6191772Sjl139090 } 6201772Sjl139090 6211772Sjl139090 /* 6221772Sjl139090 * Platform notification of lgroup (re)configuration changes 6231772Sjl139090 */ 6241772Sjl139090 /*ARGSUSED*/ 6251772Sjl139090 void 6261772Sjl139090 plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg) 6271772Sjl139090 { 6281772Sjl139090 update_membounds_t *umb; 6291772Sjl139090 lgrp_config_mem_rename_t lmr; 6301772Sjl139090 int sbd, tbd; 6311772Sjl139090 lgrp_handle_t hand, shand, thand; 6321772Sjl139090 int mnode, snode, tnode; 6331772Sjl139090 pfn_t start, end; 6341772Sjl139090 6351772Sjl139090 if (mpo_disabled) 6361772Sjl139090 return; 6371772Sjl139090 6381772Sjl139090 switch (evt) { 6391772Sjl139090 6401772Sjl139090 case LGRP_CONFIG_MEM_ADD: 6411772Sjl139090 /* 6421772Sjl139090 * Establish the lgroup handle to memnode translation. 6431772Sjl139090 */ 6441772Sjl139090 umb = (update_membounds_t *)arg; 6451772Sjl139090 6461772Sjl139090 hand = umb->u_board; 6471772Sjl139090 mnode = plat_pfn_to_mem_node(umb->u_base >> MMU_PAGESHIFT); 6481772Sjl139090 plat_assign_lgrphand_to_mem_node(hand, mnode); 6491772Sjl139090 6501772Sjl139090 break; 6511772Sjl139090 6521772Sjl139090 case LGRP_CONFIG_MEM_DEL: 6531772Sjl139090 /* 6541772Sjl139090 * Special handling for possible memory holes. 6551772Sjl139090 */ 6561772Sjl139090 umb = (update_membounds_t *)arg; 6571772Sjl139090 hand = umb->u_board; 6581772Sjl139090 if ((mnode = plat_lgrphand_to_mem_node(hand)) != -1) { 6591772Sjl139090 if (mem_node_config[mnode].exists) { 6601772Sjl139090 start = mem_node_config[mnode].physbase; 6611772Sjl139090 end = mem_node_config[mnode].physmax; 66210106SJason.Beloro@Sun.COM mem_node_del_slice(start, end); 6631772Sjl139090 } 6641772Sjl139090 } 6651772Sjl139090 6661772Sjl139090 break; 6671772Sjl139090 6681772Sjl139090 case LGRP_CONFIG_MEM_RENAME: 6691772Sjl139090 /* 6701772Sjl139090 * During a DR copy-rename operation, all of the memory 6711772Sjl139090 * on one board is moved to another board -- but the 6721772Sjl139090 * addresses/pfns and memnodes don't change. This means 6731772Sjl139090 * the memory has changed locations without changing identity. 6741772Sjl139090 * 6751772Sjl139090 * Source is where we are copying from and target is where we 6761772Sjl139090 * are copying to. After source memnode is copied to target 6771772Sjl139090 * memnode, the physical addresses of the target memnode are 6781772Sjl139090 * renamed to match what the source memnode had. Then target 6791772Sjl139090 * memnode can be removed and source memnode can take its 6801772Sjl139090 * place. 6811772Sjl139090 * 6821772Sjl139090 * To do this, swap the lgroup handle to memnode mappings for 6831772Sjl139090 * the boards, so target lgroup will have source memnode and 6841772Sjl139090 * source lgroup will have empty target memnode which is where 6851772Sjl139090 * its memory will go (if any is added to it later). 6861772Sjl139090 * 6871772Sjl139090 * Then source memnode needs to be removed from its lgroup 6881772Sjl139090 * and added to the target lgroup where the memory was living 6891772Sjl139090 * but under a different name/memnode. The memory was in the 6901772Sjl139090 * target memnode and now lives in the source memnode with 6911772Sjl139090 * different physical addresses even though it is the same 6921772Sjl139090 * memory. 6931772Sjl139090 */ 6941772Sjl139090 sbd = arg & 0xffff; 6951772Sjl139090 tbd = (arg & 0xffff0000) >> 16; 6961772Sjl139090 shand = sbd; 6971772Sjl139090 thand = tbd; 6981772Sjl139090 snode = plat_lgrphand_to_mem_node(shand); 6991772Sjl139090 tnode = plat_lgrphand_to_mem_node(thand); 7001772Sjl139090 7011772Sjl139090 /* 7021772Sjl139090 * Special handling for possible memory holes. 7031772Sjl139090 */ 7041772Sjl139090 if (tnode != -1 && mem_node_config[tnode].exists) { 7053354Sjl139090 start = mem_node_config[tnode].physbase; 7063354Sjl139090 end = mem_node_config[tnode].physmax; 70710106SJason.Beloro@Sun.COM mem_node_del_slice(start, end); 7081772Sjl139090 } 7091772Sjl139090 7101772Sjl139090 plat_assign_lgrphand_to_mem_node(thand, snode); 7111772Sjl139090 plat_assign_lgrphand_to_mem_node(shand, tnode); 7121772Sjl139090 7131772Sjl139090 lmr.lmem_rename_from = shand; 7141772Sjl139090 lmr.lmem_rename_to = thand; 7151772Sjl139090 7161772Sjl139090 /* 7171772Sjl139090 * Remove source memnode of copy rename from its lgroup 7181772Sjl139090 * and add it to its new target lgroup 7191772Sjl139090 */ 7201772Sjl139090 lgrp_config(LGRP_CONFIG_MEM_RENAME, (uintptr_t)snode, 7211772Sjl139090 (uintptr_t)&lmr); 7221772Sjl139090 7231772Sjl139090 break; 7241772Sjl139090 7251772Sjl139090 default: 7261772Sjl139090 break; 7271772Sjl139090 } 7281772Sjl139090 } 7291772Sjl139090 7301772Sjl139090 /* 7311772Sjl139090 * Return latency between "from" and "to" lgroups 7321772Sjl139090 * 7331772Sjl139090 * This latency number can only be used for relative comparison 7341772Sjl139090 * between lgroups on the running system, cannot be used across platforms, 7351772Sjl139090 * and may not reflect the actual latency. It is platform and implementation 7361772Sjl139090 * specific, so platform gets to decide its value. It would be nice if the 7371772Sjl139090 * number was at least proportional to make comparisons more meaningful though. 7381772Sjl139090 * NOTE: The numbers below are supposed to be load latencies for uncached 7391772Sjl139090 * memory divided by 10. 7401772Sjl139090 * 7411772Sjl139090 */ 7421772Sjl139090 int 7431772Sjl139090 plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to) 7441772Sjl139090 { 7451772Sjl139090 /* 7461772Sjl139090 * Return min remote latency when there are more than two lgroups 7471772Sjl139090 * (root and child) and getting latency between two different lgroups 7481772Sjl139090 * or root is involved 7491772Sjl139090 */ 7501772Sjl139090 if (lgrp_optimizations() && (from != to || 7511772Sjl139090 from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE)) 7522491Shyw return (42); 7531772Sjl139090 else 7542491Shyw return (35); 7551772Sjl139090 } 7561772Sjl139090 7571772Sjl139090 /* 7581772Sjl139090 * Return platform handle for root lgroup 7591772Sjl139090 */ 7601772Sjl139090 lgrp_handle_t 7611772Sjl139090 plat_lgrp_root_hand(void) 7621772Sjl139090 { 7631772Sjl139090 if (mpo_disabled) 7641772Sjl139090 return (lgrp_default_handle); 7651772Sjl139090 7661772Sjl139090 return (LGRP_DEFAULT_HANDLE); 7671772Sjl139090 } 7681772Sjl139090 7691772Sjl139090 /*ARGSUSED*/ 7701772Sjl139090 void 7711772Sjl139090 plat_freelist_process(int mnode) 7721772Sjl139090 { 7731772Sjl139090 } 7741772Sjl139090 7751772Sjl139090 void 7761772Sjl139090 load_platform_drivers(void) 7771772Sjl139090 { 7781772Sjl139090 (void) i_ddi_attach_pseudo_node("dr"); 7791772Sjl139090 } 7801772Sjl139090 7811772Sjl139090 /* 7821772Sjl139090 * No platform drivers on this platform 7831772Sjl139090 */ 7841772Sjl139090 char *platform_module_list[] = { 7851772Sjl139090 (char *)0 7861772Sjl139090 }; 7871772Sjl139090 7881772Sjl139090 /*ARGSUSED*/ 7891772Sjl139090 void 7901772Sjl139090 plat_tod_fault(enum tod_fault_type tod_bad) 7911772Sjl139090 { 7921772Sjl139090 } 7931772Sjl139090 7941772Sjl139090 /*ARGSUSED*/ 7951772Sjl139090 void 7961772Sjl139090 cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid) 7971772Sjl139090 { 7981772Sjl139090 static void (*scf_panic_callback)(int); 7991772Sjl139090 static void (*scf_shutdown_callback)(int); 8001772Sjl139090 8011772Sjl139090 /* 8021772Sjl139090 * This is for notifing system panic/shutdown to SCF. 8031772Sjl139090 * In case of shutdown and panic, SCF call back 8041772Sjl139090 * function should be called. 8051772Sjl139090 * <SCF call back functions> 8061772Sjl139090 * scf_panic_callb() : panicsys()->panic_quiesce_hw() 8071772Sjl139090 * scf_shutdown_callb(): halt() or power_down() or reboot_machine() 8081772Sjl139090 * cpuid should be -1 and state should be SIGST_EXIT. 8091772Sjl139090 */ 8101772Sjl139090 if (state == SIGST_EXIT && cpuid == -1) { 8111772Sjl139090 8121772Sjl139090 /* 8131772Sjl139090 * find the symbol for the SCF panic callback routine in driver 8141772Sjl139090 */ 8151772Sjl139090 if (scf_panic_callback == NULL) 8161772Sjl139090 scf_panic_callback = (void (*)(int)) 8175037Sjl139090 modgetsymvalue("scf_panic_callb", 0); 8181772Sjl139090 if (scf_shutdown_callback == NULL) 8191772Sjl139090 scf_shutdown_callback = (void (*)(int)) 8205037Sjl139090 modgetsymvalue("scf_shutdown_callb", 0); 8211772Sjl139090 8221772Sjl139090 switch (sub_state) { 8231772Sjl139090 case SIGSUBST_PANIC: 8241772Sjl139090 if (scf_panic_callback == NULL) { 8251772Sjl139090 cmn_err(CE_NOTE, "!cpu_sgn_update: " 8261772Sjl139090 "scf_panic_callb not found\n"); 8271772Sjl139090 return; 8281772Sjl139090 } 8291772Sjl139090 scf_panic_callback(SIGSUBST_PANIC); 8301772Sjl139090 break; 8311772Sjl139090 8321772Sjl139090 case SIGSUBST_HALT: 8331772Sjl139090 if (scf_shutdown_callback == NULL) { 8341772Sjl139090 cmn_err(CE_NOTE, "!cpu_sgn_update: " 8351772Sjl139090 "scf_shutdown_callb not found\n"); 8361772Sjl139090 return; 8371772Sjl139090 } 8381772Sjl139090 scf_shutdown_callback(SIGSUBST_HALT); 8391772Sjl139090 break; 8401772Sjl139090 8411772Sjl139090 case SIGSUBST_ENVIRON: 8421772Sjl139090 if (scf_shutdown_callback == NULL) { 8431772Sjl139090 cmn_err(CE_NOTE, "!cpu_sgn_update: " 8441772Sjl139090 "scf_shutdown_callb not found\n"); 8451772Sjl139090 return; 8461772Sjl139090 } 8471772Sjl139090 scf_shutdown_callback(SIGSUBST_ENVIRON); 8481772Sjl139090 break; 8491772Sjl139090 8501772Sjl139090 case SIGSUBST_REBOOT: 8511772Sjl139090 if (scf_shutdown_callback == NULL) { 8521772Sjl139090 cmn_err(CE_NOTE, "!cpu_sgn_update: " 8531772Sjl139090 "scf_shutdown_callb not found\n"); 8541772Sjl139090 return; 8551772Sjl139090 } 8561772Sjl139090 scf_shutdown_callback(SIGSUBST_REBOOT); 8571772Sjl139090 break; 8581772Sjl139090 } 8591772Sjl139090 } 8601772Sjl139090 } 8611772Sjl139090 8621772Sjl139090 /*ARGSUSED*/ 8631772Sjl139090 int 8641772Sjl139090 plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id, 8651772Sjl139090 int flt_in_memory, ushort_t flt_status, 8661772Sjl139090 char *buf, int buflen, int *lenp) 8671772Sjl139090 { 8681772Sjl139090 /* 8691772Sjl139090 * check if it's a Memory error. 8701772Sjl139090 */ 8711772Sjl139090 if (flt_in_memory) { 8721772Sjl139090 if (opl_get_mem_unum != NULL) { 8735037Sjl139090 return (opl_get_mem_unum(synd_code, flt_addr, buf, 8745037Sjl139090 buflen, lenp)); 8751772Sjl139090 } else { 8761772Sjl139090 return (ENOTSUP); 8771772Sjl139090 } 8781772Sjl139090 } else { 8791772Sjl139090 return (ENOTSUP); 8801772Sjl139090 } 8811772Sjl139090 } 8821772Sjl139090 8831772Sjl139090 /*ARGSUSED*/ 8841772Sjl139090 int 8851772Sjl139090 plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp) 8861772Sjl139090 { 8872214Sav145390 int ret = 0; 8885347Sjfrank int sb; 8893123Ssubhan int plen; 8901772Sjl139090 8911772Sjl139090 sb = opl_get_physical_board(LSB_ID(cpuid)); 8921772Sjl139090 if (sb == -1) { 8931772Sjl139090 return (ENXIO); 8941772Sjl139090 } 8951772Sjl139090 8963627Ssubhan /* 8973627Ssubhan * opl_cur_model is assigned here 8983627Ssubhan */ 8993627Ssubhan if (opl_cur_model == NULL) { 9003627Ssubhan set_model_info(); 9015539Swh31274 9025539Swh31274 /* 9035539Swh31274 * if not matched, return 9045539Swh31274 */ 9055539Swh31274 if (opl_cur_model == NULL) 9065539Swh31274 return (ENODEV); 9073627Ssubhan } 9083627Ssubhan 9093123Ssubhan ASSERT((opl_cur_model - opl_models) == (opl_cur_model->model_type)); 9103123Ssubhan 9113123Ssubhan switch (opl_cur_model->model_type) { 9123123Ssubhan case FF1: 9132214Sav145390 plen = snprintf(buf, buflen, "/%s/CPUM%d", "MBU_A", 9142214Sav145390 CHIP_ID(cpuid) / 2); 9152214Sav145390 break; 9162214Sav145390 9173123Ssubhan case FF2: 9182214Sav145390 plen = snprintf(buf, buflen, "/%s/CPUM%d", "MBU_B", 9192808Sav145390 (CHIP_ID(cpuid) / 2) + (sb * 2)); 9202214Sav145390 break; 9212214Sav145390 9223123Ssubhan case DC1: 9233123Ssubhan case DC2: 9243123Ssubhan case DC3: 9252214Sav145390 plen = snprintf(buf, buflen, "/%s%02d/CPUM%d", "CMU", sb, 9262214Sav145390 CHIP_ID(cpuid)); 9272214Sav145390 break; 9282214Sav145390 9296297Sjl139090 case IKKAKU: 9306297Sjl139090 plen = snprintf(buf, buflen, "/%s", "MBU_A"); 9316297Sjl139090 break; 9326297Sjl139090 9332214Sav145390 default: 9342214Sav145390 /* This should never happen */ 9352214Sav145390 return (ENODEV); 9362214Sav145390 } 9372214Sav145390 9382214Sav145390 if (plen >= buflen) { 9392214Sav145390 ret = ENOSPC; 9401772Sjl139090 } else { 9411772Sjl139090 if (lenp) 9421772Sjl139090 *lenp = strlen(buf); 9431772Sjl139090 } 9442214Sav145390 return (ret); 9451772Sjl139090 } 9461772Sjl139090 9471772Sjl139090 void 9481772Sjl139090 plat_nodename_set(void) 9491772Sjl139090 { 9505347Sjfrank post_xscf_msg((char *)&utsname, sizeof (struct utsname)); 9511772Sjl139090 } 9521772Sjl139090 9531772Sjl139090 caddr_t efcode_vaddr = NULL; 9541772Sjl139090 9551772Sjl139090 /* 9561772Sjl139090 * Preallocate enough memory for fcode claims. 9571772Sjl139090 */ 9581772Sjl139090 9591772Sjl139090 caddr_t 9601772Sjl139090 efcode_alloc(caddr_t alloc_base) 9611772Sjl139090 { 9621772Sjl139090 caddr_t efcode_alloc_base = (caddr_t)roundup((uintptr_t)alloc_base, 9631772Sjl139090 MMU_PAGESIZE); 9641772Sjl139090 caddr_t vaddr; 9651772Sjl139090 9661772Sjl139090 /* 9671772Sjl139090 * allocate the physical memory for the Oberon fcode. 9681772Sjl139090 */ 9691772Sjl139090 if ((vaddr = (caddr_t)BOP_ALLOC(bootops, efcode_alloc_base, 9701772Sjl139090 efcode_size, MMU_PAGESIZE)) == NULL) 9711772Sjl139090 cmn_err(CE_PANIC, "Cannot allocate Efcode Memory"); 9721772Sjl139090 9731772Sjl139090 efcode_vaddr = vaddr; 9741772Sjl139090 9751772Sjl139090 return (efcode_alloc_base + efcode_size); 9761772Sjl139090 } 9771772Sjl139090 9781772Sjl139090 caddr_t 9791772Sjl139090 plat_startup_memlist(caddr_t alloc_base) 9801772Sjl139090 { 9811772Sjl139090 caddr_t tmp_alloc_base; 9821772Sjl139090 9831772Sjl139090 tmp_alloc_base = efcode_alloc(alloc_base); 9841772Sjl139090 tmp_alloc_base = 9851772Sjl139090 (caddr_t)roundup((uintptr_t)tmp_alloc_base, ecache_alignsize); 9861772Sjl139090 return (tmp_alloc_base); 9871772Sjl139090 } 9881772Sjl139090 9895834Spt157919 /* need to forward declare these */ 9905834Spt157919 static void plat_lock_delay(uint_t); 9915834Spt157919 9921772Sjl139090 void 9931772Sjl139090 startup_platform(void) 9941772Sjl139090 { 9955788Smv143129 if (clock_tick_threshold == 0) 9965788Smv143129 clock_tick_threshold = OPL_CLOCK_TICK_THRESHOLD; 9975788Smv143129 if (clock_tick_ncpus == 0) 9985788Smv143129 clock_tick_ncpus = OPL_CLOCK_TICK_NCPUS; 9995834Spt157919 mutex_lock_delay = plat_lock_delay; 10005834Spt157919 mutex_cap_factor = OPL_BOFF_MAX_SCALE; 10011772Sjl139090 } 10022214Sav145390 10035923Sjfrank static uint_t 10045923Sjfrank get_mmu_id(processorid_t cpuid) 10055923Sjfrank { 10065923Sjfrank int pb = opl_get_physical_board(LSB_ID(cpuid)); 10075923Sjfrank 10085923Sjfrank if (pb == -1) { 10095923Sjfrank cmn_err(CE_PANIC, 10105923Sjfrank "opl_get_physical_board failed (cpu %d LSB %u)", 10115923Sjfrank cpuid, LSB_ID(cpuid)); 10125923Sjfrank } 10135923Sjfrank return (pb * OPL_MAX_COREID_PER_BOARD) + (CHIP_ID(cpuid) * 10145923Sjfrank OPL_MAX_COREID_PER_CMP) + CORE_ID(cpuid); 10155923Sjfrank } 10165923Sjfrank 10172241Shuah void 10182241Shuah plat_cpuid_to_mmu_ctx_info(processorid_t cpuid, mmu_ctx_info_t *info) 10192241Shuah { 10202241Shuah int impl; 10212241Shuah 10222241Shuah impl = cpunodes[cpuid].implementation; 10235037Sjl139090 if (IS_OLYMPUS_C(impl) || IS_JUPITER(impl)) { 10245923Sjfrank info->mmu_idx = get_mmu_id(cpuid); 10252241Shuah info->mmu_nctxs = 8192; 10262241Shuah } else { 10272241Shuah cmn_err(CE_PANIC, "Unknown processor %d", impl); 10282241Shuah } 10292241Shuah } 10302241Shuah 10312214Sav145390 int 10322214Sav145390 plat_get_mem_sid(char *unum, char *buf, int buflen, int *lenp) 10332214Sav145390 { 10342214Sav145390 if (opl_get_mem_sid == NULL) { 10352214Sav145390 return (ENOTSUP); 10362214Sav145390 } 10372214Sav145390 return (opl_get_mem_sid(unum, buf, buflen, lenp)); 10382214Sav145390 } 10392214Sav145390 10402214Sav145390 int 10412214Sav145390 plat_get_mem_offset(uint64_t paddr, uint64_t *offp) 10422214Sav145390 { 10432214Sav145390 if (opl_get_mem_offset == NULL) { 10442214Sav145390 return (ENOTSUP); 10452214Sav145390 } 10462214Sav145390 return (opl_get_mem_offset(paddr, offp)); 10472214Sav145390 } 10482214Sav145390 10492214Sav145390 int 10502214Sav145390 plat_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *addrp) 10512214Sav145390 { 10522214Sav145390 if (opl_get_mem_addr == NULL) { 10532214Sav145390 return (ENOTSUP); 10542214Sav145390 } 10552214Sav145390 return (opl_get_mem_addr(unum, sid, offset, addrp)); 10562214Sav145390 } 10573914Spm145316 10583914Spm145316 void 10595834Spt157919 plat_lock_delay(uint_t backoff) 10603914Spm145316 { 10613914Spm145316 int i; 10625834Spt157919 uint_t cnt, remcnt; 10633914Spm145316 int ctr; 10645834Spt157919 hrtime_t delay_start, rem_delay; 10653914Spm145316 /* 10663914Spm145316 * Platform specific lock delay code for OPL 10673914Spm145316 * 10683914Spm145316 * Using staged linear increases in the delay. 10693914Spm145316 * The sleep instruction is the preferred method of delay, 10703914Spm145316 * but is too large of granularity for the initial backoff. 10713914Spm145316 */ 10723914Spm145316 10735834Spt157919 if (backoff < 100) { 10743914Spm145316 /* 10753914Spm145316 * If desired backoff is long enough, 10763914Spm145316 * use sleep for most of it 10773914Spm145316 */ 10785834Spt157919 for (cnt = backoff; 10795834Spt157919 cnt >= OPL_BOFF_SLEEP; 10805037Sjl139090 cnt -= OPL_BOFF_SLEEP) { 10813914Spm145316 cpu_smt_pause(); 10823914Spm145316 } 10833914Spm145316 /* 10843914Spm145316 * spin for small remainder of backoff 10853914Spm145316 */ 10863914Spm145316 for (ctr = cnt * OPL_BOFF_SPIN; ctr; ctr--) { 10875834Spt157919 mutex_delay_default(); 10883914Spm145316 } 10893914Spm145316 } else { 10905834Spt157919 /* backoff is large. Fill it by sleeping */ 10916592Sck142721 delay_start = gethrtime_waitfree(); 10925834Spt157919 cnt = backoff / OPL_BOFF_SLEEP; 10933914Spm145316 /* 10943914Spm145316 * use sleep instructions for delay 10953914Spm145316 */ 10963914Spm145316 for (i = 0; i < cnt; i++) { 10973914Spm145316 cpu_smt_pause(); 10983914Spm145316 } 10993914Spm145316 11003914Spm145316 /* 11013914Spm145316 * Note: if the other strand executes a sleep instruction, 11023914Spm145316 * then the sleep ends immediately with a minimum time of 11033914Spm145316 * 42 clocks. We check gethrtime to insure we have 11043914Spm145316 * waited long enough. And we include both a short 11055834Spt157919 * spin loop and a sleep for repeated delay times. 11063914Spm145316 */ 11073914Spm145316 11086592Sck142721 rem_delay = gethrtime_waitfree() - delay_start; 11095834Spt157919 while (rem_delay < cnt * OPL_BOFF_TM) { 11105834Spt157919 remcnt = cnt - (rem_delay / OPL_BOFF_TM); 11115834Spt157919 for (i = 0; i < remcnt; i++) { 11125834Spt157919 cpu_smt_pause(); 11135834Spt157919 for (ctr = OPL_BOFF_SPIN; ctr; ctr--) { 11145834Spt157919 mutex_delay_default(); 11155834Spt157919 } 11163914Spm145316 } 11176592Sck142721 rem_delay = gethrtime_waitfree() - delay_start; 11183914Spm145316 } 11193914Spm145316 } 11203914Spm145316 } 11215347Sjfrank 11225347Sjfrank /* 11235347Sjfrank * The following code implements asynchronous call to XSCF to setup the 11245347Sjfrank * domain node name. 11255347Sjfrank */ 11265347Sjfrank 11275347Sjfrank #define FREE_MSG(m) kmem_free((m), NM_LEN((m)->len)) 11285347Sjfrank 11295347Sjfrank /* 11305347Sjfrank * The following three macros define the all operations on the request 11315347Sjfrank * list we are using here, and hide the details of the list 11325347Sjfrank * implementation from the code. 11335347Sjfrank */ 11345347Sjfrank #define PUSH(m) \ 11355347Sjfrank { \ 11365347Sjfrank (m)->next = ctl_msg.head; \ 11375347Sjfrank (m)->prev = NULL; \ 11385347Sjfrank if ((m)->next != NULL) \ 11395347Sjfrank (m)->next->prev = (m); \ 11405347Sjfrank ctl_msg.head = (m); \ 11415347Sjfrank } 11425347Sjfrank 11435347Sjfrank #define REMOVE(m) \ 11445347Sjfrank { \ 11455347Sjfrank if ((m)->prev != NULL) \ 11465347Sjfrank (m)->prev->next = (m)->next; \ 11475347Sjfrank else \ 11485347Sjfrank ctl_msg.head = (m)->next; \ 11495347Sjfrank if ((m)->next != NULL) \ 11505347Sjfrank (m)->next->prev = (m)->prev; \ 11515347Sjfrank } 11525347Sjfrank 11535347Sjfrank #define FREE_THE_TAIL(head) \ 11545347Sjfrank { \ 11555347Sjfrank nm_msg_t *n_msg, *m; \ 11565347Sjfrank m = (head)->next; \ 11575347Sjfrank (head)->next = NULL; \ 11585347Sjfrank while (m != NULL) { \ 11595347Sjfrank n_msg = m->next; \ 11605347Sjfrank FREE_MSG(m); \ 11615347Sjfrank m = n_msg; \ 11625347Sjfrank } \ 11635347Sjfrank } 11645347Sjfrank 11655347Sjfrank #define SCF_PUTINFO(f, s, p) \ 11665347Sjfrank f(KEY_ESCF, 0x01, 0, s, p) 11675347Sjfrank 11685347Sjfrank #define PASS2XSCF(m, r) ((r = SCF_PUTINFO(ctl_msg.scf_service_function, \ 11695347Sjfrank (m)->len, (m)->data)) == 0) 11705347Sjfrank 11715347Sjfrank /* 11725347Sjfrank * The value of the following macro loosely depends on the 11735347Sjfrank * value of the "device busy" timeout used in the SCF driver. 11745347Sjfrank * (See pass2xscf_thread()). 11755347Sjfrank */ 11765347Sjfrank #define SCF_DEVBUSY_DELAY 10 11775347Sjfrank 11785347Sjfrank /* 11795347Sjfrank * The default number of attempts to contact the scf driver 11805347Sjfrank * if we cannot fetch any information about the timeout value 11815347Sjfrank * it uses. 11825347Sjfrank */ 11835347Sjfrank 11845347Sjfrank #define REPEATS 4 11855347Sjfrank 11865347Sjfrank typedef struct nm_msg { 11875347Sjfrank struct nm_msg *next; 11885347Sjfrank struct nm_msg *prev; 11895347Sjfrank int len; 11905347Sjfrank char data[1]; 11915347Sjfrank } nm_msg_t; 11925347Sjfrank 11935347Sjfrank #define NM_LEN(len) (sizeof (nm_msg_t) + (len) - 1) 11945347Sjfrank 11955347Sjfrank static struct ctlmsg { 11965347Sjfrank nm_msg_t *head; 11975347Sjfrank nm_msg_t *now_serving; 11985347Sjfrank kmutex_t nm_lock; 11995347Sjfrank kthread_t *nmt; 12005347Sjfrank int cnt; 12015347Sjfrank int (*scf_service_function)(uint32_t, uint8_t, 12025347Sjfrank uint32_t, uint32_t, void *); 12035347Sjfrank } ctl_msg; 12045347Sjfrank 12055347Sjfrank static void 12065347Sjfrank post_xscf_msg(char *dp, int len) 12075347Sjfrank { 12085347Sjfrank nm_msg_t *msg; 12095347Sjfrank 12105347Sjfrank msg = (nm_msg_t *)kmem_zalloc(NM_LEN(len), KM_SLEEP); 12115347Sjfrank 12125347Sjfrank bcopy(dp, msg->data, len); 12135347Sjfrank msg->len = len; 12145347Sjfrank 12155347Sjfrank mutex_enter(&ctl_msg.nm_lock); 12165347Sjfrank if (ctl_msg.nmt == NULL) { 12175347Sjfrank ctl_msg.nmt = thread_create(NULL, 0, pass2xscf_thread, 12185347Sjfrank NULL, 0, &p0, TS_RUN, minclsyspri); 12195347Sjfrank } 12205347Sjfrank 12215347Sjfrank PUSH(msg); 12225347Sjfrank ctl_msg.cnt++; 12235347Sjfrank mutex_exit(&ctl_msg.nm_lock); 12245347Sjfrank } 12255347Sjfrank 12265347Sjfrank static void 12275347Sjfrank pass2xscf_thread() 12285347Sjfrank { 12295347Sjfrank nm_msg_t *msg; 12305347Sjfrank int ret; 12315347Sjfrank uint_t i, msg_sent, xscf_driver_delay; 12325347Sjfrank static uint_t repeat_cnt; 12335347Sjfrank uint_t *scf_wait_cnt; 12345347Sjfrank 12355347Sjfrank mutex_enter(&ctl_msg.nm_lock); 12365347Sjfrank 12375347Sjfrank /* 12385347Sjfrank * Find the address of the SCF put routine if it's not done yet. 12395347Sjfrank */ 12405347Sjfrank if (ctl_msg.scf_service_function == NULL) { 12415347Sjfrank if ((ctl_msg.scf_service_function = 12425347Sjfrank (int (*)(uint32_t, uint8_t, uint32_t, uint32_t, void *)) 12435347Sjfrank modgetsymvalue("scf_service_putinfo", 0)) == NULL) { 12445347Sjfrank cmn_err(CE_NOTE, "pass2xscf_thread: " 12455347Sjfrank "scf_service_putinfo not found\n"); 12465347Sjfrank ctl_msg.nmt = NULL; 12475347Sjfrank mutex_exit(&ctl_msg.nm_lock); 12485347Sjfrank return; 12495347Sjfrank } 12505347Sjfrank } 12515347Sjfrank 12525347Sjfrank /* 12535347Sjfrank * Calculate the number of attempts to connect XSCF based on the 12545347Sjfrank * scf driver delay (which is 12555347Sjfrank * SCF_DEVBUSY_DELAY*scf_online_wait_rcnt seconds) and the value 12565347Sjfrank * of xscf_connect_delay (the total number of seconds to wait 12575347Sjfrank * till xscf get ready.) 12585347Sjfrank */ 12595347Sjfrank if (repeat_cnt == 0) { 12605347Sjfrank if ((scf_wait_cnt = 12615347Sjfrank (uint_t *) 12625347Sjfrank modgetsymvalue("scf_online_wait_rcnt", 0)) == NULL) { 12635347Sjfrank repeat_cnt = REPEATS; 12645347Sjfrank } else { 12655347Sjfrank 12665347Sjfrank xscf_driver_delay = *scf_wait_cnt * 12675347Sjfrank SCF_DEVBUSY_DELAY; 12685347Sjfrank repeat_cnt = (xscf_connect_delay/xscf_driver_delay) + 1; 12695347Sjfrank } 12705347Sjfrank } 12715347Sjfrank 12725347Sjfrank while (ctl_msg.cnt != 0) { 12735347Sjfrank 12745347Sjfrank /* 12755347Sjfrank * Take the very last request from the queue, 12765347Sjfrank */ 12775347Sjfrank ctl_msg.now_serving = ctl_msg.head; 12785347Sjfrank ASSERT(ctl_msg.now_serving != NULL); 12795347Sjfrank 12805347Sjfrank /* 12815347Sjfrank * and discard all the others if any. 12825347Sjfrank */ 12835347Sjfrank FREE_THE_TAIL(ctl_msg.now_serving); 12845347Sjfrank ctl_msg.cnt = 1; 12855347Sjfrank mutex_exit(&ctl_msg.nm_lock); 12865347Sjfrank 12875347Sjfrank /* 12885347Sjfrank * Pass the name to XSCF. Note please, we do not hold the 12895347Sjfrank * mutex while we are doing this. 12905347Sjfrank */ 12915347Sjfrank msg_sent = 0; 12925347Sjfrank for (i = 0; i < repeat_cnt; i++) { 12935347Sjfrank if (PASS2XSCF(ctl_msg.now_serving, ret)) { 12945347Sjfrank msg_sent = 1; 12955347Sjfrank break; 12965347Sjfrank } else { 12975347Sjfrank if (ret != EBUSY) { 12985347Sjfrank cmn_err(CE_NOTE, "pass2xscf_thread:" 12995347Sjfrank " unexpected return code" 13005347Sjfrank " from scf_service_putinfo():" 13015347Sjfrank " %d\n", ret); 13025347Sjfrank } 13035347Sjfrank } 13045347Sjfrank } 13055347Sjfrank 13065347Sjfrank if (msg_sent) { 13075347Sjfrank 13085347Sjfrank /* 13095347Sjfrank * Remove the request from the list 13105347Sjfrank */ 13115347Sjfrank mutex_enter(&ctl_msg.nm_lock); 13125347Sjfrank msg = ctl_msg.now_serving; 13135347Sjfrank ctl_msg.now_serving = NULL; 13145347Sjfrank REMOVE(msg); 13155347Sjfrank ctl_msg.cnt--; 13165347Sjfrank mutex_exit(&ctl_msg.nm_lock); 13175347Sjfrank FREE_MSG(msg); 13185347Sjfrank } else { 13195347Sjfrank 13205347Sjfrank /* 13215347Sjfrank * If while we have tried to communicate with 13225347Sjfrank * XSCF there were any other requests we are 13235347Sjfrank * going to drop this one and take the latest 13245347Sjfrank * one. Otherwise we will try to pass this one 13255347Sjfrank * again. 13265347Sjfrank */ 13275347Sjfrank cmn_err(CE_NOTE, 13285347Sjfrank "pass2xscf_thread: " 13295347Sjfrank "scf_service_putinfo " 13305347Sjfrank "not responding\n"); 13315347Sjfrank } 13325347Sjfrank mutex_enter(&ctl_msg.nm_lock); 13335347Sjfrank } 13345347Sjfrank 13355347Sjfrank /* 13365347Sjfrank * The request queue is empty, exit. 13375347Sjfrank */ 13385347Sjfrank ctl_msg.nmt = NULL; 13395347Sjfrank mutex_exit(&ctl_msg.nm_lock); 13405347Sjfrank } 1341