17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22125be069SJason Beloro * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/errno.h> 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/param.h> 297c478bd9Sstevel@tonic-gate #include <sys/cpu.h> 307c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 317c478bd9Sstevel@tonic-gate #include <sys/clock.h> 327c478bd9Sstevel@tonic-gate #include <sys/promif.h> 337c478bd9Sstevel@tonic-gate #include <sys/promimpl.h> 347c478bd9Sstevel@tonic-gate #include <sys/systm.h> 357c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 367c478bd9Sstevel@tonic-gate #include <sys/debug.h> 377c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 387c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 397c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 407c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 417c478bd9Sstevel@tonic-gate #include <sys/cmp.h> 427c478bd9Sstevel@tonic-gate #include <sys/async.h> 437c478bd9Sstevel@tonic-gate #include <vm/page.h> 442f0fcb93SJason Beloro #include <vm/vm_dep.h> 451ae08745Sheppo #include <vm/hat_sfmmu.h> 461ae08745Sheppo #include <sys/sysmacros.h> 471ae08745Sheppo #include <sys/mach_descrip.h> 481ae08745Sheppo #include <sys/mdesc.h> 491ae08745Sheppo #include <sys/archsystm.h> 501ae08745Sheppo #include <sys/error.h> 511ae08745Sheppo #include <sys/mmu.h> 521ae08745Sheppo #include <sys/bitmap.h> 534bac2208Snarayan #include <sys/intreg.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate struct cpu_node cpunodes[NCPU]; 567c478bd9Sstevel@tonic-gate 571ae08745Sheppo uint64_t cpu_q_entries; 581ae08745Sheppo uint64_t dev_q_entries; 591ae08745Sheppo uint64_t cpu_rq_entries; 601ae08745Sheppo uint64_t cpu_nrq_entries; 61aaa10e67Sha uint64_t ncpu_guest_max; 621ae08745Sheppo 631ae08745Sheppo void fill_cpu(md_t *, mde_cookie_t); 641ae08745Sheppo 651ae08745Sheppo static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t); 6605d3dc4bSpaulsan static uint64_t get_mmu_tsbs(md_t *, mde_cookie_t); 6705d3dc4bSpaulsan static uint64_t get_mmu_shcontexts(md_t *, mde_cookie_t); 681ae08745Sheppo static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t); 69125be069SJason Beloro static int check_mmu_pgsz_search(md_t *, mde_cookie_t); 701ae08745Sheppo static char *construct_isalist(md_t *, mde_cookie_t, char **); 714bac2208Snarayan static void init_md_broken(md_t *, mde_cookie_t *); 721ae08745Sheppo static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *, 731ae08745Sheppo uint64_t *); 742f0fcb93SJason Beloro static void get_hwcaps(md_t *, mde_cookie_t); 752c5124a1SPrashanth Sreenivasa static void get_weakest_mem_model(md_t *, mde_cookie_t); 761ae08745Sheppo static void get_q_sizes(md_t *, mde_cookie_t); 771ae08745Sheppo static void get_va_bits(md_t *, mde_cookie_t); 78*9853d9e8SJason Beloro static size_t get_ra_limit(md_t *, mde_cookie_t); 79575a7426Spt static int get_l2_cache_node_count(md_t *); 802f0fcb93SJason Beloro static unsigned long names2bits(char *tokens, size_t tokenslen, 812f0fcb93SJason Beloro char *bit_formatter, char *warning); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate uint64_t system_clock_freq; 847c478bd9Sstevel@tonic-gate uint_t niommu_tsbs = 0; 857c478bd9Sstevel@tonic-gate 86575a7426Spt static int n_l2_caches = 0; 87575a7426Spt 88fedab560Sae /* prevent compilation with VAC defined */ 89fedab560Sae #ifdef VAC 90fedab560Sae #error "The sun4v architecture does not support VAC" 91fedab560Sae #endif 92fedab560Sae 93fedab560Sae #define S_VAC_SIZE MMU_PAGESIZE 94fedab560Sae #define S_VAC_SHIFT MMU_PAGESHIFT 95fedab560Sae 96fedab560Sae int vac_size = S_VAC_SIZE; 97fedab560Sae uint_t vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1); 98fedab560Sae int vac_shift = S_VAC_SHIFT; 99fedab560Sae uintptr_t shm_alignment = S_VAC_SIZE; 100fedab560Sae 1011ae08745Sheppo void 1021ae08745Sheppo map_wellknown_devices() 1031ae08745Sheppo { 1041ae08745Sheppo } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate void 1071ae08745Sheppo fill_cpu(md_t *mdp, mde_cookie_t cpuc) 1087c478bd9Sstevel@tonic-gate { 1091ae08745Sheppo struct cpu_node *cpunode; 1101ae08745Sheppo uint64_t cpuid; 1111ae08745Sheppo uint64_t clk_freq; 1121ae08745Sheppo char *namebuf; 1131ae08745Sheppo char *namebufp; 1141ae08745Sheppo int namelen; 1151ae08745Sheppo uint64_t associativity = 0, linesize = 0, size = 0; 1161ae08745Sheppo 1171ae08745Sheppo if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) { 1181ae08745Sheppo return; 1191ae08745Sheppo } 1207c478bd9Sstevel@tonic-gate 1214bac2208Snarayan /* All out-of-range cpus will be stopped later. */ 1221ae08745Sheppo if (cpuid >= NCPU) { 1231ae08745Sheppo cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - " 1244bac2208Snarayan "cpu excluded from configuration\n", cpuid); 1251ae08745Sheppo 1261ae08745Sheppo return; 1271ae08745Sheppo } 1281ae08745Sheppo 1291ae08745Sheppo cpunode = &cpunodes[cpuid]; 1301ae08745Sheppo cpunode->cpuid = (int)cpuid; 1311ae08745Sheppo cpunode->device_id = cpuid; 1321ae08745Sheppo 1331ae08745Sheppo if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI)) 1341ae08745Sheppo (void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI); 1351ae08745Sheppo 1361ae08745Sheppo if (md_get_prop_data(mdp, cpuc, 1371ae08745Sheppo "compatible", (uint8_t **)&namebuf, &namelen)) { 1381ae08745Sheppo cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible " 1391ae08745Sheppo "property"); 1401ae08745Sheppo } 1411ae08745Sheppo namebufp = namebuf; 1421ae08745Sheppo if (strncmp(namebufp, "SUNW,", 5) == 0) 1431ae08745Sheppo namebufp += 5; 1441ae08745Sheppo if (strlen(namebufp) > sizeof (cpunode->name)) 1451ae08745Sheppo cmn_err(CE_PANIC, "Compatible property too big to " 1461ae08745Sheppo "fit into the cpunode name buffer"); 1471ae08745Sheppo (void) strcpy(cpunode->name, namebufp); 1481ae08745Sheppo 1491ae08745Sheppo if (md_get_prop_val(mdp, cpuc, 1501ae08745Sheppo "clock-frequency", &clk_freq)) { 1511ae08745Sheppo clk_freq = 0; 1521ae08745Sheppo } 1531ae08745Sheppo cpunode->clock_freq = clk_freq; 1541ae08745Sheppo 1551ae08745Sheppo ASSERT(cpunode->clock_freq != 0); 1567c478bd9Sstevel@tonic-gate /* 1571ae08745Sheppo * Compute scaling factor based on rate of %tick. This is used 1581ae08745Sheppo * to convert from ticks derived from %tick to nanoseconds. See 1591ae08745Sheppo * comment in sun4u/sys/clock.h for details. 1607c478bd9Sstevel@tonic-gate */ 1611ae08745Sheppo cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 1621ae08745Sheppo (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1651ae08745Sheppo * The nodeid is not used in sun4v at all. Setting it 1661ae08745Sheppo * to positive value to make starting of slave CPUs 1671ae08745Sheppo * code happy. 1687c478bd9Sstevel@tonic-gate */ 1691ae08745Sheppo cpunode->nodeid = cpuid + 1; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1721ae08745Sheppo * Obtain the L2 cache information from MD. 1731ae08745Sheppo * If "Cache" node exists, then set L2 cache properties 1741ae08745Sheppo * as read from MD. 1751ae08745Sheppo * If node does not exists, then set the L2 cache properties 1761ae08745Sheppo * in individual CPU module. 1777c478bd9Sstevel@tonic-gate */ 1781ae08745Sheppo if ((!get_l2_cache_info(mdp, cpuc, 1791ae08745Sheppo &associativity, &size, &linesize)) || 1801ae08745Sheppo associativity == 0 || size == 0 || linesize == 0) { 1811ae08745Sheppo cpu_fiximp(cpunode); 1821ae08745Sheppo } else { 1831ae08745Sheppo /* 1841ae08745Sheppo * Do not expect L2 cache properties to be bigger 1851ae08745Sheppo * than 32-bit quantity. 1861ae08745Sheppo */ 1871ae08745Sheppo cpunode->ecache_associativity = (int)associativity; 1881ae08745Sheppo cpunode->ecache_size = (int)size; 1891ae08745Sheppo cpunode->ecache_linesize = (int)linesize; 1907c478bd9Sstevel@tonic-gate } 1911ae08745Sheppo 1921ae08745Sheppo cpunode->ecache_setsize = 1931ae08745Sheppo cpunode->ecache_size / cpunode->ecache_associativity; 1941ae08745Sheppo 19559ac0c16Sdavemq /* 19659ac0c16Sdavemq * Initialize the mapping for exec unit, chip and core. 19759ac0c16Sdavemq */ 1981ae08745Sheppo cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND; 19959ac0c16Sdavemq cpunode->l2_cache_mapping = NO_MAPPING_FOUND; 20059ac0c16Sdavemq cpunode->core_mapping = NO_CORE_MAPPING_FOUND; 2011ae08745Sheppo 2021ae08745Sheppo if (ecache_setsize == 0) 2031ae08745Sheppo ecache_setsize = cpunode->ecache_setsize; 2041ae08745Sheppo if (ecache_alignsize == 0) 2051ae08745Sheppo ecache_alignsize = cpunode->ecache_linesize; 2061ae08745Sheppo 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate 2091ae08745Sheppo void 2101ae08745Sheppo empty_cpu(int cpuid) 2117c478bd9Sstevel@tonic-gate { 2121ae08745Sheppo bzero(&cpunodes[cpuid], sizeof (struct cpu_node)); 2131ae08745Sheppo } 2147c478bd9Sstevel@tonic-gate 21559ac0c16Sdavemq /* 21659ac0c16Sdavemq * Use L2 cache node to derive the chip mapping. 21759ac0c16Sdavemq */ 21859ac0c16Sdavemq void 21959ac0c16Sdavemq setup_chip_mappings(md_t *mdp) 22059ac0c16Sdavemq { 2212f0fcb93SJason Beloro int ncache, ncpu; 22259ac0c16Sdavemq mde_cookie_t *node, *cachelist; 22359ac0c16Sdavemq int i, j; 22459ac0c16Sdavemq processorid_t cpuid; 22559ac0c16Sdavemq int idx = 0; 22659ac0c16Sdavemq 22759ac0c16Sdavemq ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache", 22859ac0c16Sdavemq "fwd", &cachelist); 22959ac0c16Sdavemq 23059ac0c16Sdavemq /* 23159ac0c16Sdavemq * The "cache" node is optional in MD, therefore ncaches can be 0. 23259ac0c16Sdavemq */ 23359ac0c16Sdavemq if (ncache < 1) { 23459ac0c16Sdavemq return; 23559ac0c16Sdavemq } 23659ac0c16Sdavemq 23759ac0c16Sdavemq for (i = 0; i < ncache; i++) { 23859ac0c16Sdavemq uint64_t cache_level; 23959ac0c16Sdavemq uint64_t lcpuid; 24059ac0c16Sdavemq 24159ac0c16Sdavemq if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 24259ac0c16Sdavemq continue; 24359ac0c16Sdavemq 24459ac0c16Sdavemq if (cache_level != 2) 24559ac0c16Sdavemq continue; 24659ac0c16Sdavemq 24759ac0c16Sdavemq /* 24859ac0c16Sdavemq * Found a l2 cache node. Find out the cpu nodes it 24959ac0c16Sdavemq * points to. 25059ac0c16Sdavemq */ 25159ac0c16Sdavemq ncpu = md_alloc_scan_dag(mdp, cachelist[i], "cpu", 25259ac0c16Sdavemq "back", &node); 25359ac0c16Sdavemq 25459ac0c16Sdavemq if (ncpu < 1) 25559ac0c16Sdavemq continue; 25659ac0c16Sdavemq 25759ac0c16Sdavemq for (j = 0; j < ncpu; j++) { 25859ac0c16Sdavemq if (md_get_prop_val(mdp, node[j], "id", &lcpuid)) 25959ac0c16Sdavemq continue; 26059ac0c16Sdavemq if (lcpuid >= NCPU) 26159ac0c16Sdavemq continue; 26259ac0c16Sdavemq cpuid = (processorid_t)lcpuid; 26359ac0c16Sdavemq cpunodes[cpuid].l2_cache_mapping = idx; 26459ac0c16Sdavemq } 26559ac0c16Sdavemq md_free_scan_dag(mdp, &node); 26659ac0c16Sdavemq 26759ac0c16Sdavemq idx++; 26859ac0c16Sdavemq } 26959ac0c16Sdavemq 27059ac0c16Sdavemq md_free_scan_dag(mdp, &cachelist); 27159ac0c16Sdavemq } 27259ac0c16Sdavemq 2731ae08745Sheppo void 2741ae08745Sheppo setup_exec_unit_mappings(md_t *mdp) 2751ae08745Sheppo { 2762f0fcb93SJason Beloro int num, num_eunits; 2771ae08745Sheppo mde_cookie_t cpus_node; 2781ae08745Sheppo mde_cookie_t *node, *eunit; 2791ae08745Sheppo int idx, i, j; 2801ae08745Sheppo processorid_t cpuid; 2811ae08745Sheppo char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit"; 282fb2f18f8Sesaxe enum eu_type { INTEGER, FPU } etype; 2837c478bd9Sstevel@tonic-gate 2841ae08745Sheppo /* 2851ae08745Sheppo * Find the cpu integer exec units - and 2861ae08745Sheppo * setup the mappings appropriately. 2871ae08745Sheppo */ 2881ae08745Sheppo num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node); 2891ae08745Sheppo if (num < 1) 2904bac2208Snarayan cmn_err(CE_PANIC, "No cpus node in machine description"); 2911ae08745Sheppo if (num > 1) 2921ae08745Sheppo cmn_err(CE_PANIC, "More than 1 cpus node in machine" 2931ae08745Sheppo " description"); 2941ae08745Sheppo 2951ae08745Sheppo cpus_node = node[0]; 2961ae08745Sheppo md_free_scan_dag(mdp, &node); 2971ae08745Sheppo 2981ae08745Sheppo num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name, 2991ae08745Sheppo "fwd", &eunit); 3001ae08745Sheppo if (num_eunits > 0) { 301fb2f18f8Sesaxe char *int_str = broken_md_flag ? "int" : "integer"; 302fb2f18f8Sesaxe char *fpu_str = "fp"; 3031ae08745Sheppo 3041ae08745Sheppo /* Spin through and find all the integer exec units */ 3051ae08745Sheppo for (i = 0; i < num_eunits; i++) { 3061ae08745Sheppo char *p; 3071ae08745Sheppo char *val; 3081ae08745Sheppo int vallen; 3091ae08745Sheppo uint64_t lcpuid; 3101ae08745Sheppo 311fb2f18f8Sesaxe /* ignore nodes with no type */ 3121ae08745Sheppo if (md_get_prop_data(mdp, eunit[i], "type", 313ad8d2eb8Szx (uint8_t **)&val, &vallen)) 314ad8d2eb8Szx continue; 3151ae08745Sheppo 3161ae08745Sheppo for (p = val; *p != '\0'; p += strlen(p) + 1) { 317fb2f18f8Sesaxe if (strcmp(p, int_str) == 0) { 318fb2f18f8Sesaxe etype = INTEGER; 3191ae08745Sheppo goto found; 320fb2f18f8Sesaxe } 321fb2f18f8Sesaxe if (strcmp(p, fpu_str) == 0) { 322fb2f18f8Sesaxe etype = FPU; 323fb2f18f8Sesaxe goto found; 324fb2f18f8Sesaxe } 3257c478bd9Sstevel@tonic-gate } 3261ae08745Sheppo 3271ae08745Sheppo continue; 3281ae08745Sheppo found: 3291ae08745Sheppo idx = NCPU + i; 3307c478bd9Sstevel@tonic-gate /* 3311ae08745Sheppo * find the cpus attached to this EU and 3321ae08745Sheppo * update their mapping indices 3337c478bd9Sstevel@tonic-gate */ 3341ae08745Sheppo num = md_alloc_scan_dag(mdp, eunit[i], "cpu", 3351ae08745Sheppo "back", &node); 3361ae08745Sheppo 3371ae08745Sheppo if (num < 1) 3381ae08745Sheppo cmn_err(CE_PANIC, "exec-unit node in MD" 3391ae08745Sheppo " not attached to a cpu node"); 3401ae08745Sheppo 3411ae08745Sheppo for (j = 0; j < num; j++) { 3421ae08745Sheppo if (md_get_prop_val(mdp, node[j], "id", 3431ae08745Sheppo &lcpuid)) 3441ae08745Sheppo continue; 3451ae08745Sheppo if (lcpuid >= NCPU) 3461ae08745Sheppo continue; 3471ae08745Sheppo cpuid = (processorid_t)lcpuid; 348fb2f18f8Sesaxe switch (etype) { 349fb2f18f8Sesaxe case INTEGER: 350fb2f18f8Sesaxe cpunodes[cpuid].exec_unit_mapping = idx; 351fb2f18f8Sesaxe break; 352fb2f18f8Sesaxe case FPU: 353fb2f18f8Sesaxe cpunodes[cpuid].fpu_mapping = idx; 354fb2f18f8Sesaxe break; 355fb2f18f8Sesaxe } 3561ae08745Sheppo } 3571ae08745Sheppo md_free_scan_dag(mdp, &node); 3587c478bd9Sstevel@tonic-gate } 3592f0fcb93SJason Beloro md_free_scan_dag(mdp, &eunit); 3602f0fcb93SJason Beloro } 3612f0fcb93SJason Beloro } 3622f0fcb93SJason Beloro 3632f0fcb93SJason Beloro /* 3642f0fcb93SJason Beloro * Setup instruction cache coherency. The "memory-coherent" property 3652f0fcb93SJason Beloro * is optional. Default for Icache_coherency is 1 (I$ is coherent). 3662f0fcb93SJason Beloro * If we find an Icache with coherency == 0, then enable non-coherent 3672f0fcb93SJason Beloro * Icache support. 3682f0fcb93SJason Beloro */ 3692f0fcb93SJason Beloro void 3702f0fcb93SJason Beloro setup_icache_coherency(md_t *mdp) 3712f0fcb93SJason Beloro { 3722f0fcb93SJason Beloro int ncache; 3732f0fcb93SJason Beloro mde_cookie_t *cachelist; 3742f0fcb93SJason Beloro int i; 3757c478bd9Sstevel@tonic-gate 3762f0fcb93SJason Beloro ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache", 3772f0fcb93SJason Beloro "fwd", &cachelist); 3781ae08745Sheppo 3792f0fcb93SJason Beloro /* 3802f0fcb93SJason Beloro * The "cache" node is optional in MD, therefore ncaches can be 0. 3812f0fcb93SJason Beloro */ 3822f0fcb93SJason Beloro if (ncache < 1) { 3832f0fcb93SJason Beloro return; 3847c478bd9Sstevel@tonic-gate } 3852f0fcb93SJason Beloro 3862f0fcb93SJason Beloro for (i = 0; i < ncache; i++) { 3872f0fcb93SJason Beloro uint64_t cache_level; 3882f0fcb93SJason Beloro uint64_t memory_coherent; 3892f0fcb93SJason Beloro uint8_t *type; 3902f0fcb93SJason Beloro int typelen; 3912f0fcb93SJason Beloro 3922f0fcb93SJason Beloro if (md_get_prop_val(mdp, cachelist[i], "level", 3932f0fcb93SJason Beloro &cache_level)) 3942f0fcb93SJason Beloro continue; 3952f0fcb93SJason Beloro 3962f0fcb93SJason Beloro if (cache_level != 1) 3972f0fcb93SJason Beloro continue; 3982f0fcb93SJason Beloro 3992f0fcb93SJason Beloro if (md_get_prop_data(mdp, cachelist[i], "type", 4002f0fcb93SJason Beloro &type, &typelen)) 4012f0fcb93SJason Beloro continue; 4022f0fcb93SJason Beloro 4032f0fcb93SJason Beloro if (strcmp((char *)type, "instn") != 0) 4042f0fcb93SJason Beloro continue; 4052f0fcb93SJason Beloro 4062f0fcb93SJason Beloro if (md_get_prop_val(mdp, cachelist[i], "memory-coherent", 4072f0fcb93SJason Beloro &memory_coherent)) 4082f0fcb93SJason Beloro continue; 4092f0fcb93SJason Beloro 4102f0fcb93SJason Beloro if (memory_coherent != 0) 4112f0fcb93SJason Beloro continue; 4122f0fcb93SJason Beloro 4132f0fcb93SJason Beloro mach_setup_icache(memory_coherent); 4142f0fcb93SJason Beloro break; 4152f0fcb93SJason Beloro } 4162f0fcb93SJason Beloro 4172f0fcb93SJason Beloro md_free_scan_dag(mdp, &cachelist); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4201ae08745Sheppo /* 4211ae08745Sheppo * All the common setup of sun4v CPU modules is done by this routine. 4221ae08745Sheppo */ 4231ae08745Sheppo void 4241ae08745Sheppo cpu_setup_common(char **cpu_module_isa_set) 4257c478bd9Sstevel@tonic-gate { 4261ae08745Sheppo extern int mmu_exported_pagesize_mask; 4271ae08745Sheppo int nocpus, i; 4281ae08745Sheppo size_t ra_limit; 4291ae08745Sheppo mde_cookie_t *cpulist; 4301ae08745Sheppo md_t *mdp; 4311ae08745Sheppo 4321ae08745Sheppo if ((mdp = md_get_handle()) == NULL) 4331ae08745Sheppo cmn_err(CE_PANIC, "Unable to initialize machine description"); 4341ae08745Sheppo 43506fb6a36Sdv boot_ncpus = nocpus = md_alloc_scan_dag(mdp, 4361ae08745Sheppo md_root_node(mdp), "cpu", "fwd", &cpulist); 4371ae08745Sheppo if (nocpus < 1) { 4381ae08745Sheppo cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation " 4391ae08745Sheppo "failed or incorrect number of CPUs in MD"); 4401ae08745Sheppo } 4417c478bd9Sstevel@tonic-gate 4424bac2208Snarayan init_md_broken(mdp, cpulist); 4434bac2208Snarayan 4441ae08745Sheppo if (use_page_coloring) { 4451ae08745Sheppo do_pg_coloring = 1; 4461ae08745Sheppo } 4471ae08745Sheppo 4481ae08745Sheppo /* 4491e2e7a75Shuah * Get the valid mmu page sizes mask, Q sizes and isalist/r 4501ae08745Sheppo * from the MD for the first available CPU in cpulist. 4511e2e7a75Shuah * 4521e2e7a75Shuah * Do not expect the MMU page sizes mask to be more than 32-bit. 4531ae08745Sheppo */ 4541ae08745Sheppo mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]); 4551ae08745Sheppo 45605d3dc4bSpaulsan /* 45705d3dc4bSpaulsan * Get the number of contexts and tsbs supported. 45805d3dc4bSpaulsan */ 45905d3dc4bSpaulsan if (get_mmu_shcontexts(mdp, cpulist[0]) >= MIN_NSHCONTEXTS && 46005d3dc4bSpaulsan get_mmu_tsbs(mdp, cpulist[0]) >= MIN_NTSBS) { 46105d3dc4bSpaulsan shctx_on = 1; 46205d3dc4bSpaulsan } 46305d3dc4bSpaulsan 464125be069SJason Beloro /* 465125be069SJason Beloro * Get and check page search register properties. 466125be069SJason Beloro */ 467125be069SJason Beloro pgsz_search_on = check_mmu_pgsz_search(mdp, cpulist[0]); 468125be069SJason Beloro 4691ae08745Sheppo for (i = 0; i < nocpus; i++) 4701ae08745Sheppo fill_cpu(mdp, cpulist[i]); 4711ae08745Sheppo 472575a7426Spt /* setup l2 cache count. */ 473575a7426Spt n_l2_caches = get_l2_cache_node_count(mdp); 474575a7426Spt 47559ac0c16Sdavemq setup_chip_mappings(mdp); 4761ae08745Sheppo setup_exec_unit_mappings(mdp); 4772f0fcb93SJason Beloro setup_icache_coherency(mdp); 4781ae08745Sheppo 4791ae08745Sheppo /* 4801ae08745Sheppo * If MD is broken then append the passed ISA set, 4811ae08745Sheppo * otherwise trust the MD. 4821ae08745Sheppo */ 4831ae08745Sheppo 4841ae08745Sheppo if (broken_md_flag) 4851ae08745Sheppo isa_list = construct_isalist(mdp, cpulist[0], 4861ae08745Sheppo cpu_module_isa_set); 4871ae08745Sheppo else 4881ae08745Sheppo isa_list = construct_isalist(mdp, cpulist[0], NULL); 4891ae08745Sheppo 4902f0fcb93SJason Beloro get_hwcaps(mdp, cpulist[0]); 4912c5124a1SPrashanth Sreenivasa get_weakest_mem_model(mdp, cpulist[0]); 4921ae08745Sheppo get_q_sizes(mdp, cpulist[0]); 4931ae08745Sheppo get_va_bits(mdp, cpulist[0]); 4941ae08745Sheppo 4951ae08745Sheppo /* 4961ae08745Sheppo * ra_limit is the highest real address in the machine. 4971ae08745Sheppo */ 498*9853d9e8SJason Beloro ra_limit = get_ra_limit(mdp, cpulist[0]); 4991ae08745Sheppo 5001ae08745Sheppo md_free_scan_dag(mdp, &cpulist); 5011ae08745Sheppo 5021ae08745Sheppo (void) md_fini_handle(mdp); 5031ae08745Sheppo 5041ae08745Sheppo /* 5051ae08745Sheppo * Block stores invalidate all pages of the d$ so pagecopy 5061ae08745Sheppo * et. al. do not need virtual translations with virtual 5071ae08745Sheppo * coloring taken into consideration. 5081ae08745Sheppo */ 5091ae08745Sheppo pp_consistent_coloring = 0; 5101ae08745Sheppo 5111ae08745Sheppo /* 5121ae08745Sheppo * The kpm mapping window. 5131ae08745Sheppo * kpm_size: 5141ae08745Sheppo * The size of a single kpm range. 5151ae08745Sheppo * The overall size will be: kpm_size * vac_colors. 5161ae08745Sheppo * kpm_vbase: 5171ae08745Sheppo * The virtual start address of the kpm range within the kernel 5181ae08745Sheppo * virtual address space. kpm_vbase has to be kpm_size aligned. 5191ae08745Sheppo */ 5201ae08745Sheppo 5211ae08745Sheppo /* 5221ae08745Sheppo * Make kpm_vbase, kpm_size aligned to kpm_size_shift. 5231ae08745Sheppo * To do this find the nearest power of 2 size that the 5241ae08745Sheppo * actual ra_limit fits within. 5251ae08745Sheppo * If it is an even power of two use that, otherwise use the 5261ae08745Sheppo * next power of two larger than ra_limit. 5271ae08745Sheppo */ 5281ae08745Sheppo 5291ae08745Sheppo ASSERT(ra_limit != 0); 5301ae08745Sheppo 5311ae08745Sheppo kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ? 532ad8d2eb8Szx highbit(ra_limit) : highbit(ra_limit) - 1; 5331ae08745Sheppo 5341ae08745Sheppo /* 5351ae08745Sheppo * No virtual caches on sun4v so size matches size shift 5361ae08745Sheppo */ 5371ae08745Sheppo kpm_size = 1ul << kpm_size_shift; 5381ae08745Sheppo 5391ae08745Sheppo if (va_bits < VA_ADDRESS_SPACE_BITS) { 5407c478bd9Sstevel@tonic-gate /* 5411ae08745Sheppo * In case of VA hole 5421ae08745Sheppo * kpm_base = hole_end + 1TB 5431ae08745Sheppo * Starting 1TB beyond where VA hole ends because on Niagara 5441ae08745Sheppo * processor software must not use pages within 4GB of the 5451ae08745Sheppo * VA hole as instruction pages to avoid problems with 5461ae08745Sheppo * prefetching into the VA hole. 5477c478bd9Sstevel@tonic-gate */ 5481ae08745Sheppo kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) + 5491ae08745Sheppo (1ull << 40)); 5501ae08745Sheppo } else { /* Number of VA bits 64 ... no VA hole */ 5511ae08745Sheppo kpm_vbase = (caddr_t)0x8000000000000000ull; /* 8 EB */ 5527c478bd9Sstevel@tonic-gate } 5531ae08745Sheppo 5541ae08745Sheppo /* 5551ae08745Sheppo * The traptrace code uses either %tick or %stick for 5561ae08745Sheppo * timestamping. The sun4v require use of %stick. 5571ae08745Sheppo */ 5581ae08745Sheppo traptrace_use_stick = 1; 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5611ae08745Sheppo /* 5621ae08745Sheppo * Get the nctxs from MD. If absent panic. 5631ae08745Sheppo */ 5641ae08745Sheppo static uint64_t 5651ae08745Sheppo get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 5667c478bd9Sstevel@tonic-gate { 5671ae08745Sheppo uint64_t ctx_bits; 5687c478bd9Sstevel@tonic-gate 5691ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits", 5701ae08745Sheppo &ctx_bits)) 5711ae08745Sheppo ctx_bits = 0; 5727c478bd9Sstevel@tonic-gate 5731ae08745Sheppo if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS) 5741ae08745Sheppo cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits " 5751ae08745Sheppo "returned by MD", ctx_bits); 5767c478bd9Sstevel@tonic-gate 5771ae08745Sheppo return (ctx_bits); 5781ae08745Sheppo } 5797c478bd9Sstevel@tonic-gate 58005d3dc4bSpaulsan /* 58105d3dc4bSpaulsan * Get the number of tsbs from MD. If absent the default value is 0. 58205d3dc4bSpaulsan */ 58305d3dc4bSpaulsan static uint64_t 58405d3dc4bSpaulsan get_mmu_tsbs(md_t *mdp, mde_cookie_t cpu_node_cookie) 58505d3dc4bSpaulsan { 58605d3dc4bSpaulsan uint64_t number_tsbs; 58705d3dc4bSpaulsan 58805d3dc4bSpaulsan if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-#tsbs", 58905d3dc4bSpaulsan &number_tsbs)) 59005d3dc4bSpaulsan number_tsbs = 0; 59105d3dc4bSpaulsan 59205d3dc4bSpaulsan return (number_tsbs); 59305d3dc4bSpaulsan } 59405d3dc4bSpaulsan 59505d3dc4bSpaulsan /* 5967dacfc44Spaulsan * Get the number of shared contexts from MD. If absent the default value is 0. 59705d3dc4bSpaulsan * 59805d3dc4bSpaulsan */ 59905d3dc4bSpaulsan static uint64_t 60005d3dc4bSpaulsan get_mmu_shcontexts(md_t *mdp, mde_cookie_t cpu_node_cookie) 60105d3dc4bSpaulsan { 60205d3dc4bSpaulsan uint64_t number_contexts; 60305d3dc4bSpaulsan 60405d3dc4bSpaulsan if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#shared-contexts", 60505d3dc4bSpaulsan &number_contexts)) 60605d3dc4bSpaulsan number_contexts = 0; 60705d3dc4bSpaulsan 60805d3dc4bSpaulsan return (number_contexts); 60905d3dc4bSpaulsan } 61005d3dc4bSpaulsan 6111ae08745Sheppo /* 6121ae08745Sheppo * Initalize supported page sizes information. 6131ae08745Sheppo * Set to 0, if the page sizes mask information is absent in MD. 6141ae08745Sheppo */ 6151ae08745Sheppo static uint64_t 6161ae08745Sheppo get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 6171ae08745Sheppo { 6181ae08745Sheppo uint64_t mmu_page_size_list; 6197c478bd9Sstevel@tonic-gate 6201ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list", 6211ae08745Sheppo &mmu_page_size_list)) 6221ae08745Sheppo mmu_page_size_list = 0; 6231ae08745Sheppo 6241ae08745Sheppo if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK) 6251ae08745Sheppo cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned" 6261ae08745Sheppo "by MD", mmu_page_size_list); 6271ae08745Sheppo 6281ae08745Sheppo return (mmu_page_size_list); 6291ae08745Sheppo } 6301ae08745Sheppo 6311ae08745Sheppo /* 6321ae08745Sheppo * This routine gets the isalist information from MD and appends 6331ae08745Sheppo * the CPU module ISA set if required. 6341ae08745Sheppo */ 6351ae08745Sheppo static char * 6361ae08745Sheppo construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie, 6371ae08745Sheppo char **cpu_module_isa_set) 6381ae08745Sheppo { 6391ae08745Sheppo extern int at_flags; 6401ae08745Sheppo char *md_isalist; 6411ae08745Sheppo int md_isalen; 6421ae08745Sheppo char *isabuf; 6431ae08745Sheppo int isalen; 6441ae08745Sheppo char **isa_set; 6451ae08745Sheppo char *p, *q; 6461ae08745Sheppo int cpu_module_isalen = 0, found = 0; 6471ae08745Sheppo 6481ae08745Sheppo (void) md_get_prop_data(mdp, cpu_node_cookie, 6491ae08745Sheppo "isalist", (uint8_t **)&isabuf, &isalen); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /* 6521ae08745Sheppo * We support binaries for all the cpus that have shipped so far. 6531ae08745Sheppo * The kernel emulates instructions that are not supported by hardware. 6547c478bd9Sstevel@tonic-gate */ 6551ae08745Sheppo at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1; 6567c478bd9Sstevel@tonic-gate 6571ae08745Sheppo /* 6581ae08745Sheppo * Construct the space separated isa_list. 6591ae08745Sheppo */ 6601ae08745Sheppo if (cpu_module_isa_set != NULL) { 6611ae08745Sheppo for (isa_set = cpu_module_isa_set; *isa_set != NULL; 6621ae08745Sheppo isa_set++) { 6631ae08745Sheppo cpu_module_isalen += strlen(*isa_set); 6641ae08745Sheppo cpu_module_isalen++; /* for space character */ 6651ae08745Sheppo } 6661ae08745Sheppo } 6677c478bd9Sstevel@tonic-gate 6681ae08745Sheppo /* 6691ae08745Sheppo * Allocate the buffer of MD isa buffer length + CPU module 6701ae08745Sheppo * isa buffer length. 6711ae08745Sheppo */ 6721ae08745Sheppo md_isalen = isalen + cpu_module_isalen + 2; 6731ae08745Sheppo md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0); 6741ae08745Sheppo if (md_isalist == NULL) 6751ae08745Sheppo cmn_err(CE_PANIC, "construct_isalist: Allocation failed for " 6761ae08745Sheppo "md_isalist"); 6771ae08745Sheppo 6781ae08745Sheppo md_isalist[0] = '\0'; /* create an empty string to start */ 6791ae08745Sheppo for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) { 6801ae08745Sheppo (void) strlcat(md_isalist, p, md_isalen); 6811ae08745Sheppo (void) strcat(md_isalist, " "); 6821ae08745Sheppo } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* 6851ae08745Sheppo * Check if the isa_set is present in isalist returned by MD. 6861ae08745Sheppo * If yes, then no need to append it, if no then append it to 6871ae08745Sheppo * isalist returned by MD. 6887c478bd9Sstevel@tonic-gate */ 6891ae08745Sheppo if (cpu_module_isa_set != NULL) { 6901ae08745Sheppo for (isa_set = cpu_module_isa_set; *isa_set != NULL; 6911ae08745Sheppo isa_set++) { 6921ae08745Sheppo found = 0; 6931ae08745Sheppo for (p = isabuf, q = p + isalen; p < q; 6941ae08745Sheppo p += strlen(p) + 1) { 6951ae08745Sheppo if (strcmp(p, *isa_set) == 0) { 6961ae08745Sheppo found = 1; 6971ae08745Sheppo break; 6981ae08745Sheppo } 6991ae08745Sheppo } 7001ae08745Sheppo if (!found) { 7011ae08745Sheppo (void) strlcat(md_isalist, *isa_set, md_isalen); 7021ae08745Sheppo (void) strcat(md_isalist, " "); 7031ae08745Sheppo } 7041ae08745Sheppo } 7051ae08745Sheppo } 7061ae08745Sheppo 7071ae08745Sheppo /* Get rid of any trailing white spaces */ 7081ae08745Sheppo md_isalist[strlen(md_isalist) - 1] = '\0'; 7091ae08745Sheppo 7101ae08745Sheppo return (md_isalist); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7132f0fcb93SJason Beloro static void 7142f0fcb93SJason Beloro get_hwcaps(md_t *mdp, mde_cookie_t cpu_node_cookie) 7152f0fcb93SJason Beloro { 7162f0fcb93SJason Beloro char *hwcapbuf; 7172f0fcb93SJason Beloro int hwcaplen; 7182f0fcb93SJason Beloro 7192f0fcb93SJason Beloro if (md_get_prop_data(mdp, cpu_node_cookie, 7202f0fcb93SJason Beloro "hwcap-list", (uint8_t **)&hwcapbuf, &hwcaplen)) { 7212f0fcb93SJason Beloro /* Property not found */ 7222f0fcb93SJason Beloro return; 7232f0fcb93SJason Beloro } 7242f0fcb93SJason Beloro 7252f0fcb93SJason Beloro cpu_hwcap_flags |= names2bits(hwcapbuf, hwcaplen, FMT_AV_SPARC, 7262f0fcb93SJason Beloro "unrecognized token: %s"); 7272f0fcb93SJason Beloro } 7282f0fcb93SJason Beloro 7292c5124a1SPrashanth Sreenivasa static void 7302c5124a1SPrashanth Sreenivasa get_weakest_mem_model(md_t *mdp, mde_cookie_t cpu_node_cookie) 7312c5124a1SPrashanth Sreenivasa { 7322c5124a1SPrashanth Sreenivasa char *mmbuf; 7332c5124a1SPrashanth Sreenivasa int mmlen; 7342c5124a1SPrashanth Sreenivasa uint_t wmm; 7352c5124a1SPrashanth Sreenivasa char *p, *q; 7362c5124a1SPrashanth Sreenivasa 7372c5124a1SPrashanth Sreenivasa if (md_get_prop_data(mdp, cpu_node_cookie, 7382c5124a1SPrashanth Sreenivasa "memory-model-list", (uint8_t **)&mmbuf, &mmlen)) { 7392c5124a1SPrashanth Sreenivasa /* Property not found */ 7402c5124a1SPrashanth Sreenivasa return; 7412c5124a1SPrashanth Sreenivasa } 7422c5124a1SPrashanth Sreenivasa 7432c5124a1SPrashanth Sreenivasa wmm = TSTATE_MM_TSO; 7442c5124a1SPrashanth Sreenivasa for (p = mmbuf, q = p + mmlen; p < q; p += strlen(p) + 1) { 7452c5124a1SPrashanth Sreenivasa if (strcmp(p, "wc") == 0) 7462c5124a1SPrashanth Sreenivasa wmm = TSTATE_MM_WC; 7472c5124a1SPrashanth Sreenivasa } 7482c5124a1SPrashanth Sreenivasa weakest_mem_model = wmm; 7492c5124a1SPrashanth Sreenivasa } 7502f0fcb93SJason Beloro 7512f0fcb93SJason Beloro /* 7522f0fcb93SJason Beloro * Does the opposite of cmn_err(9f) "%b" conversion specification: 7532f0fcb93SJason Beloro * Given a list of strings, converts them to a bit-vector. 7542f0fcb93SJason Beloro * 7552f0fcb93SJason Beloro * tokens - is a buffer of [NUL-terminated] strings. 7562f0fcb93SJason Beloro * tokenslen - length of tokenbuf in bytes. 7572f0fcb93SJason Beloro * bit_formatter - is a %b format string, such as FMT_AV_SPARC 7582f0fcb93SJason Beloro * from /usr/include/sys/auxv_SPARC.h, of the form: 7592f0fcb93SJason Beloro * <base-char>[<bit-char><token-string>]... 7602f0fcb93SJason Beloro * <base-char> is ignored. 7612f0fcb93SJason Beloro * <bit-char> is [1-32], as per cmn_err(9f). 7622f0fcb93SJason Beloro * warning - is a printf-style format string containing "%s", 7632f0fcb93SJason Beloro * which is used to print a warning message when an unrecognized 7642f0fcb93SJason Beloro * token is found. If warning is NULL, no warning is printed. 7652f0fcb93SJason Beloro * Returns a bit-vector corresponding to the specified tokens. 7662f0fcb93SJason Beloro */ 7672f0fcb93SJason Beloro 7682f0fcb93SJason Beloro static unsigned long 7692f0fcb93SJason Beloro names2bits(char *tokens, size_t tokenslen, char *bit_formatter, char *warning) 7702f0fcb93SJason Beloro { 7712f0fcb93SJason Beloro char *cur; 7722f0fcb93SJason Beloro size_t curlen; 7732f0fcb93SJason Beloro unsigned long ul = 0; 7742f0fcb93SJason Beloro char *hit; 7752f0fcb93SJason Beloro char *bs; 7762f0fcb93SJason Beloro 7772f0fcb93SJason Beloro bit_formatter++; /* skip base; not needed for input */ 7782f0fcb93SJason Beloro cur = tokens; 7792f0fcb93SJason Beloro while (tokenslen) { 7802f0fcb93SJason Beloro curlen = strlen(cur); 7812f0fcb93SJason Beloro bs = bit_formatter; 7822f0fcb93SJason Beloro /* 7832f0fcb93SJason Beloro * We need a complicated while loop and the >=32 check, 7842f0fcb93SJason Beloro * instead of a simple "if (strstr())" so that when the 7852f0fcb93SJason Beloro * token is "vis", we don't match on "vis2" (for example). 7862f0fcb93SJason Beloro */ 7872f0fcb93SJason Beloro /* LINTED E_EQUALITY_NOT_ASSIGNMENT */ 7882f0fcb93SJason Beloro while ((hit = strstr(bs, cur)) && 7892f0fcb93SJason Beloro *(hit + curlen) >= 32) { 7902f0fcb93SJason Beloro /* 7912f0fcb93SJason Beloro * We're still in the middle of a word, i.e., not 7922f0fcb93SJason Beloro * pointing at a <bit-char>. So advance ptr 7932f0fcb93SJason Beloro * to ensure forward progress. 7942f0fcb93SJason Beloro */ 7952f0fcb93SJason Beloro bs = hit + curlen + 1; 7962f0fcb93SJason Beloro } 7972f0fcb93SJason Beloro 7982f0fcb93SJason Beloro if (hit != NULL) { 7992f0fcb93SJason Beloro ul |= (1<<(*(hit-1) - 1)); 8002f0fcb93SJason Beloro } else { 8012f0fcb93SJason Beloro /* The token wasn't found in bit_formatter */ 8022f0fcb93SJason Beloro if (warning != NULL) 8032f0fcb93SJason Beloro cmn_err(CE_WARN, warning, cur); 8042f0fcb93SJason Beloro } 8052f0fcb93SJason Beloro tokenslen -= curlen + 1; 8062f0fcb93SJason Beloro cur += curlen + 1; 8072f0fcb93SJason Beloro } 8082f0fcb93SJason Beloro return (ul); 8092f0fcb93SJason Beloro } 8102f0fcb93SJason Beloro 8111ae08745Sheppo uint64_t 812*9853d9e8SJason Beloro get_ra_limit(md_t *mdp, mde_cookie_t cpu_node_cookie) 8131ae08745Sheppo { 814*9853d9e8SJason Beloro extern int ppvm_enable; 815*9853d9e8SJason Beloro extern int meta_alloc_enable; 8161ae08745Sheppo mde_cookie_t *mem_list; 8171ae08745Sheppo mde_cookie_t *mblock_list; 8181ae08745Sheppo int i; 8191ae08745Sheppo int memnodes; 8201ae08745Sheppo int nmblock; 821*9853d9e8SJason Beloro uint64_t r; 8221ae08745Sheppo uint64_t base; 8231ae08745Sheppo uint64_t size; 8241ae08745Sheppo uint64_t ra_limit = 0, new_limit = 0; 8251ae08745Sheppo 826*9853d9e8SJason Beloro if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#ra-bits", &r) == 0) { 827*9853d9e8SJason Beloro if (r == 0 || r > RA_ADDRESS_SPACE_BITS) 828*9853d9e8SJason Beloro cmn_err(CE_PANIC, "Incorrect number of ra bits in MD"); 829*9853d9e8SJason Beloro else { 830*9853d9e8SJason Beloro /* 831*9853d9e8SJason Beloro * Enable memory DR and metadata (page_t) 832*9853d9e8SJason Beloro * allocation from existing memory. 833*9853d9e8SJason Beloro */ 834*9853d9e8SJason Beloro ppvm_enable = 1; 835*9853d9e8SJason Beloro meta_alloc_enable = 1; 836*9853d9e8SJason Beloro return (1ULL << r); 837*9853d9e8SJason Beloro } 838*9853d9e8SJason Beloro } 839*9853d9e8SJason Beloro 840*9853d9e8SJason Beloro cmn_err(CE_WARN, "mmu-#ra-bits property not found in MD"); 841*9853d9e8SJason Beloro cmn_err(CE_WARN, "Memory DR disabled"); 842*9853d9e8SJason Beloro 8431ae08745Sheppo memnodes = md_alloc_scan_dag(mdp, 8441ae08745Sheppo md_root_node(mdp), "memory", "fwd", &mem_list); 8451ae08745Sheppo 8461ae08745Sheppo ASSERT(memnodes == 1); 8471ae08745Sheppo 8481ae08745Sheppo nmblock = md_alloc_scan_dag(mdp, 8491ae08745Sheppo mem_list[0], "mblock", "fwd", &mblock_list); 8501ae08745Sheppo if (nmblock < 1) 8511ae08745Sheppo cmn_err(CE_PANIC, "cannot find mblock nodes in MD"); 8521ae08745Sheppo 8531ae08745Sheppo for (i = 0; i < nmblock; i++) { 8541ae08745Sheppo if (md_get_prop_val(mdp, mblock_list[i], "base", &base)) 8551ae08745Sheppo cmn_err(CE_PANIC, "base property missing from MD" 8561ae08745Sheppo " mblock node"); 8571ae08745Sheppo if (md_get_prop_val(mdp, mblock_list[i], "size", &size)) 8581ae08745Sheppo cmn_err(CE_PANIC, "size property missing from MD" 8591ae08745Sheppo " mblock node"); 8601ae08745Sheppo 8611ae08745Sheppo ASSERT(size != 0); 8621ae08745Sheppo 8631ae08745Sheppo new_limit = base + size; 8641ae08745Sheppo 8651ae08745Sheppo if (base > new_limit) 8661ae08745Sheppo cmn_err(CE_PANIC, "mblock in MD wrapped around"); 8671ae08745Sheppo 8681ae08745Sheppo if (new_limit > ra_limit) 869ad8d2eb8Szx ra_limit = new_limit; 8701ae08745Sheppo } 8711ae08745Sheppo 8721ae08745Sheppo ASSERT(ra_limit != 0); 8731ae08745Sheppo 8741ae08745Sheppo if (ra_limit > MAX_REAL_ADDRESS) { 8751ae08745Sheppo cmn_err(CE_WARN, "Highest real address in MD too large" 8761ae08745Sheppo " clipping to %llx\n", MAX_REAL_ADDRESS); 8771ae08745Sheppo ra_limit = MAX_REAL_ADDRESS; 8781ae08745Sheppo } 8791ae08745Sheppo 8801ae08745Sheppo md_free_scan_dag(mdp, &mblock_list); 8811ae08745Sheppo 8821ae08745Sheppo md_free_scan_dag(mdp, &mem_list); 8831ae08745Sheppo 8841ae08745Sheppo return (ra_limit); 8851ae08745Sheppo } 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate /* 8881ae08745Sheppo * This routine sets the globals for CPU and DEV mondo queue entries and 8891ae08745Sheppo * resumable and non-resumable error queue entries. 8904bac2208Snarayan * 8914bac2208Snarayan * First, look up the number of bits available to pass an entry number. 8924bac2208Snarayan * This can vary by platform and may result in allocating an unreasonably 8934bac2208Snarayan * (or impossibly) large amount of memory for the corresponding table, 894d5e8e65eSdavemq * so we clamp it by 'max_entries'. Finally, since the q size is used when 895d5e8e65eSdavemq * calling contig_mem_alloc(), which expects a power of 2, clamp the q size 896d5e8e65eSdavemq * down to a power of 2. If the prop is missing, use 'default_entries'. 8977c478bd9Sstevel@tonic-gate */ 8981ae08745Sheppo static uint64_t 8991ae08745Sheppo get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie, 9004bac2208Snarayan char *qnamep, uint64_t default_entries, uint64_t max_entries) 9011ae08745Sheppo { 9021ae08745Sheppo uint64_t entries; 9031ae08745Sheppo 9044bac2208Snarayan if (default_entries > max_entries) 9054bac2208Snarayan cmn_err(CE_CONT, "!get_single_q_size: dflt %ld > " 9064bac2208Snarayan "max %ld for %s\n", default_entries, max_entries, qnamep); 9074bac2208Snarayan 9081ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) { 9091ae08745Sheppo if (!broken_md_flag) 9101ae08745Sheppo cmn_err(CE_PANIC, "Missing %s property in MD cpu node", 911ad8d2eb8Szx qnamep); 9121ae08745Sheppo entries = default_entries; 9131ae08745Sheppo } else { 9141ae08745Sheppo entries = 1 << entries; 9151ae08745Sheppo } 9164bac2208Snarayan 9174bac2208Snarayan entries = MIN(entries, max_entries); 918d5e8e65eSdavemq /* If not a power of 2, truncate to a power of 2. */ 919d5e8e65eSdavemq if ((entries & (entries - 1)) != 0) { 920d5e8e65eSdavemq entries = 1 << (highbit(entries) - 1); 921d5e8e65eSdavemq } 9224bac2208Snarayan 9231ae08745Sheppo return (entries); 9241ae08745Sheppo } 9251ae08745Sheppo 9264bac2208Snarayan /* Scaling constant used to compute size of cpu mondo queue */ 9274bac2208Snarayan #define CPU_MONDO_Q_MULTIPLIER 8 9281ae08745Sheppo 9297c478bd9Sstevel@tonic-gate static void 9301ae08745Sheppo get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 9317c478bd9Sstevel@tonic-gate { 9324bac2208Snarayan uint64_t max_qsize; 9334bac2208Snarayan mde_cookie_t *platlist; 9344bac2208Snarayan int nrnode; 9354bac2208Snarayan 9364bac2208Snarayan /* 9374bac2208Snarayan * Compute the maximum number of entries for the cpu mondo queue. 9384bac2208Snarayan * Use the appropriate property in the platform node, if it is 9394bac2208Snarayan * available. Else, base it on NCPU. 9404bac2208Snarayan */ 9414bac2208Snarayan nrnode = md_alloc_scan_dag(mdp, 9424bac2208Snarayan md_root_node(mdp), "platform", "fwd", &platlist); 9434bac2208Snarayan 9444bac2208Snarayan ASSERT(nrnode == 1); 9454bac2208Snarayan 946aaa10e67Sha ncpu_guest_max = NCPU; 947aaa10e67Sha (void) md_get_prop_val(mdp, platlist[0], "max-cpus", &ncpu_guest_max); 948aaa10e67Sha max_qsize = ncpu_guest_max * CPU_MONDO_Q_MULTIPLIER; 9494bac2208Snarayan 9504bac2208Snarayan md_free_scan_dag(mdp, &platlist); 9514bac2208Snarayan 9521ae08745Sheppo cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie, 9534bac2208Snarayan "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES, max_qsize); 9541ae08745Sheppo 9551ae08745Sheppo dev_q_entries = get_single_q_size(mdp, cpu_node_cookie, 956b0fc0e77Sgovinda "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES, MAXIVNUM); 9571ae08745Sheppo 9581ae08745Sheppo cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie, 9594bac2208Snarayan "q-resumable-#bits", CPU_RQ_ENTRIES, MAX_CPU_RQ_ENTRIES); 9601ae08745Sheppo 9611ae08745Sheppo cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie, 9624bac2208Snarayan "q-nonresumable-#bits", CPU_NRQ_ENTRIES, MAX_CPU_NRQ_ENTRIES); 9631ae08745Sheppo } 9641ae08745Sheppo 9651ae08745Sheppo 9661ae08745Sheppo static void 9671ae08745Sheppo get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 9681ae08745Sheppo { 9691ae08745Sheppo uint64_t value = VA_ADDRESS_SPACE_BITS; 9701ae08745Sheppo 9711ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value)) 9721ae08745Sheppo cmn_err(CE_PANIC, "mmu-#va-bits property not found in MD"); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate 9751ae08745Sheppo if (value == 0 || value > VA_ADDRESS_SPACE_BITS) 9761ae08745Sheppo cmn_err(CE_PANIC, "Incorrect number of va bits in MD"); 9777c478bd9Sstevel@tonic-gate 9781ae08745Sheppo /* Do not expect number of VA bits to be more than 32-bit quantity */ 9797c478bd9Sstevel@tonic-gate 9801ae08745Sheppo va_bits = (int)value; 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate /* 9831ae08745Sheppo * Correct the value for VA bits on UltraSPARC-T1 based systems 9841ae08745Sheppo * in case of broken MD. 9857c478bd9Sstevel@tonic-gate */ 9861ae08745Sheppo if (broken_md_flag) 9871ae08745Sheppo va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS; 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 990575a7426Spt int 991575a7426Spt l2_cache_node_count(void) 992575a7426Spt { 993575a7426Spt return (n_l2_caches); 994575a7426Spt } 995575a7426Spt 996575a7426Spt /* 997575a7426Spt * count the number of l2 caches. 998575a7426Spt */ 999575a7426Spt int 1000575a7426Spt get_l2_cache_node_count(md_t *mdp) 1001575a7426Spt { 1002575a7426Spt int i; 1003575a7426Spt mde_cookie_t *cachenodes; 1004575a7426Spt uint64_t level; 1005575a7426Spt int n_cachenodes = md_alloc_scan_dag(mdp, md_root_node(mdp), 1006575a7426Spt "cache", "fwd", &cachenodes); 1007575a7426Spt int l2_caches = 0; 1008575a7426Spt 1009575a7426Spt for (i = 0; i < n_cachenodes; i++) { 1010575a7426Spt if (md_get_prop_val(mdp, cachenodes[i], "level", &level) != 0) { 1011575a7426Spt level = 0; 1012575a7426Spt } 1013575a7426Spt if (level == 2) { 1014575a7426Spt l2_caches++; 1015575a7426Spt } 1016575a7426Spt } 1017575a7426Spt md_free_scan_dag(mdp, &cachenodes); 1018575a7426Spt return (l2_caches); 1019575a7426Spt } 1020575a7426Spt 10211ae08745Sheppo /* 10221ae08745Sheppo * This routine returns the L2 cache information such as -- associativity, 10231ae08745Sheppo * size and linesize. 10241ae08745Sheppo */ 10251ae08745Sheppo static int 10261ae08745Sheppo get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie, 10271ae08745Sheppo uint64_t *associativity, uint64_t *size, uint64_t *linesize) 10281ae08745Sheppo { 10291ae08745Sheppo mde_cookie_t *cachelist; 10301ae08745Sheppo int ncaches, i; 1031f5db7437Sae uint64_t cache_level = 0; 10321ae08745Sheppo 10331ae08745Sheppo ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache", 10341ae08745Sheppo "fwd", &cachelist); 10351ae08745Sheppo /* 10361ae08745Sheppo * The "cache" node is optional in MD, therefore ncaches can be 0. 10371ae08745Sheppo */ 10381ae08745Sheppo if (ncaches < 1) { 10391ae08745Sheppo return (0); 10401ae08745Sheppo } 10411ae08745Sheppo 10421ae08745Sheppo for (i = 0; i < ncaches; i++) { 10431ae08745Sheppo uint64_t local_assoc; 10441ae08745Sheppo uint64_t local_size; 10451ae08745Sheppo uint64_t local_lsize; 10461ae08745Sheppo 10471ae08745Sheppo if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 10481ae08745Sheppo continue; 10491ae08745Sheppo 1050f5db7437Sae if (cache_level != 2) continue; 10511ae08745Sheppo 10521ae08745Sheppo /* If properties are missing from this cache ignore it */ 10531ae08745Sheppo 10541ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 10551ae08745Sheppo "associativity", &local_assoc))) { 10561ae08745Sheppo continue; 10571ae08745Sheppo } 10581ae08745Sheppo 10591ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 10601ae08745Sheppo "size", &local_size))) { 10611ae08745Sheppo continue; 10621ae08745Sheppo } 10631ae08745Sheppo 10641ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 10651ae08745Sheppo "line-size", &local_lsize))) { 10661ae08745Sheppo continue; 10671ae08745Sheppo } 10681ae08745Sheppo 10691ae08745Sheppo *associativity = local_assoc; 10701ae08745Sheppo *size = local_size; 10711ae08745Sheppo *linesize = local_lsize; 1072f5db7437Sae break; 10731ae08745Sheppo } 10747c478bd9Sstevel@tonic-gate 10751ae08745Sheppo md_free_scan_dag(mdp, &cachelist); 10761ae08745Sheppo 1077f5db7437Sae return ((cache_level == 2) ? 1 : 0); 10781ae08745Sheppo } 10791ae08745Sheppo 10804bac2208Snarayan 10811ae08745Sheppo /* 10824bac2208Snarayan * Set the broken_md_flag to 1 if the MD doesn't have 10834bac2208Snarayan * the domaining-enabled property in the platform node and the 10844bac2208Snarayan * platform uses the UltraSPARC-T1 cpu. This flag is used to 10854bac2208Snarayan * workaround some of the incorrect MD properties. 10861ae08745Sheppo */ 10871ae08745Sheppo static void 10884bac2208Snarayan init_md_broken(md_t *mdp, mde_cookie_t *cpulist) 10897c478bd9Sstevel@tonic-gate { 10901ae08745Sheppo int nrnode; 10911ae08745Sheppo mde_cookie_t *platlist, rootnode; 10921ae08745Sheppo uint64_t val = 0; 10934bac2208Snarayan char *namebuf; 10944bac2208Snarayan int namelen; 10951ae08745Sheppo 10961ae08745Sheppo rootnode = md_root_node(mdp); 10971ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 10984bac2208Snarayan ASSERT(cpulist); 10991ae08745Sheppo 11004bac2208Snarayan nrnode = md_alloc_scan_dag(mdp, rootnode, "platform", "fwd", 11011ae08745Sheppo &platlist); 11021ae08745Sheppo 1103f273041fSjm if (nrnode < 1) 1104f273041fSjm cmn_err(CE_PANIC, "init_md_broken: platform node missing"); 11051ae08745Sheppo 11064bac2208Snarayan if (md_get_prop_data(mdp, cpulist[0], 11074bac2208Snarayan "compatible", (uint8_t **)&namebuf, &namelen)) { 11084bac2208Snarayan cmn_err(CE_PANIC, "init_md_broken: " 11094bac2208Snarayan "Cannot read 'compatible' property of 'cpu' node"); 11104bac2208Snarayan } 11117c478bd9Sstevel@tonic-gate 11124bac2208Snarayan if (md_get_prop_val(mdp, platlist[0], 1113ad8d2eb8Szx "domaining-enabled", &val) == -1 && 11144bac2208Snarayan strcmp(namebuf, "SUNW,UltraSPARC-T1") == 0) 11151ae08745Sheppo broken_md_flag = 1; 11161ae08745Sheppo 11171ae08745Sheppo md_free_scan_dag(mdp, &platlist); 11187c478bd9Sstevel@tonic-gate } 1119125be069SJason Beloro 1120125be069SJason Beloro /* 1121125be069SJason Beloro * This routine gets the MD properties associated with the TLB search order API 1122125be069SJason Beloro * and compares these against the expected values for a processor which supports 1123125be069SJason Beloro * this API. The return value is used to determine whether use the API. 1124125be069SJason Beloro */ 1125125be069SJason Beloro static int 1126125be069SJason Beloro check_mmu_pgsz_search(md_t *mdp, mde_cookie_t cpu_node_cookie) 1127125be069SJason Beloro { 1128125be069SJason Beloro 1129125be069SJason Beloro uint64_t mmu_search_nshared_contexts; 1130125be069SJason Beloro uint64_t mmu_max_search_order; 1131125be069SJason Beloro uint64_t mmu_non_priv_search_unified; 1132125be069SJason Beloro uint64_t mmu_search_page_size_list; 1133125be069SJason Beloro 1134125be069SJason Beloro if (md_get_prop_val(mdp, cpu_node_cookie, 1135125be069SJason Beloro "mmu-search-#shared-contexts", &mmu_search_nshared_contexts)) 1136125be069SJason Beloro mmu_search_nshared_contexts = 0; 1137125be069SJason Beloro 1138125be069SJason Beloro if (mmu_search_nshared_contexts == 0 || 1139125be069SJason Beloro mmu_search_nshared_contexts != NSEARCH_SHCONTEXTS) 1140125be069SJason Beloro return (0); 1141125be069SJason Beloro 1142125be069SJason Beloro if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-search-order", 1143125be069SJason Beloro &mmu_max_search_order)) 1144125be069SJason Beloro mmu_max_search_order = 0; 1145125be069SJason Beloro 1146125be069SJason Beloro if (mmu_max_search_order == 0 || mmu_max_search_order != 1147125be069SJason Beloro MAX_PGSZ_SEARCH_ORDER) 1148125be069SJason Beloro return (0); 1149125be069SJason Beloro 1150125be069SJason Beloro if (md_get_prop_val(mdp, cpu_node_cookie, 1151125be069SJason Beloro "mmu-non-priv-search-unified", &mmu_non_priv_search_unified)) 1152125be069SJason Beloro mmu_non_priv_search_unified = -1; 1153125be069SJason Beloro 1154125be069SJason Beloro if (mmu_non_priv_search_unified != 1) { 1155125be069SJason Beloro return (0); 1156125be069SJason Beloro } 1157125be069SJason Beloro 1158125be069SJason Beloro if (md_get_prop_val(mdp, cpu_node_cookie, 1159125be069SJason Beloro "mmu-search-page-size-list", &mmu_search_page_size_list)) { 1160125be069SJason Beloro mmu_search_page_size_list = 0; 1161125be069SJason Beloro return (0); 1162125be069SJason Beloro } 1163125be069SJason Beloro 1164125be069SJason Beloro return (1); 1165125be069SJason Beloro } 1166