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 /* 22fb2f18f8Sesaxe * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/errno.h> 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/param.h> 317c478bd9Sstevel@tonic-gate #include <sys/cpu.h> 327c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 337c478bd9Sstevel@tonic-gate #include <sys/clock.h> 347c478bd9Sstevel@tonic-gate #include <sys/promif.h> 357c478bd9Sstevel@tonic-gate #include <sys/promimpl.h> 367c478bd9Sstevel@tonic-gate #include <sys/systm.h> 377c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 387c478bd9Sstevel@tonic-gate #include <sys/debug.h> 397c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 407c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 417c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 427c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 437c478bd9Sstevel@tonic-gate #include <sys/cmp.h> 447c478bd9Sstevel@tonic-gate #include <sys/async.h> 457c478bd9Sstevel@tonic-gate #include <vm/page.h> 461ae08745Sheppo #include <vm/hat_sfmmu.h> 471ae08745Sheppo #include <sys/sysmacros.h> 481ae08745Sheppo #include <sys/mach_descrip.h> 491ae08745Sheppo #include <sys/mdesc.h> 501ae08745Sheppo #include <sys/archsystm.h> 511ae08745Sheppo #include <sys/error.h> 521ae08745Sheppo #include <sys/mmu.h> 531ae08745Sheppo #include <sys/bitmap.h> 544bac2208Snarayan #include <sys/intreg.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate int ncpunode; 577c478bd9Sstevel@tonic-gate struct cpu_node cpunodes[NCPU]; 587c478bd9Sstevel@tonic-gate 591ae08745Sheppo uint64_t cpu_q_entries; 601ae08745Sheppo uint64_t dev_q_entries; 611ae08745Sheppo uint64_t cpu_rq_entries; 621ae08745Sheppo uint64_t cpu_nrq_entries; 63*aaa10e67Sha uint64_t ncpu_guest_max; 641ae08745Sheppo 651ae08745Sheppo void fill_cpu(md_t *, mde_cookie_t); 661ae08745Sheppo 671ae08745Sheppo static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t); 681ae08745Sheppo static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t); 691ae08745Sheppo static char *construct_isalist(md_t *, mde_cookie_t, char **); 701ae08745Sheppo static void set_at_flags(char *, int, 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 *); 741ae08745Sheppo static id_t get_exec_unit_mapping(md_t *, mde_cookie_t, mde_cookie_t *); 751ae08745Sheppo static int find_exec_unit_id(mde_cookie_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); 781ae08745Sheppo static size_t get_ra_limit(md_t *); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate uint64_t system_clock_freq; 817c478bd9Sstevel@tonic-gate int niobus = 0; 827c478bd9Sstevel@tonic-gate uint_t niommu_tsbs = 0; 837c478bd9Sstevel@tonic-gate 84fedab560Sae /* prevent compilation with VAC defined */ 85fedab560Sae #ifdef VAC 86fedab560Sae #error "The sun4v architecture does not support VAC" 87fedab560Sae #endif 88fedab560Sae 89fedab560Sae #define S_VAC_SIZE MMU_PAGESIZE 90fedab560Sae #define S_VAC_SHIFT MMU_PAGESHIFT 91fedab560Sae 92fedab560Sae int vac_size = S_VAC_SIZE; 93fedab560Sae uint_t vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1); 94fedab560Sae int vac_shift = S_VAC_SHIFT; 95fedab560Sae uintptr_t shm_alignment = S_VAC_SIZE; 96fedab560Sae 971ae08745Sheppo void 981ae08745Sheppo map_wellknown_devices() 991ae08745Sheppo { 1001ae08745Sheppo } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate void 1031ae08745Sheppo fill_cpu(md_t *mdp, mde_cookie_t cpuc) 1047c478bd9Sstevel@tonic-gate { 1051ae08745Sheppo struct cpu_node *cpunode; 1061ae08745Sheppo uint64_t cpuid; 1071ae08745Sheppo uint64_t clk_freq; 1081ae08745Sheppo char *namebuf; 1091ae08745Sheppo char *namebufp; 1101ae08745Sheppo int namelen; 1111ae08745Sheppo uint64_t associativity = 0, linesize = 0, size = 0; 1121ae08745Sheppo 1131ae08745Sheppo if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) { 1141ae08745Sheppo return; 1151ae08745Sheppo } 1167c478bd9Sstevel@tonic-gate 1174bac2208Snarayan /* All out-of-range cpus will be stopped later. */ 1181ae08745Sheppo if (cpuid >= NCPU) { 1191ae08745Sheppo cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - " 1204bac2208Snarayan "cpu excluded from configuration\n", cpuid); 1211ae08745Sheppo 1221ae08745Sheppo return; 1231ae08745Sheppo } 1241ae08745Sheppo 1251ae08745Sheppo cpunode = &cpunodes[cpuid]; 1261ae08745Sheppo cpunode->cpuid = (int)cpuid; 1271ae08745Sheppo cpunode->device_id = cpuid; 1281ae08745Sheppo 1291ae08745Sheppo if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI)) 1301ae08745Sheppo (void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI); 1311ae08745Sheppo 1321ae08745Sheppo if (md_get_prop_data(mdp, cpuc, 1331ae08745Sheppo "compatible", (uint8_t **)&namebuf, &namelen)) { 1341ae08745Sheppo cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible " 1351ae08745Sheppo "property"); 1361ae08745Sheppo } 1371ae08745Sheppo namebufp = namebuf; 1381ae08745Sheppo if (strncmp(namebufp, "SUNW,", 5) == 0) 1391ae08745Sheppo namebufp += 5; 1401ae08745Sheppo if (strlen(namebufp) > sizeof (cpunode->name)) 1411ae08745Sheppo cmn_err(CE_PANIC, "Compatible property too big to " 1421ae08745Sheppo "fit into the cpunode name buffer"); 1431ae08745Sheppo (void) strcpy(cpunode->name, namebufp); 1441ae08745Sheppo 1451ae08745Sheppo if (md_get_prop_val(mdp, cpuc, 1461ae08745Sheppo "clock-frequency", &clk_freq)) { 1471ae08745Sheppo clk_freq = 0; 1481ae08745Sheppo } 1491ae08745Sheppo cpunode->clock_freq = clk_freq; 1501ae08745Sheppo 1511ae08745Sheppo ASSERT(cpunode->clock_freq != 0); 1527c478bd9Sstevel@tonic-gate /* 1531ae08745Sheppo * Compute scaling factor based on rate of %tick. This is used 1541ae08745Sheppo * to convert from ticks derived from %tick to nanoseconds. See 1551ae08745Sheppo * comment in sun4u/sys/clock.h for details. 1567c478bd9Sstevel@tonic-gate */ 1571ae08745Sheppo cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 1581ae08745Sheppo (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1611ae08745Sheppo * The nodeid is not used in sun4v at all. Setting it 1621ae08745Sheppo * to positive value to make starting of slave CPUs 1631ae08745Sheppo * code happy. 1647c478bd9Sstevel@tonic-gate */ 1651ae08745Sheppo cpunode->nodeid = cpuid + 1; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1681ae08745Sheppo * Obtain the L2 cache information from MD. 1691ae08745Sheppo * If "Cache" node exists, then set L2 cache properties 1701ae08745Sheppo * as read from MD. 1711ae08745Sheppo * If node does not exists, then set the L2 cache properties 1721ae08745Sheppo * in individual CPU module. 1737c478bd9Sstevel@tonic-gate */ 1741ae08745Sheppo if ((!get_l2_cache_info(mdp, cpuc, 1751ae08745Sheppo &associativity, &size, &linesize)) || 1761ae08745Sheppo associativity == 0 || size == 0 || linesize == 0) { 1771ae08745Sheppo cpu_fiximp(cpunode); 1781ae08745Sheppo } else { 1791ae08745Sheppo /* 1801ae08745Sheppo * Do not expect L2 cache properties to be bigger 1811ae08745Sheppo * than 32-bit quantity. 1821ae08745Sheppo */ 1831ae08745Sheppo cpunode->ecache_associativity = (int)associativity; 1841ae08745Sheppo cpunode->ecache_size = (int)size; 1851ae08745Sheppo cpunode->ecache_linesize = (int)linesize; 1867c478bd9Sstevel@tonic-gate } 1871ae08745Sheppo 1881ae08745Sheppo cpunode->ecache_setsize = 1891ae08745Sheppo cpunode->ecache_size / cpunode->ecache_associativity; 1901ae08745Sheppo 1911ae08745Sheppo /* 1921ae08745Sheppo * Start off by assigning the cpu id as the default 1931ae08745Sheppo * mapping index. 1941ae08745Sheppo */ 1951ae08745Sheppo 1961ae08745Sheppo cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND; 1971ae08745Sheppo 1981ae08745Sheppo if (ecache_setsize == 0) 1991ae08745Sheppo ecache_setsize = cpunode->ecache_setsize; 2001ae08745Sheppo if (ecache_alignsize == 0) 2011ae08745Sheppo ecache_alignsize = cpunode->ecache_linesize; 2021ae08745Sheppo 2031ae08745Sheppo ncpunode++; 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2061ae08745Sheppo void 2071ae08745Sheppo empty_cpu(int cpuid) 2087c478bd9Sstevel@tonic-gate { 2091ae08745Sheppo bzero(&cpunodes[cpuid], sizeof (struct cpu_node)); 2101ae08745Sheppo ncpunode--; 2111ae08745Sheppo } 2127c478bd9Sstevel@tonic-gate 2131ae08745Sheppo void 2141ae08745Sheppo setup_exec_unit_mappings(md_t *mdp) 2151ae08745Sheppo { 2161ae08745Sheppo uint64_t num, num_eunits; 2171ae08745Sheppo mde_cookie_t cpus_node; 2181ae08745Sheppo mde_cookie_t *node, *eunit; 2191ae08745Sheppo int idx, i, j; 2201ae08745Sheppo processorid_t cpuid; 2211ae08745Sheppo char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit"; 222fb2f18f8Sesaxe enum eu_type { INTEGER, FPU } etype; 2237c478bd9Sstevel@tonic-gate 2241ae08745Sheppo /* 2251ae08745Sheppo * Find the cpu integer exec units - and 2261ae08745Sheppo * setup the mappings appropriately. 2271ae08745Sheppo */ 2281ae08745Sheppo num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node); 2291ae08745Sheppo if (num < 1) 2304bac2208Snarayan cmn_err(CE_PANIC, "No cpus node in machine description"); 2311ae08745Sheppo if (num > 1) 2321ae08745Sheppo cmn_err(CE_PANIC, "More than 1 cpus node in machine" 2331ae08745Sheppo " description"); 2341ae08745Sheppo 2351ae08745Sheppo cpus_node = node[0]; 2361ae08745Sheppo md_free_scan_dag(mdp, &node); 2371ae08745Sheppo 2381ae08745Sheppo num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name, 2391ae08745Sheppo "fwd", &eunit); 2401ae08745Sheppo if (num_eunits > 0) { 241fb2f18f8Sesaxe char *int_str = broken_md_flag ? "int" : "integer"; 242fb2f18f8Sesaxe char *fpu_str = "fp"; 2431ae08745Sheppo 2441ae08745Sheppo /* Spin through and find all the integer exec units */ 2451ae08745Sheppo for (i = 0; i < num_eunits; i++) { 2461ae08745Sheppo char *p; 2471ae08745Sheppo char *val; 2481ae08745Sheppo int vallen; 2491ae08745Sheppo uint64_t lcpuid; 2501ae08745Sheppo 251fb2f18f8Sesaxe /* ignore nodes with no type */ 2521ae08745Sheppo if (md_get_prop_data(mdp, eunit[i], "type", 2531ae08745Sheppo (uint8_t **)&val, &vallen)) continue; 2541ae08745Sheppo 2551ae08745Sheppo for (p = val; *p != '\0'; p += strlen(p) + 1) { 256fb2f18f8Sesaxe if (strcmp(p, int_str) == 0) { 257fb2f18f8Sesaxe etype = INTEGER; 2581ae08745Sheppo goto found; 259fb2f18f8Sesaxe } 260fb2f18f8Sesaxe if (strcmp(p, fpu_str) == 0) { 261fb2f18f8Sesaxe etype = FPU; 262fb2f18f8Sesaxe goto found; 263fb2f18f8Sesaxe } 2647c478bd9Sstevel@tonic-gate } 2651ae08745Sheppo 2661ae08745Sheppo continue; 2671ae08745Sheppo found: 2681ae08745Sheppo idx = NCPU + i; 2697c478bd9Sstevel@tonic-gate /* 2701ae08745Sheppo * find the cpus attached to this EU and 2711ae08745Sheppo * update their mapping indices 2727c478bd9Sstevel@tonic-gate */ 2731ae08745Sheppo num = md_alloc_scan_dag(mdp, eunit[i], "cpu", 2741ae08745Sheppo "back", &node); 2751ae08745Sheppo 2761ae08745Sheppo if (num < 1) 2771ae08745Sheppo cmn_err(CE_PANIC, "exec-unit node in MD" 2781ae08745Sheppo " not attached to a cpu node"); 2791ae08745Sheppo 2801ae08745Sheppo for (j = 0; j < num; j++) { 2811ae08745Sheppo if (md_get_prop_val(mdp, node[j], "id", 2821ae08745Sheppo &lcpuid)) 2831ae08745Sheppo continue; 2841ae08745Sheppo if (lcpuid >= NCPU) 2851ae08745Sheppo continue; 2861ae08745Sheppo cpuid = (processorid_t)lcpuid; 287fb2f18f8Sesaxe switch (etype) { 288fb2f18f8Sesaxe case INTEGER: 289fb2f18f8Sesaxe cpunodes[cpuid].exec_unit_mapping = idx; 290fb2f18f8Sesaxe break; 291fb2f18f8Sesaxe case FPU: 292fb2f18f8Sesaxe cpunodes[cpuid].fpu_mapping = idx; 293fb2f18f8Sesaxe break; 294fb2f18f8Sesaxe } 2951ae08745Sheppo } 2961ae08745Sheppo md_free_scan_dag(mdp, &node); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2991ae08745Sheppo 3001ae08745Sheppo md_free_scan_dag(mdp, &eunit); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3041ae08745Sheppo /* 3051ae08745Sheppo * All the common setup of sun4v CPU modules is done by this routine. 3061ae08745Sheppo */ 3071ae08745Sheppo void 3081ae08745Sheppo cpu_setup_common(char **cpu_module_isa_set) 3097c478bd9Sstevel@tonic-gate { 3101ae08745Sheppo extern int disable_delay_tlb_flush, delay_tlb_flush; 3111ae08745Sheppo extern int mmu_exported_pagesize_mask; 3121ae08745Sheppo int nocpus, i; 3131ae08745Sheppo size_t ra_limit; 3141ae08745Sheppo mde_cookie_t *cpulist; 3151ae08745Sheppo md_t *mdp; 3161ae08745Sheppo 3171ae08745Sheppo if ((mdp = md_get_handle()) == NULL) 3181ae08745Sheppo cmn_err(CE_PANIC, "Unable to initialize machine description"); 3191ae08745Sheppo 3201ae08745Sheppo nocpus = md_alloc_scan_dag(mdp, 3211ae08745Sheppo md_root_node(mdp), "cpu", "fwd", &cpulist); 3221ae08745Sheppo if (nocpus < 1) { 3231ae08745Sheppo cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation " 3241ae08745Sheppo "failed or incorrect number of CPUs in MD"); 3251ae08745Sheppo } 3267c478bd9Sstevel@tonic-gate 3274bac2208Snarayan init_md_broken(mdp, cpulist); 3284bac2208Snarayan 3291ae08745Sheppo if (use_page_coloring) { 3301ae08745Sheppo do_pg_coloring = 1; 3311ae08745Sheppo if (use_virtual_coloring) { 3321ae08745Sheppo /* 3331ae08745Sheppo * XXX Sun4v cpus don't have virtual caches 3341ae08745Sheppo */ 3351ae08745Sheppo do_virtual_coloring = 1; 3367c478bd9Sstevel@tonic-gate } 3371ae08745Sheppo } 3381ae08745Sheppo 3391ae08745Sheppo /* 3401e2e7a75Shuah * Get the valid mmu page sizes mask, Q sizes and isalist/r 3411ae08745Sheppo * from the MD for the first available CPU in cpulist. 3421e2e7a75Shuah * 3431e2e7a75Shuah * Do not expect the MMU page sizes mask to be more than 32-bit. 3441ae08745Sheppo */ 3451ae08745Sheppo mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]); 3461ae08745Sheppo 3471ae08745Sheppo for (i = 0; i < nocpus; i++) 3481ae08745Sheppo fill_cpu(mdp, cpulist[i]); 3491ae08745Sheppo 3501ae08745Sheppo setup_exec_unit_mappings(mdp); 3511ae08745Sheppo 3521ae08745Sheppo /* 3531ae08745Sheppo * If MD is broken then append the passed ISA set, 3541ae08745Sheppo * otherwise trust the MD. 3551ae08745Sheppo */ 3561ae08745Sheppo 3571ae08745Sheppo if (broken_md_flag) 3581ae08745Sheppo isa_list = construct_isalist(mdp, cpulist[0], 3591ae08745Sheppo cpu_module_isa_set); 3601ae08745Sheppo else 3611ae08745Sheppo isa_list = construct_isalist(mdp, cpulist[0], NULL); 3621ae08745Sheppo 3631ae08745Sheppo get_q_sizes(mdp, cpulist[0]); 3641ae08745Sheppo 3651ae08745Sheppo get_va_bits(mdp, cpulist[0]); 3661ae08745Sheppo 3671ae08745Sheppo /* 3681ae08745Sheppo * ra_limit is the highest real address in the machine. 3691ae08745Sheppo */ 3701ae08745Sheppo ra_limit = get_ra_limit(mdp); 3711ae08745Sheppo 3721ae08745Sheppo md_free_scan_dag(mdp, &cpulist); 3731ae08745Sheppo 3741ae08745Sheppo (void) md_fini_handle(mdp); 3751ae08745Sheppo 3761ae08745Sheppo /* 3771ae08745Sheppo * Block stores invalidate all pages of the d$ so pagecopy 3781ae08745Sheppo * et. al. do not need virtual translations with virtual 3791ae08745Sheppo * coloring taken into consideration. 3801ae08745Sheppo */ 3811ae08745Sheppo pp_consistent_coloring = 0; 3821ae08745Sheppo 3831ae08745Sheppo /* 3841ae08745Sheppo * The kpm mapping window. 3851ae08745Sheppo * kpm_size: 3861ae08745Sheppo * The size of a single kpm range. 3871ae08745Sheppo * The overall size will be: kpm_size * vac_colors. 3881ae08745Sheppo * kpm_vbase: 3891ae08745Sheppo * The virtual start address of the kpm range within the kernel 3901ae08745Sheppo * virtual address space. kpm_vbase has to be kpm_size aligned. 3911ae08745Sheppo */ 3921ae08745Sheppo 3931ae08745Sheppo /* 3941ae08745Sheppo * Make kpm_vbase, kpm_size aligned to kpm_size_shift. 3951ae08745Sheppo * To do this find the nearest power of 2 size that the 3961ae08745Sheppo * actual ra_limit fits within. 3971ae08745Sheppo * If it is an even power of two use that, otherwise use the 3981ae08745Sheppo * next power of two larger than ra_limit. 3991ae08745Sheppo */ 4001ae08745Sheppo 4011ae08745Sheppo ASSERT(ra_limit != 0); 4021ae08745Sheppo 4031ae08745Sheppo kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ? 4041ae08745Sheppo highbit(ra_limit) : highbit(ra_limit) - 1; 4051ae08745Sheppo 4061ae08745Sheppo /* 4071ae08745Sheppo * No virtual caches on sun4v so size matches size shift 4081ae08745Sheppo */ 4091ae08745Sheppo kpm_size = 1ul << kpm_size_shift; 4101ae08745Sheppo 4111ae08745Sheppo if (va_bits < VA_ADDRESS_SPACE_BITS) { 4127c478bd9Sstevel@tonic-gate /* 4131ae08745Sheppo * In case of VA hole 4141ae08745Sheppo * kpm_base = hole_end + 1TB 4151ae08745Sheppo * Starting 1TB beyond where VA hole ends because on Niagara 4161ae08745Sheppo * processor software must not use pages within 4GB of the 4171ae08745Sheppo * VA hole as instruction pages to avoid problems with 4181ae08745Sheppo * prefetching into the VA hole. 4197c478bd9Sstevel@tonic-gate */ 4201ae08745Sheppo kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) + 4211ae08745Sheppo (1ull << 40)); 4221ae08745Sheppo } else { /* Number of VA bits 64 ... no VA hole */ 4231ae08745Sheppo kpm_vbase = (caddr_t)0x8000000000000000ull; /* 8 EB */ 4247c478bd9Sstevel@tonic-gate } 4251ae08745Sheppo 4261ae08745Sheppo /* 4271ae08745Sheppo * The traptrace code uses either %tick or %stick for 4281ae08745Sheppo * timestamping. The sun4v require use of %stick. 4291ae08745Sheppo */ 4301ae08745Sheppo traptrace_use_stick = 1; 4311ae08745Sheppo 4321ae08745Sheppo /* 4331ae08745Sheppo * sun4v provides demap_all 4341ae08745Sheppo */ 4351ae08745Sheppo if (!disable_delay_tlb_flush) 4361ae08745Sheppo delay_tlb_flush = 1; 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4391ae08745Sheppo /* 4401ae08745Sheppo * Get the nctxs from MD. If absent panic. 4411ae08745Sheppo */ 4421ae08745Sheppo static uint64_t 4431ae08745Sheppo get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 4447c478bd9Sstevel@tonic-gate { 4451ae08745Sheppo uint64_t ctx_bits; 4467c478bd9Sstevel@tonic-gate 4471ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits", 4481ae08745Sheppo &ctx_bits)) 4491ae08745Sheppo ctx_bits = 0; 4507c478bd9Sstevel@tonic-gate 4511ae08745Sheppo if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS) 4521ae08745Sheppo cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits " 4531ae08745Sheppo "returned by MD", ctx_bits); 4547c478bd9Sstevel@tonic-gate 4551ae08745Sheppo return (ctx_bits); 4561ae08745Sheppo } 4577c478bd9Sstevel@tonic-gate 4581ae08745Sheppo /* 4591ae08745Sheppo * Initalize supported page sizes information. 4601ae08745Sheppo * Set to 0, if the page sizes mask information is absent in MD. 4611ae08745Sheppo */ 4621ae08745Sheppo static uint64_t 4631ae08745Sheppo get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 4641ae08745Sheppo { 4651ae08745Sheppo uint64_t mmu_page_size_list; 4667c478bd9Sstevel@tonic-gate 4671ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list", 4681ae08745Sheppo &mmu_page_size_list)) 4691ae08745Sheppo mmu_page_size_list = 0; 4701ae08745Sheppo 4711ae08745Sheppo if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK) 4721ae08745Sheppo cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned" 4731ae08745Sheppo "by MD", mmu_page_size_list); 4741ae08745Sheppo 4751ae08745Sheppo return (mmu_page_size_list); 4761ae08745Sheppo } 4771ae08745Sheppo 4781ae08745Sheppo /* 4791ae08745Sheppo * This routine gets the isalist information from MD and appends 4801ae08745Sheppo * the CPU module ISA set if required. 4811ae08745Sheppo */ 4821ae08745Sheppo static char * 4831ae08745Sheppo construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie, 4841ae08745Sheppo char **cpu_module_isa_set) 4851ae08745Sheppo { 4861ae08745Sheppo extern int at_flags; 4871ae08745Sheppo char *md_isalist; 4881ae08745Sheppo int md_isalen; 4891ae08745Sheppo char *isabuf; 4901ae08745Sheppo int isalen; 4911ae08745Sheppo char **isa_set; 4921ae08745Sheppo char *p, *q; 4931ae08745Sheppo int cpu_module_isalen = 0, found = 0; 4941ae08745Sheppo 4951ae08745Sheppo (void) md_get_prop_data(mdp, cpu_node_cookie, 4961ae08745Sheppo "isalist", (uint8_t **)&isabuf, &isalen); 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* 4991ae08745Sheppo * We support binaries for all the cpus that have shipped so far. 5001ae08745Sheppo * The kernel emulates instructions that are not supported by hardware. 5017c478bd9Sstevel@tonic-gate */ 5021ae08745Sheppo at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1; 5037c478bd9Sstevel@tonic-gate 5041ae08745Sheppo /* 5051ae08745Sheppo * Construct the space separated isa_list. 5061ae08745Sheppo */ 5071ae08745Sheppo if (cpu_module_isa_set != NULL) { 5081ae08745Sheppo for (isa_set = cpu_module_isa_set; *isa_set != NULL; 5091ae08745Sheppo isa_set++) { 5101ae08745Sheppo cpu_module_isalen += strlen(*isa_set); 5111ae08745Sheppo cpu_module_isalen++; /* for space character */ 5121ae08745Sheppo } 5131ae08745Sheppo } 5147c478bd9Sstevel@tonic-gate 5151ae08745Sheppo /* 5161ae08745Sheppo * Allocate the buffer of MD isa buffer length + CPU module 5171ae08745Sheppo * isa buffer length. 5181ae08745Sheppo */ 5191ae08745Sheppo md_isalen = isalen + cpu_module_isalen + 2; 5201ae08745Sheppo md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0); 5211ae08745Sheppo if (md_isalist == NULL) 5221ae08745Sheppo cmn_err(CE_PANIC, "construct_isalist: Allocation failed for " 5231ae08745Sheppo "md_isalist"); 5241ae08745Sheppo 5251ae08745Sheppo md_isalist[0] = '\0'; /* create an empty string to start */ 5261ae08745Sheppo for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) { 5271ae08745Sheppo (void) strlcat(md_isalist, p, md_isalen); 5281ae08745Sheppo (void) strcat(md_isalist, " "); 5291ae08745Sheppo } 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate /* 5321ae08745Sheppo * Check if the isa_set is present in isalist returned by MD. 5331ae08745Sheppo * If yes, then no need to append it, if no then append it to 5341ae08745Sheppo * isalist returned by MD. 5357c478bd9Sstevel@tonic-gate */ 5361ae08745Sheppo if (cpu_module_isa_set != NULL) { 5371ae08745Sheppo for (isa_set = cpu_module_isa_set; *isa_set != NULL; 5381ae08745Sheppo isa_set++) { 5391ae08745Sheppo found = 0; 5401ae08745Sheppo for (p = isabuf, q = p + isalen; p < q; 5411ae08745Sheppo p += strlen(p) + 1) { 5421ae08745Sheppo if (strcmp(p, *isa_set) == 0) { 5431ae08745Sheppo found = 1; 5441ae08745Sheppo break; 5451ae08745Sheppo } 5461ae08745Sheppo } 5471ae08745Sheppo if (!found) { 5481ae08745Sheppo (void) strlcat(md_isalist, *isa_set, md_isalen); 5491ae08745Sheppo (void) strcat(md_isalist, " "); 5501ae08745Sheppo } 5511ae08745Sheppo } 5521ae08745Sheppo } 5531ae08745Sheppo 5541ae08745Sheppo /* Get rid of any trailing white spaces */ 5551ae08745Sheppo md_isalist[strlen(md_isalist) - 1] = '\0'; 5561ae08745Sheppo 5571ae08745Sheppo return (md_isalist); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5601ae08745Sheppo uint64_t 5611ae08745Sheppo get_ra_limit(md_t *mdp) 5621ae08745Sheppo { 5631ae08745Sheppo mde_cookie_t *mem_list; 5641ae08745Sheppo mde_cookie_t *mblock_list; 5651ae08745Sheppo int i; 5661ae08745Sheppo int memnodes; 5671ae08745Sheppo int nmblock; 5681ae08745Sheppo uint64_t base; 5691ae08745Sheppo uint64_t size; 5701ae08745Sheppo uint64_t ra_limit = 0, new_limit = 0; 5711ae08745Sheppo 5721ae08745Sheppo memnodes = md_alloc_scan_dag(mdp, 5731ae08745Sheppo md_root_node(mdp), "memory", "fwd", &mem_list); 5741ae08745Sheppo 5751ae08745Sheppo ASSERT(memnodes == 1); 5761ae08745Sheppo 5771ae08745Sheppo nmblock = md_alloc_scan_dag(mdp, 5781ae08745Sheppo mem_list[0], "mblock", "fwd", &mblock_list); 5791ae08745Sheppo if (nmblock < 1) 5801ae08745Sheppo cmn_err(CE_PANIC, "cannot find mblock nodes in MD"); 5811ae08745Sheppo 5821ae08745Sheppo for (i = 0; i < nmblock; i++) { 5831ae08745Sheppo if (md_get_prop_val(mdp, mblock_list[i], "base", &base)) 5841ae08745Sheppo cmn_err(CE_PANIC, "base property missing from MD" 5851ae08745Sheppo " mblock node"); 5861ae08745Sheppo if (md_get_prop_val(mdp, mblock_list[i], "size", &size)) 5871ae08745Sheppo cmn_err(CE_PANIC, "size property missing from MD" 5881ae08745Sheppo " mblock node"); 5891ae08745Sheppo 5901ae08745Sheppo ASSERT(size != 0); 5911ae08745Sheppo 5921ae08745Sheppo new_limit = base + size; 5931ae08745Sheppo 5941ae08745Sheppo if (base > new_limit) 5951ae08745Sheppo cmn_err(CE_PANIC, "mblock in MD wrapped around"); 5961ae08745Sheppo 5971ae08745Sheppo if (new_limit > ra_limit) 5981ae08745Sheppo ra_limit = new_limit; 5991ae08745Sheppo } 6001ae08745Sheppo 6011ae08745Sheppo ASSERT(ra_limit != 0); 6021ae08745Sheppo 6031ae08745Sheppo if (ra_limit > MAX_REAL_ADDRESS) { 6041ae08745Sheppo cmn_err(CE_WARN, "Highest real address in MD too large" 6051ae08745Sheppo " clipping to %llx\n", MAX_REAL_ADDRESS); 6061ae08745Sheppo ra_limit = MAX_REAL_ADDRESS; 6071ae08745Sheppo } 6081ae08745Sheppo 6091ae08745Sheppo md_free_scan_dag(mdp, &mblock_list); 6101ae08745Sheppo 6111ae08745Sheppo md_free_scan_dag(mdp, &mem_list); 6121ae08745Sheppo 6131ae08745Sheppo return (ra_limit); 6141ae08745Sheppo } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* 6171ae08745Sheppo * This routine sets the globals for CPU and DEV mondo queue entries and 6181ae08745Sheppo * resumable and non-resumable error queue entries. 6194bac2208Snarayan * 6204bac2208Snarayan * First, look up the number of bits available to pass an entry number. 6214bac2208Snarayan * This can vary by platform and may result in allocating an unreasonably 6224bac2208Snarayan * (or impossibly) large amount of memory for the corresponding table, 6234bac2208Snarayan * so we clamp it by 'max_entries'. If the prop is missing, use 6244bac2208Snarayan * 'default_entries'. 6257c478bd9Sstevel@tonic-gate */ 6261ae08745Sheppo static uint64_t 6271ae08745Sheppo get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie, 6284bac2208Snarayan char *qnamep, uint64_t default_entries, uint64_t max_entries) 6291ae08745Sheppo { 6301ae08745Sheppo uint64_t entries; 6311ae08745Sheppo 6324bac2208Snarayan if (default_entries > max_entries) 6334bac2208Snarayan cmn_err(CE_CONT, "!get_single_q_size: dflt %ld > " 6344bac2208Snarayan "max %ld for %s\n", default_entries, max_entries, qnamep); 6354bac2208Snarayan 6361ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) { 6371ae08745Sheppo if (!broken_md_flag) 6381ae08745Sheppo cmn_err(CE_PANIC, "Missing %s property in MD cpu node", 6391ae08745Sheppo qnamep); 6401ae08745Sheppo entries = default_entries; 6411ae08745Sheppo } else { 6421ae08745Sheppo entries = 1 << entries; 6431ae08745Sheppo } 6444bac2208Snarayan 6454bac2208Snarayan entries = MIN(entries, max_entries); 6464bac2208Snarayan 6471ae08745Sheppo return (entries); 6481ae08745Sheppo } 6491ae08745Sheppo 6504bac2208Snarayan /* Scaling constant used to compute size of cpu mondo queue */ 6514bac2208Snarayan #define CPU_MONDO_Q_MULTIPLIER 8 6521ae08745Sheppo 6537c478bd9Sstevel@tonic-gate static void 6541ae08745Sheppo get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 6557c478bd9Sstevel@tonic-gate { 6564bac2208Snarayan uint64_t max_qsize; 6574bac2208Snarayan mde_cookie_t *platlist; 6584bac2208Snarayan int nrnode; 6594bac2208Snarayan 6604bac2208Snarayan /* 6614bac2208Snarayan * Compute the maximum number of entries for the cpu mondo queue. 6624bac2208Snarayan * Use the appropriate property in the platform node, if it is 6634bac2208Snarayan * available. Else, base it on NCPU. 6644bac2208Snarayan */ 6654bac2208Snarayan nrnode = md_alloc_scan_dag(mdp, 6664bac2208Snarayan md_root_node(mdp), "platform", "fwd", &platlist); 6674bac2208Snarayan 6684bac2208Snarayan ASSERT(nrnode == 1); 6694bac2208Snarayan 670*aaa10e67Sha ncpu_guest_max = NCPU; 671*aaa10e67Sha (void) md_get_prop_val(mdp, platlist[0], "max-cpus", &ncpu_guest_max); 672*aaa10e67Sha max_qsize = ncpu_guest_max * CPU_MONDO_Q_MULTIPLIER; 6734bac2208Snarayan 6744bac2208Snarayan md_free_scan_dag(mdp, &platlist); 6754bac2208Snarayan 6761ae08745Sheppo cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie, 6774bac2208Snarayan "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES, max_qsize); 6781ae08745Sheppo 6791ae08745Sheppo dev_q_entries = get_single_q_size(mdp, cpu_node_cookie, 680b0fc0e77Sgovinda "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES, MAXIVNUM); 6811ae08745Sheppo 6821ae08745Sheppo cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie, 6834bac2208Snarayan "q-resumable-#bits", CPU_RQ_ENTRIES, MAX_CPU_RQ_ENTRIES); 6841ae08745Sheppo 6851ae08745Sheppo cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie, 6864bac2208Snarayan "q-nonresumable-#bits", CPU_NRQ_ENTRIES, MAX_CPU_NRQ_ENTRIES); 6871ae08745Sheppo } 6881ae08745Sheppo 6891ae08745Sheppo 6901ae08745Sheppo static void 6911ae08745Sheppo get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 6921ae08745Sheppo { 6931ae08745Sheppo uint64_t value = VA_ADDRESS_SPACE_BITS; 6941ae08745Sheppo 6951ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value)) 6961ae08745Sheppo cmn_err(CE_PANIC, "mmu-#va-bits property not found in MD"); 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate 6991ae08745Sheppo if (value == 0 || value > VA_ADDRESS_SPACE_BITS) 7001ae08745Sheppo cmn_err(CE_PANIC, "Incorrect number of va bits in MD"); 7017c478bd9Sstevel@tonic-gate 7021ae08745Sheppo /* Do not expect number of VA bits to be more than 32-bit quantity */ 7037c478bd9Sstevel@tonic-gate 7041ae08745Sheppo va_bits = (int)value; 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* 7071ae08745Sheppo * Correct the value for VA bits on UltraSPARC-T1 based systems 7081ae08745Sheppo * in case of broken MD. 7097c478bd9Sstevel@tonic-gate */ 7101ae08745Sheppo if (broken_md_flag) 7111ae08745Sheppo va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS; 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7141ae08745Sheppo /* 7151ae08745Sheppo * This routine returns the L2 cache information such as -- associativity, 7161ae08745Sheppo * size and linesize. 7171ae08745Sheppo */ 7181ae08745Sheppo static int 7191ae08745Sheppo get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie, 7201ae08745Sheppo uint64_t *associativity, uint64_t *size, uint64_t *linesize) 7211ae08745Sheppo { 7221ae08745Sheppo mde_cookie_t *cachelist; 7231ae08745Sheppo int ncaches, i; 7241ae08745Sheppo uint64_t max_level; 7251ae08745Sheppo 7261ae08745Sheppo ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache", 7271ae08745Sheppo "fwd", &cachelist); 7281ae08745Sheppo /* 7291ae08745Sheppo * The "cache" node is optional in MD, therefore ncaches can be 0. 7301ae08745Sheppo */ 7311ae08745Sheppo if (ncaches < 1) { 7321ae08745Sheppo return (0); 7331ae08745Sheppo } 7341ae08745Sheppo 7351ae08745Sheppo max_level = 0; 7361ae08745Sheppo for (i = 0; i < ncaches; i++) { 7371ae08745Sheppo uint64_t cache_level; 7381ae08745Sheppo uint64_t local_assoc; 7391ae08745Sheppo uint64_t local_size; 7401ae08745Sheppo uint64_t local_lsize; 7411ae08745Sheppo 7421ae08745Sheppo if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 7431ae08745Sheppo continue; 7441ae08745Sheppo 7451ae08745Sheppo if (cache_level <= max_level) continue; 7461ae08745Sheppo 7471ae08745Sheppo /* If properties are missing from this cache ignore it */ 7481ae08745Sheppo 7491ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 7501ae08745Sheppo "associativity", &local_assoc))) { 7511ae08745Sheppo continue; 7521ae08745Sheppo } 7531ae08745Sheppo 7541ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 7551ae08745Sheppo "size", &local_size))) { 7561ae08745Sheppo continue; 7571ae08745Sheppo } 7581ae08745Sheppo 7591ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 7601ae08745Sheppo "line-size", &local_lsize))) { 7611ae08745Sheppo continue; 7621ae08745Sheppo } 7631ae08745Sheppo 7641ae08745Sheppo max_level = cache_level; 7651ae08745Sheppo *associativity = local_assoc; 7661ae08745Sheppo *size = local_size; 7671ae08745Sheppo *linesize = local_lsize; 7681ae08745Sheppo } 7697c478bd9Sstevel@tonic-gate 7701ae08745Sheppo md_free_scan_dag(mdp, &cachelist); 7711ae08745Sheppo 7721ae08745Sheppo return ((max_level > 0) ? 1 : 0); 7731ae08745Sheppo } 7741ae08745Sheppo 7754bac2208Snarayan 7761ae08745Sheppo /* 7774bac2208Snarayan * Set the broken_md_flag to 1 if the MD doesn't have 7784bac2208Snarayan * the domaining-enabled property in the platform node and the 7794bac2208Snarayan * platform uses the UltraSPARC-T1 cpu. This flag is used to 7804bac2208Snarayan * workaround some of the incorrect MD properties. 7811ae08745Sheppo */ 7821ae08745Sheppo static void 7834bac2208Snarayan init_md_broken(md_t *mdp, mde_cookie_t *cpulist) 7847c478bd9Sstevel@tonic-gate { 7851ae08745Sheppo int nrnode; 7861ae08745Sheppo mde_cookie_t *platlist, rootnode; 7871ae08745Sheppo uint64_t val = 0; 7884bac2208Snarayan char *namebuf; 7894bac2208Snarayan int namelen; 7901ae08745Sheppo 7911ae08745Sheppo rootnode = md_root_node(mdp); 7921ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 7934bac2208Snarayan ASSERT(cpulist); 7941ae08745Sheppo 7954bac2208Snarayan nrnode = md_alloc_scan_dag(mdp, rootnode, "platform", "fwd", 7961ae08745Sheppo &platlist); 7971ae08745Sheppo 798f273041fSjm if (nrnode < 1) 799f273041fSjm cmn_err(CE_PANIC, "init_md_broken: platform node missing"); 8001ae08745Sheppo 8014bac2208Snarayan if (md_get_prop_data(mdp, cpulist[0], 8024bac2208Snarayan "compatible", (uint8_t **)&namebuf, &namelen)) { 8034bac2208Snarayan cmn_err(CE_PANIC, "init_md_broken: " 8044bac2208Snarayan "Cannot read 'compatible' property of 'cpu' node"); 8054bac2208Snarayan } 8067c478bd9Sstevel@tonic-gate 8074bac2208Snarayan if (md_get_prop_val(mdp, platlist[0], 8084bac2208Snarayan "domaining-enabled", &val) == -1 && 8094bac2208Snarayan strcmp(namebuf, "SUNW,UltraSPARC-T1") == 0) 8101ae08745Sheppo broken_md_flag = 1; 8111ae08745Sheppo 8121ae08745Sheppo md_free_scan_dag(mdp, &platlist); 8137c478bd9Sstevel@tonic-gate } 814