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 /* 2294c894bbSVikram Hegde * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #include <sys/errno.h> 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/param.h> 287c478bd9Sstevel@tonic-gate #include <sys/cpu.h> 297c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 307c478bd9Sstevel@tonic-gate #include <sys/clock.h> 317c478bd9Sstevel@tonic-gate #include <sys/promif.h> 327c478bd9Sstevel@tonic-gate #include <sys/promimpl.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 347c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 357c478bd9Sstevel@tonic-gate #include <sys/debug.h> 367c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 377c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 387c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 397c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 407c478bd9Sstevel@tonic-gate #include <sys/cmp.h> 417c478bd9Sstevel@tonic-gate #include <sys/async.h> 427c478bd9Sstevel@tonic-gate #include <vm/page.h> 431ae08745Sheppo #include <vm/hat_sfmmu.h> 441ae08745Sheppo #include <sys/sysmacros.h> 451ae08745Sheppo #include <sys/mach_descrip.h> 461ae08745Sheppo #include <sys/mdesc.h> 471ae08745Sheppo #include <sys/archsystm.h> 481ae08745Sheppo #include <sys/error.h> 491ae08745Sheppo #include <sys/mmu.h> 501ae08745Sheppo #include <sys/bitmap.h> 514bac2208Snarayan #include <sys/intreg.h> 5294c894bbSVikram Hegde #include <sys/instance.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate struct cpu_node cpunodes[NCPU]; 557c478bd9Sstevel@tonic-gate 561ae08745Sheppo uint64_t cpu_q_entries; 571ae08745Sheppo uint64_t dev_q_entries; 581ae08745Sheppo uint64_t cpu_rq_entries; 591ae08745Sheppo uint64_t cpu_nrq_entries; 60aaa10e67Sha137994 uint64_t ncpu_guest_max; 611ae08745Sheppo 621ae08745Sheppo void fill_cpu(md_t *, mde_cookie_t); 631ae08745Sheppo 641ae08745Sheppo static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t); 6505d3dc4bSpaulsan static uint64_t get_mmu_tsbs(md_t *, mde_cookie_t); 6605d3dc4bSpaulsan static uint64_t get_mmu_shcontexts(md_t *, mde_cookie_t); 671ae08745Sheppo static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t); 681ae08745Sheppo static char *construct_isalist(md_t *, mde_cookie_t, char **); 694bac2208Snarayan static void init_md_broken(md_t *, mde_cookie_t *); 701ae08745Sheppo static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *, 711ae08745Sheppo uint64_t *); 722f0fcb93SJason Beloro static void get_hwcaps(md_t *, mde_cookie_t); 732c5124a1SPrashanth Sreenivasa static void get_weakest_mem_model(md_t *, mde_cookie_t); 741ae08745Sheppo static void get_q_sizes(md_t *, mde_cookie_t); 751ae08745Sheppo static void get_va_bits(md_t *, mde_cookie_t); 769853d9e8SJason Beloro static size_t get_ra_limit(md_t *, mde_cookie_t); 77575a7426Spt157919 static int get_l2_cache_node_count(md_t *); 782f0fcb93SJason Beloro static unsigned long names2bits(char *tokens, size_t tokenslen, 792f0fcb93SJason Beloro char *bit_formatter, char *warning); 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate uint64_t system_clock_freq; 827c478bd9Sstevel@tonic-gate uint_t niommu_tsbs = 0; 837c478bd9Sstevel@tonic-gate 84575a7426Spt157919 static int n_l2_caches = 0; 85575a7426Spt157919 86fedab560Sae112802 /* prevent compilation with VAC defined */ 87fedab560Sae112802 #ifdef VAC 88fedab560Sae112802 #error "The sun4v architecture does not support VAC" 89fedab560Sae112802 #endif 90fedab560Sae112802 91fedab560Sae112802 #define S_VAC_SIZE MMU_PAGESIZE 92fedab560Sae112802 #define S_VAC_SHIFT MMU_PAGESHIFT 93fedab560Sae112802 94fedab560Sae112802 int vac_size = S_VAC_SIZE; 95fedab560Sae112802 uint_t vac_mask = MMU_PAGEMASK & (S_VAC_SIZE - 1); 96fedab560Sae112802 int vac_shift = S_VAC_SHIFT; 97fedab560Sae112802 uintptr_t shm_alignment = S_VAC_SIZE; 98fedab560Sae112802 997c478bd9Sstevel@tonic-gate void 1007c478bd9Sstevel@tonic-gate map_wellknown_devices() 1017c478bd9Sstevel@tonic-gate { 1021ae08745Sheppo } 1031ae08745Sheppo 1047c478bd9Sstevel@tonic-gate void 1051ae08745Sheppo fill_cpu(md_t *mdp, mde_cookie_t cpuc) 1067c478bd9Sstevel@tonic-gate { 1077c478bd9Sstevel@tonic-gate struct cpu_node *cpunode; 1081ae08745Sheppo uint64_t cpuid; 1091ae08745Sheppo uint64_t clk_freq; 1101ae08745Sheppo char *namebuf; 1117c478bd9Sstevel@tonic-gate char *namebufp; 1121ae08745Sheppo int namelen; 1131ae08745Sheppo uint64_t associativity = 0, linesize = 0, size = 0; 1147c478bd9Sstevel@tonic-gate 1151ae08745Sheppo if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) { 1161ae08745Sheppo return; 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate 1194bac2208Snarayan /* All out-of-range cpus will be stopped later. */ 1201ae08745Sheppo if (cpuid >= NCPU) { 1211ae08745Sheppo cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - " 1224bac2208Snarayan "cpu excluded from configuration\n", cpuid); 1231ae08745Sheppo 1247c478bd9Sstevel@tonic-gate return; 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate cpunode = &cpunodes[cpuid]; 1281ae08745Sheppo cpunode->cpuid = (int)cpuid; 1297c478bd9Sstevel@tonic-gate cpunode->device_id = cpuid; 1307c478bd9Sstevel@tonic-gate 1311ae08745Sheppo if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI)) 1321ae08745Sheppo (void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI); 1331ae08745Sheppo 1341ae08745Sheppo if (md_get_prop_data(mdp, cpuc, 1351ae08745Sheppo "compatible", (uint8_t **)&namebuf, &namelen)) { 1361ae08745Sheppo cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible " 1371ae08745Sheppo "property"); 1381ae08745Sheppo } 1397c478bd9Sstevel@tonic-gate namebufp = namebuf; 1407c478bd9Sstevel@tonic-gate if (strncmp(namebufp, "SUNW,", 5) == 0) 1417c478bd9Sstevel@tonic-gate namebufp += 5; 1421ae08745Sheppo if (strlen(namebufp) > sizeof (cpunode->name)) 1431ae08745Sheppo cmn_err(CE_PANIC, "Compatible property too big to " 1441ae08745Sheppo "fit into the cpunode name buffer"); 1457c478bd9Sstevel@tonic-gate (void) strcpy(cpunode->name, namebufp); 1467c478bd9Sstevel@tonic-gate 1471ae08745Sheppo if (md_get_prop_val(mdp, cpuc, 1481ae08745Sheppo "clock-frequency", &clk_freq)) { 1497c478bd9Sstevel@tonic-gate clk_freq = 0; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate cpunode->clock_freq = clk_freq; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate ASSERT(cpunode->clock_freq != 0); 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * Compute scaling factor based on rate of %tick. This is used 1567c478bd9Sstevel@tonic-gate * to convert from ticks derived from %tick to nanoseconds. See 1577c478bd9Sstevel@tonic-gate * comment in sun4u/sys/clock.h for details. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 1607c478bd9Sstevel@tonic-gate (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 1617c478bd9Sstevel@tonic-gate 1621ae08745Sheppo /* 1631ae08745Sheppo * The nodeid is not used in sun4v at all. Setting it 1641ae08745Sheppo * to positive value to make starting of slave CPUs 1651ae08745Sheppo * code happy. 1661ae08745Sheppo */ 1671ae08745Sheppo cpunode->nodeid = cpuid + 1; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1701ae08745Sheppo * Obtain the L2 cache information from MD. 1711ae08745Sheppo * If "Cache" node exists, then set L2 cache properties 1721ae08745Sheppo * as read from MD. 1731ae08745Sheppo * If node does not exists, then set the L2 cache properties 1741ae08745Sheppo * in individual CPU module. 1757c478bd9Sstevel@tonic-gate */ 1761ae08745Sheppo if ((!get_l2_cache_info(mdp, cpuc, 1771ae08745Sheppo &associativity, &size, &linesize)) || 1781ae08745Sheppo associativity == 0 || size == 0 || linesize == 0) { 1797c478bd9Sstevel@tonic-gate cpu_fiximp(cpunode); 1801ae08745Sheppo } else { 1811ae08745Sheppo /* 1821ae08745Sheppo * Do not expect L2 cache properties to be bigger 1831ae08745Sheppo * than 32-bit quantity. 1841ae08745Sheppo */ 1851ae08745Sheppo cpunode->ecache_associativity = (int)associativity; 1861ae08745Sheppo cpunode->ecache_size = (int)size; 1871ae08745Sheppo cpunode->ecache_linesize = (int)linesize; 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1901ae08745Sheppo cpunode->ecache_setsize = 1911ae08745Sheppo cpunode->ecache_size / cpunode->ecache_associativity; 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate /* 19459ac0c16Sdavemq * Initialize the mapping for exec unit, chip and core. 1951ae08745Sheppo */ 1961ae08745Sheppo cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND; 19759ac0c16Sdavemq cpunode->l2_cache_mapping = NO_MAPPING_FOUND; 19859ac0c16Sdavemq cpunode->core_mapping = NO_CORE_MAPPING_FOUND; 1991ae08745Sheppo 2001ae08745Sheppo if (ecache_setsize == 0) 2011ae08745Sheppo ecache_setsize = cpunode->ecache_setsize; 2021ae08745Sheppo if (ecache_alignsize == 0) 2031ae08745Sheppo ecache_alignsize = cpunode->ecache_linesize; 2041ae08745Sheppo 2051ae08745Sheppo } 2061ae08745Sheppo 2071ae08745Sheppo void 2081ae08745Sheppo empty_cpu(int cpuid) 2091ae08745Sheppo { 2101ae08745Sheppo bzero(&cpunodes[cpuid], sizeof (struct cpu_node)); 2111ae08745Sheppo } 2121ae08745Sheppo 21359ac0c16Sdavemq /* 21459ac0c16Sdavemq * Use L2 cache node to derive the chip mapping. 21559ac0c16Sdavemq */ 21659ac0c16Sdavemq void 21759ac0c16Sdavemq setup_chip_mappings(md_t *mdp) 21859ac0c16Sdavemq { 2192f0fcb93SJason Beloro int ncache, ncpu; 22059ac0c16Sdavemq mde_cookie_t *node, *cachelist; 22159ac0c16Sdavemq int i, j; 22259ac0c16Sdavemq processorid_t cpuid; 22359ac0c16Sdavemq int idx = 0; 22459ac0c16Sdavemq 22559ac0c16Sdavemq ncache = md_alloc_scan_dag(mdp, md_root_node(mdp), "cache", 22659ac0c16Sdavemq "fwd", &cachelist); 22759ac0c16Sdavemq 22859ac0c16Sdavemq /* 22959ac0c16Sdavemq * The "cache" node is optional in MD, therefore ncaches can be 0. 23059ac0c16Sdavemq */ 23159ac0c16Sdavemq if (ncache < 1) { 23259ac0c16Sdavemq return; 23359ac0c16Sdavemq } 23459ac0c16Sdavemq 23559ac0c16Sdavemq for (i = 0; i < ncache; i++) { 23659ac0c16Sdavemq uint64_t cache_level; 23759ac0c16Sdavemq uint64_t lcpuid; 23859ac0c16Sdavemq 23959ac0c16Sdavemq if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 24059ac0c16Sdavemq continue; 24159ac0c16Sdavemq 24259ac0c16Sdavemq if (cache_level != 2) 24359ac0c16Sdavemq continue; 24459ac0c16Sdavemq 24559ac0c16Sdavemq /* 24659ac0c16Sdavemq * Found a l2 cache node. Find out the cpu nodes it 24759ac0c16Sdavemq * points to. 24859ac0c16Sdavemq */ 24959ac0c16Sdavemq ncpu = md_alloc_scan_dag(mdp, cachelist[i], "cpu", 25059ac0c16Sdavemq "back", &node); 25159ac0c16Sdavemq 25259ac0c16Sdavemq if (ncpu < 1) 25359ac0c16Sdavemq continue; 25459ac0c16Sdavemq 25559ac0c16Sdavemq for (j = 0; j < ncpu; j++) { 25659ac0c16Sdavemq if (md_get_prop_val(mdp, node[j], "id", &lcpuid)) 25759ac0c16Sdavemq continue; 25859ac0c16Sdavemq if (lcpuid >= NCPU) 25959ac0c16Sdavemq continue; 26059ac0c16Sdavemq cpuid = (processorid_t)lcpuid; 26159ac0c16Sdavemq cpunodes[cpuid].l2_cache_mapping = idx; 26259ac0c16Sdavemq } 26359ac0c16Sdavemq md_free_scan_dag(mdp, &node); 26459ac0c16Sdavemq 26559ac0c16Sdavemq idx++; 26659ac0c16Sdavemq } 26759ac0c16Sdavemq 26859ac0c16Sdavemq md_free_scan_dag(mdp, &cachelist); 26959ac0c16Sdavemq } 27059ac0c16Sdavemq 2711ae08745Sheppo void 2721ae08745Sheppo setup_exec_unit_mappings(md_t *mdp) 2731ae08745Sheppo { 2742f0fcb93SJason Beloro int num, num_eunits; 2751ae08745Sheppo mde_cookie_t cpus_node; 2761ae08745Sheppo mde_cookie_t *node, *eunit; 2771ae08745Sheppo int idx, i, j; 2781ae08745Sheppo processorid_t cpuid; 2791ae08745Sheppo char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit"; 280fb2f18f8Sesaxe enum eu_type { INTEGER, FPU } etype; 2811ae08745Sheppo 2821ae08745Sheppo /* 2831ae08745Sheppo * Find the cpu integer exec units - and 2841ae08745Sheppo * setup the mappings appropriately. 2851ae08745Sheppo */ 2861ae08745Sheppo num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node); 2871ae08745Sheppo if (num < 1) 2884bac2208Snarayan cmn_err(CE_PANIC, "No cpus node in machine description"); 2891ae08745Sheppo if (num > 1) 2901ae08745Sheppo cmn_err(CE_PANIC, "More than 1 cpus node in machine" 2911ae08745Sheppo " description"); 2921ae08745Sheppo 2931ae08745Sheppo cpus_node = node[0]; 2941ae08745Sheppo md_free_scan_dag(mdp, &node); 2951ae08745Sheppo 2961ae08745Sheppo num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name, 2971ae08745Sheppo "fwd", &eunit); 2981ae08745Sheppo if (num_eunits > 0) { 299fb2f18f8Sesaxe char *int_str = broken_md_flag ? "int" : "integer"; 300fb2f18f8Sesaxe char *fpu_str = "fp"; 3011ae08745Sheppo 3021ae08745Sheppo /* Spin through and find all the integer exec units */ 3031ae08745Sheppo for (i = 0; i < num_eunits; i++) { 3041ae08745Sheppo char *p; 3051ae08745Sheppo char *val; 3061ae08745Sheppo int vallen; 3071ae08745Sheppo uint64_t lcpuid; 3081ae08745Sheppo 3091ae08745Sheppo /* ignore nodes with no type */ 3101ae08745Sheppo if (md_get_prop_data(mdp, eunit[i], "type", 311ad8d2eb8Szx151605 (uint8_t **)&val, &vallen)) 312ad8d2eb8Szx151605 continue; 3131ae08745Sheppo 3141ae08745Sheppo for (p = val; *p != '\0'; p += strlen(p) + 1) { 315fb2f18f8Sesaxe if (strcmp(p, int_str) == 0) { 316fb2f18f8Sesaxe etype = INTEGER; 3171ae08745Sheppo goto found; 3181ae08745Sheppo } 319fb2f18f8Sesaxe if (strcmp(p, fpu_str) == 0) { 320fb2f18f8Sesaxe etype = FPU; 321fb2f18f8Sesaxe goto found; 322fb2f18f8Sesaxe } 323fb2f18f8Sesaxe } 3241ae08745Sheppo 3251ae08745Sheppo continue; 3261ae08745Sheppo found: 3271ae08745Sheppo idx = NCPU + i; 3281ae08745Sheppo /* 3291ae08745Sheppo * find the cpus attached to this EU and 3301ae08745Sheppo * update their mapping indices 3311ae08745Sheppo */ 3321ae08745Sheppo num = md_alloc_scan_dag(mdp, eunit[i], "cpu", 3331ae08745Sheppo "back", &node); 3341ae08745Sheppo 3351ae08745Sheppo if (num < 1) 3361ae08745Sheppo cmn_err(CE_PANIC, "exec-unit node in MD" 3371ae08745Sheppo " not attached to a cpu node"); 3381ae08745Sheppo 3391ae08745Sheppo for (j = 0; j < num; j++) { 3401ae08745Sheppo if (md_get_prop_val(mdp, node[j], "id", 3411ae08745Sheppo &lcpuid)) 3421ae08745Sheppo continue; 3431ae08745Sheppo if (lcpuid >= NCPU) 3441ae08745Sheppo continue; 3451ae08745Sheppo cpuid = (processorid_t)lcpuid; 346fb2f18f8Sesaxe switch (etype) { 347fb2f18f8Sesaxe case INTEGER: 3481ae08745Sheppo cpunodes[cpuid].exec_unit_mapping = idx; 349fb2f18f8Sesaxe break; 350fb2f18f8Sesaxe case FPU: 351fb2f18f8Sesaxe cpunodes[cpuid].fpu_mapping = idx; 352fb2f18f8Sesaxe break; 353fb2f18f8Sesaxe } 3541ae08745Sheppo } 3551ae08745Sheppo md_free_scan_dag(mdp, &node); 3561ae08745Sheppo } 3579d0d62adSJason Beloro 3589d0d62adSJason Beloro 3591ae08745Sheppo md_free_scan_dag(mdp, &eunit); 3601ae08745Sheppo } 3611ae08745Sheppo } 3621ae08745Sheppo 3631ae08745Sheppo /* 3641ae08745Sheppo * All the common setup of sun4v CPU modules is done by this routine. 3651ae08745Sheppo */ 3661ae08745Sheppo void 3671ae08745Sheppo cpu_setup_common(char **cpu_module_isa_set) 3681ae08745Sheppo { 3691ae08745Sheppo extern int mmu_exported_pagesize_mask; 3701ae08745Sheppo int nocpus, i; 3711ae08745Sheppo size_t ra_limit; 3721ae08745Sheppo mde_cookie_t *cpulist; 3731ae08745Sheppo md_t *mdp; 3741ae08745Sheppo 3751ae08745Sheppo if ((mdp = md_get_handle()) == NULL) 3761ae08745Sheppo cmn_err(CE_PANIC, "Unable to initialize machine description"); 3771ae08745Sheppo 37806fb6a36Sdv142724 boot_ncpus = nocpus = md_alloc_scan_dag(mdp, 3791ae08745Sheppo md_root_node(mdp), "cpu", "fwd", &cpulist); 3801ae08745Sheppo if (nocpus < 1) { 3811ae08745Sheppo cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation " 3821ae08745Sheppo "failed or incorrect number of CPUs in MD"); 3831ae08745Sheppo } 3841ae08745Sheppo 3854bac2208Snarayan init_md_broken(mdp, cpulist); 3864bac2208Snarayan 3871ae08745Sheppo if (use_page_coloring) { 3881ae08745Sheppo do_pg_coloring = 1; 3891ae08745Sheppo } 3901ae08745Sheppo 3911ae08745Sheppo /* 3921e2e7a75Shuah * Get the valid mmu page sizes mask, Q sizes and isalist/r 3931ae08745Sheppo * from the MD for the first available CPU in cpulist. 3941e2e7a75Shuah * 3951e2e7a75Shuah * Do not expect the MMU page sizes mask to be more than 32-bit. 3961ae08745Sheppo */ 3971ae08745Sheppo mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]); 3981ae08745Sheppo 39905d3dc4bSpaulsan /* 40005d3dc4bSpaulsan * Get the number of contexts and tsbs supported. 40105d3dc4bSpaulsan */ 40205d3dc4bSpaulsan if (get_mmu_shcontexts(mdp, cpulist[0]) >= MIN_NSHCONTEXTS && 40305d3dc4bSpaulsan get_mmu_tsbs(mdp, cpulist[0]) >= MIN_NTSBS) { 40405d3dc4bSpaulsan shctx_on = 1; 40505d3dc4bSpaulsan } 40605d3dc4bSpaulsan 4071ae08745Sheppo for (i = 0; i < nocpus; i++) 4081ae08745Sheppo fill_cpu(mdp, cpulist[i]); 4091ae08745Sheppo 410575a7426Spt157919 /* setup l2 cache count. */ 411575a7426Spt157919 n_l2_caches = get_l2_cache_node_count(mdp); 412575a7426Spt157919 41359ac0c16Sdavemq setup_chip_mappings(mdp); 4141ae08745Sheppo setup_exec_unit_mappings(mdp); 4151ae08745Sheppo 4161ae08745Sheppo /* 4171ae08745Sheppo * If MD is broken then append the passed ISA set, 4181ae08745Sheppo * otherwise trust the MD. 4191ae08745Sheppo */ 4201ae08745Sheppo 4211ae08745Sheppo if (broken_md_flag) 4221ae08745Sheppo isa_list = construct_isalist(mdp, cpulist[0], 4231ae08745Sheppo cpu_module_isa_set); 4241ae08745Sheppo else 4251ae08745Sheppo isa_list = construct_isalist(mdp, cpulist[0], NULL); 4261ae08745Sheppo 4272f0fcb93SJason Beloro get_hwcaps(mdp, cpulist[0]); 4282c5124a1SPrashanth Sreenivasa get_weakest_mem_model(mdp, cpulist[0]); 4291ae08745Sheppo get_q_sizes(mdp, cpulist[0]); 4301ae08745Sheppo get_va_bits(mdp, cpulist[0]); 4311ae08745Sheppo 4321ae08745Sheppo /* 4331ae08745Sheppo * ra_limit is the highest real address in the machine. 4341ae08745Sheppo */ 4359853d9e8SJason Beloro ra_limit = get_ra_limit(mdp, cpulist[0]); 4361ae08745Sheppo 4371ae08745Sheppo md_free_scan_dag(mdp, &cpulist); 4381ae08745Sheppo 4391ae08745Sheppo (void) md_fini_handle(mdp); 4401ae08745Sheppo 4411ae08745Sheppo /* 4421ae08745Sheppo * Block stores invalidate all pages of the d$ so pagecopy 4431ae08745Sheppo * et. al. do not need virtual translations with virtual 4441ae08745Sheppo * coloring taken into consideration. 4451ae08745Sheppo */ 4461ae08745Sheppo pp_consistent_coloring = 0; 4471ae08745Sheppo 4481ae08745Sheppo /* 4491ae08745Sheppo * The kpm mapping window. 4501ae08745Sheppo * kpm_size: 4511ae08745Sheppo * The size of a single kpm range. 4521ae08745Sheppo * The overall size will be: kpm_size * vac_colors. 4531ae08745Sheppo * kpm_vbase: 4541ae08745Sheppo * The virtual start address of the kpm range within the kernel 4551ae08745Sheppo * virtual address space. kpm_vbase has to be kpm_size aligned. 4561ae08745Sheppo */ 4571ae08745Sheppo 4581ae08745Sheppo /* 4591ae08745Sheppo * Make kpm_vbase, kpm_size aligned to kpm_size_shift. 4601ae08745Sheppo * To do this find the nearest power of 2 size that the 4611ae08745Sheppo * actual ra_limit fits within. 4621ae08745Sheppo * If it is an even power of two use that, otherwise use the 4631ae08745Sheppo * next power of two larger than ra_limit. 4641ae08745Sheppo */ 4651ae08745Sheppo 4661ae08745Sheppo ASSERT(ra_limit != 0); 4671ae08745Sheppo 468*de710d24SJosef 'Jeff' Sipek kpm_size_shift = !ISP2(ra_limit) ? 4691ae08745Sheppo highbit(ra_limit) : highbit(ra_limit) - 1; 4701ae08745Sheppo 4711ae08745Sheppo /* 4721ae08745Sheppo * No virtual caches on sun4v so size matches size shift 4731ae08745Sheppo */ 4741ae08745Sheppo kpm_size = 1ul << kpm_size_shift; 4751ae08745Sheppo 4761ae08745Sheppo if (va_bits < VA_ADDRESS_SPACE_BITS) { 4771ae08745Sheppo /* 4781ae08745Sheppo * In case of VA hole 4791ae08745Sheppo * kpm_base = hole_end + 1TB 4801ae08745Sheppo * Starting 1TB beyond where VA hole ends because on Niagara 4811ae08745Sheppo * processor software must not use pages within 4GB of the 4821ae08745Sheppo * VA hole as instruction pages to avoid problems with 4831ae08745Sheppo * prefetching into the VA hole. 4841ae08745Sheppo */ 4851ae08745Sheppo kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) + 4861ae08745Sheppo (1ull << 40)); 4871ae08745Sheppo } else { /* Number of VA bits 64 ... no VA hole */ 4881ae08745Sheppo kpm_vbase = (caddr_t)0x8000000000000000ull; /* 8 EB */ 4891ae08745Sheppo } 4901ae08745Sheppo 4911ae08745Sheppo /* 4921ae08745Sheppo * The traptrace code uses either %tick or %stick for 4931ae08745Sheppo * timestamping. The sun4v require use of %stick. 4941ae08745Sheppo */ 4951ae08745Sheppo traptrace_use_stick = 1; 4961ae08745Sheppo } 4971ae08745Sheppo 4981ae08745Sheppo /* 4991ae08745Sheppo * Get the nctxs from MD. If absent panic. 5001ae08745Sheppo */ 5011ae08745Sheppo static uint64_t 5021ae08745Sheppo get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 5031ae08745Sheppo { 5041ae08745Sheppo uint64_t ctx_bits; 5051ae08745Sheppo 5061ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits", 5071ae08745Sheppo &ctx_bits)) 5081ae08745Sheppo ctx_bits = 0; 5091ae08745Sheppo 5101ae08745Sheppo if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS) 5111ae08745Sheppo cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits " 5121ae08745Sheppo "returned by MD", ctx_bits); 5131ae08745Sheppo 5141ae08745Sheppo return (ctx_bits); 5151ae08745Sheppo } 5161ae08745Sheppo 5171ae08745Sheppo /* 51805d3dc4bSpaulsan * Get the number of tsbs from MD. If absent the default value is 0. 51905d3dc4bSpaulsan */ 52005d3dc4bSpaulsan static uint64_t 52105d3dc4bSpaulsan get_mmu_tsbs(md_t *mdp, mde_cookie_t cpu_node_cookie) 52205d3dc4bSpaulsan { 52305d3dc4bSpaulsan uint64_t number_tsbs; 52405d3dc4bSpaulsan 52505d3dc4bSpaulsan if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-max-#tsbs", 52605d3dc4bSpaulsan &number_tsbs)) 52705d3dc4bSpaulsan number_tsbs = 0; 52805d3dc4bSpaulsan 52905d3dc4bSpaulsan return (number_tsbs); 53005d3dc4bSpaulsan } 53105d3dc4bSpaulsan 53205d3dc4bSpaulsan /* 5337dacfc44Spaulsan * Get the number of shared contexts from MD. If absent the default value is 0. 53405d3dc4bSpaulsan * 53505d3dc4bSpaulsan */ 53605d3dc4bSpaulsan static uint64_t 53705d3dc4bSpaulsan get_mmu_shcontexts(md_t *mdp, mde_cookie_t cpu_node_cookie) 53805d3dc4bSpaulsan { 53905d3dc4bSpaulsan uint64_t number_contexts; 54005d3dc4bSpaulsan 54105d3dc4bSpaulsan if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#shared-contexts", 54205d3dc4bSpaulsan &number_contexts)) 54305d3dc4bSpaulsan number_contexts = 0; 54405d3dc4bSpaulsan 54505d3dc4bSpaulsan return (number_contexts); 54605d3dc4bSpaulsan } 54705d3dc4bSpaulsan 54805d3dc4bSpaulsan /* 5491ae08745Sheppo * Initalize supported page sizes information. 5501ae08745Sheppo * Set to 0, if the page sizes mask information is absent in MD. 5511ae08745Sheppo */ 5521ae08745Sheppo static uint64_t 5531ae08745Sheppo get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 5541ae08745Sheppo { 5551ae08745Sheppo uint64_t mmu_page_size_list; 5561ae08745Sheppo 5571ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list", 5581ae08745Sheppo &mmu_page_size_list)) 5591ae08745Sheppo mmu_page_size_list = 0; 5601ae08745Sheppo 5611ae08745Sheppo if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK) 5621ae08745Sheppo cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned" 5631ae08745Sheppo "by MD", mmu_page_size_list); 5641ae08745Sheppo 5651ae08745Sheppo return (mmu_page_size_list); 5661ae08745Sheppo } 5671ae08745Sheppo 5681ae08745Sheppo /* 5691ae08745Sheppo * This routine gets the isalist information from MD and appends 5701ae08745Sheppo * the CPU module ISA set if required. 5711ae08745Sheppo */ 5721ae08745Sheppo static char * 5731ae08745Sheppo construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie, 5741ae08745Sheppo char **cpu_module_isa_set) 5751ae08745Sheppo { 5761ae08745Sheppo extern int at_flags; 5771ae08745Sheppo char *md_isalist; 5781ae08745Sheppo int md_isalen; 5791ae08745Sheppo char *isabuf; 5801ae08745Sheppo int isalen; 5811ae08745Sheppo char **isa_set; 5821ae08745Sheppo char *p, *q; 5831ae08745Sheppo int cpu_module_isalen = 0, found = 0; 5841ae08745Sheppo 5851ae08745Sheppo (void) md_get_prop_data(mdp, cpu_node_cookie, 5861ae08745Sheppo "isalist", (uint8_t **)&isabuf, &isalen); 5871ae08745Sheppo 5881ae08745Sheppo /* 5891ae08745Sheppo * We support binaries for all the cpus that have shipped so far. 5901ae08745Sheppo * The kernel emulates instructions that are not supported by hardware. 5911ae08745Sheppo */ 5921ae08745Sheppo at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1; 5931ae08745Sheppo 5941ae08745Sheppo /* 5951ae08745Sheppo * Construct the space separated isa_list. 5961ae08745Sheppo */ 5971ae08745Sheppo if (cpu_module_isa_set != NULL) { 5981ae08745Sheppo for (isa_set = cpu_module_isa_set; *isa_set != NULL; 5991ae08745Sheppo isa_set++) { 6001ae08745Sheppo cpu_module_isalen += strlen(*isa_set); 6011ae08745Sheppo cpu_module_isalen++; /* for space character */ 6021ae08745Sheppo } 6031ae08745Sheppo } 6041ae08745Sheppo 6051ae08745Sheppo /* 6061ae08745Sheppo * Allocate the buffer of MD isa buffer length + CPU module 6071ae08745Sheppo * isa buffer length. 6081ae08745Sheppo */ 6091ae08745Sheppo md_isalen = isalen + cpu_module_isalen + 2; 6101ae08745Sheppo md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0); 6111ae08745Sheppo if (md_isalist == NULL) 6121ae08745Sheppo cmn_err(CE_PANIC, "construct_isalist: Allocation failed for " 6131ae08745Sheppo "md_isalist"); 6141ae08745Sheppo 6151ae08745Sheppo md_isalist[0] = '\0'; /* create an empty string to start */ 6161ae08745Sheppo for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) { 6171ae08745Sheppo (void) strlcat(md_isalist, p, md_isalen); 6181ae08745Sheppo (void) strcat(md_isalist, " "); 6191ae08745Sheppo } 6201ae08745Sheppo 6211ae08745Sheppo /* 6221ae08745Sheppo * Check if the isa_set is present in isalist returned by MD. 6231ae08745Sheppo * If yes, then no need to append it, if no then append it to 6241ae08745Sheppo * isalist returned by MD. 6251ae08745Sheppo */ 6261ae08745Sheppo if (cpu_module_isa_set != NULL) { 6271ae08745Sheppo for (isa_set = cpu_module_isa_set; *isa_set != NULL; 6281ae08745Sheppo isa_set++) { 6291ae08745Sheppo found = 0; 6301ae08745Sheppo for (p = isabuf, q = p + isalen; p < q; 6311ae08745Sheppo p += strlen(p) + 1) { 6321ae08745Sheppo if (strcmp(p, *isa_set) == 0) { 6331ae08745Sheppo found = 1; 6341ae08745Sheppo break; 6351ae08745Sheppo } 6361ae08745Sheppo } 6371ae08745Sheppo if (!found) { 6381ae08745Sheppo (void) strlcat(md_isalist, *isa_set, md_isalen); 6391ae08745Sheppo (void) strcat(md_isalist, " "); 6401ae08745Sheppo } 6411ae08745Sheppo } 6421ae08745Sheppo } 6431ae08745Sheppo 6441ae08745Sheppo /* Get rid of any trailing white spaces */ 6451ae08745Sheppo md_isalist[strlen(md_isalist) - 1] = '\0'; 6461ae08745Sheppo 6471ae08745Sheppo return (md_isalist); 6481ae08745Sheppo } 6491ae08745Sheppo 6502f0fcb93SJason Beloro static void 6512f0fcb93SJason Beloro get_hwcaps(md_t *mdp, mde_cookie_t cpu_node_cookie) 6522f0fcb93SJason Beloro { 6532f0fcb93SJason Beloro char *hwcapbuf; 6542f0fcb93SJason Beloro int hwcaplen; 6552f0fcb93SJason Beloro 6562f0fcb93SJason Beloro if (md_get_prop_data(mdp, cpu_node_cookie, 6572f0fcb93SJason Beloro "hwcap-list", (uint8_t **)&hwcapbuf, &hwcaplen)) { 6582f0fcb93SJason Beloro /* Property not found */ 6592f0fcb93SJason Beloro return; 6602f0fcb93SJason Beloro } 6612f0fcb93SJason Beloro 6622f0fcb93SJason Beloro cpu_hwcap_flags |= names2bits(hwcapbuf, hwcaplen, FMT_AV_SPARC, 6632f0fcb93SJason Beloro "unrecognized token: %s"); 6642f0fcb93SJason Beloro } 6652f0fcb93SJason Beloro 6662c5124a1SPrashanth Sreenivasa static void 6672c5124a1SPrashanth Sreenivasa get_weakest_mem_model(md_t *mdp, mde_cookie_t cpu_node_cookie) 6682c5124a1SPrashanth Sreenivasa { 6692c5124a1SPrashanth Sreenivasa char *mmbuf; 6702c5124a1SPrashanth Sreenivasa int mmlen; 6712c5124a1SPrashanth Sreenivasa uint_t wmm; 6722c5124a1SPrashanth Sreenivasa char *p, *q; 6732c5124a1SPrashanth Sreenivasa 6742c5124a1SPrashanth Sreenivasa if (md_get_prop_data(mdp, cpu_node_cookie, 6752c5124a1SPrashanth Sreenivasa "memory-model-list", (uint8_t **)&mmbuf, &mmlen)) { 6762c5124a1SPrashanth Sreenivasa /* Property not found */ 6772c5124a1SPrashanth Sreenivasa return; 6782c5124a1SPrashanth Sreenivasa } 6792c5124a1SPrashanth Sreenivasa 6802c5124a1SPrashanth Sreenivasa wmm = TSTATE_MM_TSO; 6812c5124a1SPrashanth Sreenivasa for (p = mmbuf, q = p + mmlen; p < q; p += strlen(p) + 1) { 6822c5124a1SPrashanth Sreenivasa if (strcmp(p, "wc") == 0) 6832c5124a1SPrashanth Sreenivasa wmm = TSTATE_MM_WC; 6842c5124a1SPrashanth Sreenivasa } 6852c5124a1SPrashanth Sreenivasa weakest_mem_model = wmm; 6862c5124a1SPrashanth Sreenivasa } 6872f0fcb93SJason Beloro 6882f0fcb93SJason Beloro /* 6892f0fcb93SJason Beloro * Does the opposite of cmn_err(9f) "%b" conversion specification: 6902f0fcb93SJason Beloro * Given a list of strings, converts them to a bit-vector. 6912f0fcb93SJason Beloro * 6922f0fcb93SJason Beloro * tokens - is a buffer of [NUL-terminated] strings. 6932f0fcb93SJason Beloro * tokenslen - length of tokenbuf in bytes. 6942f0fcb93SJason Beloro * bit_formatter - is a %b format string, such as FMT_AV_SPARC 6952f0fcb93SJason Beloro * from /usr/include/sys/auxv_SPARC.h, of the form: 6962f0fcb93SJason Beloro * <base-char>[<bit-char><token-string>]... 6972f0fcb93SJason Beloro * <base-char> is ignored. 6982f0fcb93SJason Beloro * <bit-char> is [1-32], as per cmn_err(9f). 6992f0fcb93SJason Beloro * warning - is a printf-style format string containing "%s", 7002f0fcb93SJason Beloro * which is used to print a warning message when an unrecognized 7012f0fcb93SJason Beloro * token is found. If warning is NULL, no warning is printed. 7022f0fcb93SJason Beloro * Returns a bit-vector corresponding to the specified tokens. 7032f0fcb93SJason Beloro */ 7042f0fcb93SJason Beloro 7052f0fcb93SJason Beloro static unsigned long 7062f0fcb93SJason Beloro names2bits(char *tokens, size_t tokenslen, char *bit_formatter, char *warning) 7072f0fcb93SJason Beloro { 7082f0fcb93SJason Beloro char *cur; 7092f0fcb93SJason Beloro size_t curlen; 7102f0fcb93SJason Beloro unsigned long ul = 0; 7112f0fcb93SJason Beloro char *hit; 7122f0fcb93SJason Beloro char *bs; 7132f0fcb93SJason Beloro 7142f0fcb93SJason Beloro bit_formatter++; /* skip base; not needed for input */ 7152f0fcb93SJason Beloro cur = tokens; 7162f0fcb93SJason Beloro while (tokenslen) { 7172f0fcb93SJason Beloro curlen = strlen(cur); 7182f0fcb93SJason Beloro bs = bit_formatter; 7192f0fcb93SJason Beloro /* 7202f0fcb93SJason Beloro * We need a complicated while loop and the >=32 check, 7212f0fcb93SJason Beloro * instead of a simple "if (strstr())" so that when the 7222f0fcb93SJason Beloro * token is "vis", we don't match on "vis2" (for example). 7232f0fcb93SJason Beloro */ 7242f0fcb93SJason Beloro /* LINTED E_EQUALITY_NOT_ASSIGNMENT */ 7252f0fcb93SJason Beloro while ((hit = strstr(bs, cur)) && 7262f0fcb93SJason Beloro *(hit + curlen) >= 32) { 7272f0fcb93SJason Beloro /* 7282f0fcb93SJason Beloro * We're still in the middle of a word, i.e., not 7292f0fcb93SJason Beloro * pointing at a <bit-char>. So advance ptr 7302f0fcb93SJason Beloro * to ensure forward progress. 7312f0fcb93SJason Beloro */ 7322f0fcb93SJason Beloro bs = hit + curlen + 1; 7332f0fcb93SJason Beloro } 7342f0fcb93SJason Beloro 7352f0fcb93SJason Beloro if (hit != NULL) { 7362f0fcb93SJason Beloro ul |= (1<<(*(hit-1) - 1)); 7372f0fcb93SJason Beloro } else { 7382f0fcb93SJason Beloro /* The token wasn't found in bit_formatter */ 7392f0fcb93SJason Beloro if (warning != NULL) 7402f0fcb93SJason Beloro cmn_err(CE_WARN, warning, cur); 7412f0fcb93SJason Beloro } 7422f0fcb93SJason Beloro tokenslen -= curlen + 1; 7432f0fcb93SJason Beloro cur += curlen + 1; 7442f0fcb93SJason Beloro } 7452f0fcb93SJason Beloro return (ul); 7462f0fcb93SJason Beloro } 7472f0fcb93SJason Beloro 7481ae08745Sheppo uint64_t 7499853d9e8SJason Beloro get_ra_limit(md_t *mdp, mde_cookie_t cpu_node_cookie) 7501ae08745Sheppo { 7519853d9e8SJason Beloro extern int ppvm_enable; 7529853d9e8SJason Beloro extern int meta_alloc_enable; 7531ae08745Sheppo mde_cookie_t *mem_list; 7541ae08745Sheppo mde_cookie_t *mblock_list; 7551ae08745Sheppo int i; 7561ae08745Sheppo int memnodes; 7571ae08745Sheppo int nmblock; 7589853d9e8SJason Beloro uint64_t r; 7591ae08745Sheppo uint64_t base; 7601ae08745Sheppo uint64_t size; 7611ae08745Sheppo uint64_t ra_limit = 0, new_limit = 0; 7621ae08745Sheppo 7639853d9e8SJason Beloro if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#ra-bits", &r) == 0) { 7649853d9e8SJason Beloro if (r == 0 || r > RA_ADDRESS_SPACE_BITS) 7659853d9e8SJason Beloro cmn_err(CE_PANIC, "Incorrect number of ra bits in MD"); 7669853d9e8SJason Beloro else { 7679853d9e8SJason Beloro /* 7689853d9e8SJason Beloro * Enable memory DR and metadata (page_t) 7699853d9e8SJason Beloro * allocation from existing memory. 7709853d9e8SJason Beloro */ 7719853d9e8SJason Beloro ppvm_enable = 1; 7729853d9e8SJason Beloro meta_alloc_enable = 1; 7739853d9e8SJason Beloro return (1ULL << r); 7749853d9e8SJason Beloro } 7759853d9e8SJason Beloro } 7769853d9e8SJason Beloro 7771ae08745Sheppo memnodes = md_alloc_scan_dag(mdp, 7781ae08745Sheppo md_root_node(mdp), "memory", "fwd", &mem_list); 7791ae08745Sheppo 7801ae08745Sheppo ASSERT(memnodes == 1); 7811ae08745Sheppo 7821ae08745Sheppo nmblock = md_alloc_scan_dag(mdp, 7831ae08745Sheppo mem_list[0], "mblock", "fwd", &mblock_list); 7841ae08745Sheppo if (nmblock < 1) 7851ae08745Sheppo cmn_err(CE_PANIC, "cannot find mblock nodes in MD"); 7861ae08745Sheppo 7871ae08745Sheppo for (i = 0; i < nmblock; i++) { 7881ae08745Sheppo if (md_get_prop_val(mdp, mblock_list[i], "base", &base)) 7891ae08745Sheppo cmn_err(CE_PANIC, "base property missing from MD" 7901ae08745Sheppo " mblock node"); 7911ae08745Sheppo if (md_get_prop_val(mdp, mblock_list[i], "size", &size)) 7921ae08745Sheppo cmn_err(CE_PANIC, "size property missing from MD" 7931ae08745Sheppo " mblock node"); 7941ae08745Sheppo 7951ae08745Sheppo ASSERT(size != 0); 7961ae08745Sheppo 7971ae08745Sheppo new_limit = base + size; 7981ae08745Sheppo 7991ae08745Sheppo if (base > new_limit) 8001ae08745Sheppo cmn_err(CE_PANIC, "mblock in MD wrapped around"); 8011ae08745Sheppo 8021ae08745Sheppo if (new_limit > ra_limit) 8031ae08745Sheppo ra_limit = new_limit; 8041ae08745Sheppo } 8051ae08745Sheppo 8061ae08745Sheppo ASSERT(ra_limit != 0); 8071ae08745Sheppo 8081ae08745Sheppo if (ra_limit > MAX_REAL_ADDRESS) { 8091ae08745Sheppo cmn_err(CE_WARN, "Highest real address in MD too large" 8101ae08745Sheppo " clipping to %llx\n", MAX_REAL_ADDRESS); 8111ae08745Sheppo ra_limit = MAX_REAL_ADDRESS; 8121ae08745Sheppo } 8131ae08745Sheppo 8141ae08745Sheppo md_free_scan_dag(mdp, &mblock_list); 8151ae08745Sheppo 8161ae08745Sheppo md_free_scan_dag(mdp, &mem_list); 8171ae08745Sheppo 8181ae08745Sheppo return (ra_limit); 8191ae08745Sheppo } 8201ae08745Sheppo 8211ae08745Sheppo /* 8221ae08745Sheppo * This routine sets the globals for CPU and DEV mondo queue entries and 8231ae08745Sheppo * resumable and non-resumable error queue entries. 8244bac2208Snarayan * 8254bac2208Snarayan * First, look up the number of bits available to pass an entry number. 8264bac2208Snarayan * This can vary by platform and may result in allocating an unreasonably 8274bac2208Snarayan * (or impossibly) large amount of memory for the corresponding table, 828d5e8e65eSdavemq * so we clamp it by 'max_entries'. Finally, since the q size is used when 829d5e8e65eSdavemq * calling contig_mem_alloc(), which expects a power of 2, clamp the q size 830d5e8e65eSdavemq * down to a power of 2. If the prop is missing, use 'default_entries'. 8311ae08745Sheppo */ 8321ae08745Sheppo static uint64_t 8331ae08745Sheppo get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie, 8344bac2208Snarayan char *qnamep, uint64_t default_entries, uint64_t max_entries) 8351ae08745Sheppo { 8361ae08745Sheppo uint64_t entries; 8371ae08745Sheppo 8384bac2208Snarayan if (default_entries > max_entries) 8394bac2208Snarayan cmn_err(CE_CONT, "!get_single_q_size: dflt %ld > " 8404bac2208Snarayan "max %ld for %s\n", default_entries, max_entries, qnamep); 8414bac2208Snarayan 8421ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) { 8431ae08745Sheppo if (!broken_md_flag) 8441ae08745Sheppo cmn_err(CE_PANIC, "Missing %s property in MD cpu node", 8451ae08745Sheppo qnamep); 8461ae08745Sheppo entries = default_entries; 8471ae08745Sheppo } else { 8481ae08745Sheppo entries = 1 << entries; 8491ae08745Sheppo } 8504bac2208Snarayan 8514bac2208Snarayan entries = MIN(entries, max_entries); 852d5e8e65eSdavemq /* If not a power of 2, truncate to a power of 2. */ 853*de710d24SJosef 'Jeff' Sipek if (!ISP2(entries)) { 854d5e8e65eSdavemq entries = 1 << (highbit(entries) - 1); 855d5e8e65eSdavemq } 8564bac2208Snarayan 8571ae08745Sheppo return (entries); 8581ae08745Sheppo } 8591ae08745Sheppo 8604bac2208Snarayan /* Scaling constant used to compute size of cpu mondo queue */ 8614bac2208Snarayan #define CPU_MONDO_Q_MULTIPLIER 8 8621ae08745Sheppo 8631ae08745Sheppo static void 8641ae08745Sheppo get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 8651ae08745Sheppo { 8664bac2208Snarayan uint64_t max_qsize; 8674bac2208Snarayan mde_cookie_t *platlist; 8684bac2208Snarayan int nrnode; 8694bac2208Snarayan 8704bac2208Snarayan /* 8714bac2208Snarayan * Compute the maximum number of entries for the cpu mondo queue. 8724bac2208Snarayan * Use the appropriate property in the platform node, if it is 8734bac2208Snarayan * available. Else, base it on NCPU. 8744bac2208Snarayan */ 8754bac2208Snarayan nrnode = md_alloc_scan_dag(mdp, 8764bac2208Snarayan md_root_node(mdp), "platform", "fwd", &platlist); 8774bac2208Snarayan 8784bac2208Snarayan ASSERT(nrnode == 1); 8794bac2208Snarayan 880aaa10e67Sha137994 ncpu_guest_max = NCPU; 881aaa10e67Sha137994 (void) md_get_prop_val(mdp, platlist[0], "max-cpus", &ncpu_guest_max); 882aaa10e67Sha137994 max_qsize = ncpu_guest_max * CPU_MONDO_Q_MULTIPLIER; 8834bac2208Snarayan 8844bac2208Snarayan md_free_scan_dag(mdp, &platlist); 8854bac2208Snarayan 8861ae08745Sheppo cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie, 8874bac2208Snarayan "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES, max_qsize); 8881ae08745Sheppo 8891ae08745Sheppo dev_q_entries = get_single_q_size(mdp, cpu_node_cookie, 890b0fc0e77Sgovinda "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES, MAXIVNUM); 8911ae08745Sheppo 8921ae08745Sheppo cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie, 8934bac2208Snarayan "q-resumable-#bits", CPU_RQ_ENTRIES, MAX_CPU_RQ_ENTRIES); 8941ae08745Sheppo 8951ae08745Sheppo cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie, 8964bac2208Snarayan "q-nonresumable-#bits", CPU_NRQ_ENTRIES, MAX_CPU_NRQ_ENTRIES); 8971ae08745Sheppo } 8981ae08745Sheppo 8991ae08745Sheppo 9001ae08745Sheppo static void 9011ae08745Sheppo get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 9021ae08745Sheppo { 9031ae08745Sheppo uint64_t value = VA_ADDRESS_SPACE_BITS; 9041ae08745Sheppo 9051ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value)) 9061ae08745Sheppo cmn_err(CE_PANIC, "mmu-#va-bits property not found in MD"); 9071ae08745Sheppo 9081ae08745Sheppo 9091ae08745Sheppo if (value == 0 || value > VA_ADDRESS_SPACE_BITS) 9101ae08745Sheppo cmn_err(CE_PANIC, "Incorrect number of va bits in MD"); 9111ae08745Sheppo 9121ae08745Sheppo /* Do not expect number of VA bits to be more than 32-bit quantity */ 9131ae08745Sheppo 9141ae08745Sheppo va_bits = (int)value; 9151ae08745Sheppo 9161ae08745Sheppo /* 9171ae08745Sheppo * Correct the value for VA bits on UltraSPARC-T1 based systems 9181ae08745Sheppo * in case of broken MD. 9191ae08745Sheppo */ 9201ae08745Sheppo if (broken_md_flag) 9211ae08745Sheppo va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS; 9221ae08745Sheppo } 9231ae08745Sheppo 924575a7426Spt157919 int 925575a7426Spt157919 l2_cache_node_count(void) 926575a7426Spt157919 { 927575a7426Spt157919 return (n_l2_caches); 928575a7426Spt157919 } 929575a7426Spt157919 930575a7426Spt157919 /* 931575a7426Spt157919 * count the number of l2 caches. 932575a7426Spt157919 */ 933575a7426Spt157919 int 934575a7426Spt157919 get_l2_cache_node_count(md_t *mdp) 935575a7426Spt157919 { 936575a7426Spt157919 int i; 937575a7426Spt157919 mde_cookie_t *cachenodes; 938575a7426Spt157919 uint64_t level; 939575a7426Spt157919 int n_cachenodes = md_alloc_scan_dag(mdp, md_root_node(mdp), 940575a7426Spt157919 "cache", "fwd", &cachenodes); 941575a7426Spt157919 int l2_caches = 0; 942575a7426Spt157919 943575a7426Spt157919 for (i = 0; i < n_cachenodes; i++) { 944575a7426Spt157919 if (md_get_prop_val(mdp, cachenodes[i], "level", &level) != 0) { 945575a7426Spt157919 level = 0; 946575a7426Spt157919 } 947575a7426Spt157919 if (level == 2) { 948575a7426Spt157919 l2_caches++; 949575a7426Spt157919 } 950575a7426Spt157919 } 951575a7426Spt157919 md_free_scan_dag(mdp, &cachenodes); 952575a7426Spt157919 return (l2_caches); 953575a7426Spt157919 } 954575a7426Spt157919 9551ae08745Sheppo /* 9561ae08745Sheppo * This routine returns the L2 cache information such as -- associativity, 9571ae08745Sheppo * size and linesize. 9581ae08745Sheppo */ 9591ae08745Sheppo static int 9601ae08745Sheppo get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie, 9611ae08745Sheppo uint64_t *associativity, uint64_t *size, uint64_t *linesize) 9621ae08745Sheppo { 9631ae08745Sheppo mde_cookie_t *cachelist; 9641ae08745Sheppo int ncaches, i; 965f5db7437Sae112802 uint64_t cache_level = 0; 9661ae08745Sheppo 9671ae08745Sheppo ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache", 9681ae08745Sheppo "fwd", &cachelist); 9691ae08745Sheppo /* 9701ae08745Sheppo * The "cache" node is optional in MD, therefore ncaches can be 0. 9711ae08745Sheppo */ 9721ae08745Sheppo if (ncaches < 1) { 9731ae08745Sheppo return (0); 9741ae08745Sheppo } 9751ae08745Sheppo 9761ae08745Sheppo for (i = 0; i < ncaches; i++) { 9771ae08745Sheppo uint64_t local_assoc; 9781ae08745Sheppo uint64_t local_size; 9791ae08745Sheppo uint64_t local_lsize; 9801ae08745Sheppo 9811ae08745Sheppo if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 9821ae08745Sheppo continue; 9831ae08745Sheppo 984f5db7437Sae112802 if (cache_level != 2) continue; 9851ae08745Sheppo 9861ae08745Sheppo /* If properties are missing from this cache ignore it */ 9871ae08745Sheppo 9881ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 9891ae08745Sheppo "associativity", &local_assoc))) { 9901ae08745Sheppo continue; 9911ae08745Sheppo } 9921ae08745Sheppo 9931ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 9941ae08745Sheppo "size", &local_size))) { 9951ae08745Sheppo continue; 9961ae08745Sheppo } 9971ae08745Sheppo 9981ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 9991ae08745Sheppo "line-size", &local_lsize))) { 10001ae08745Sheppo continue; 10011ae08745Sheppo } 10021ae08745Sheppo 10031ae08745Sheppo *associativity = local_assoc; 10041ae08745Sheppo *size = local_size; 10051ae08745Sheppo *linesize = local_lsize; 1006f5db7437Sae112802 break; 10071ae08745Sheppo } 10081ae08745Sheppo 10091ae08745Sheppo md_free_scan_dag(mdp, &cachelist); 10101ae08745Sheppo 1011f5db7437Sae112802 return ((cache_level == 2) ? 1 : 0); 10121ae08745Sheppo } 10131ae08745Sheppo 10144bac2208Snarayan 10151ae08745Sheppo /* 10164bac2208Snarayan * Set the broken_md_flag to 1 if the MD doesn't have 10174bac2208Snarayan * the domaining-enabled property in the platform node and the 10184bac2208Snarayan * platform uses the UltraSPARC-T1 cpu. This flag is used to 10194bac2208Snarayan * workaround some of the incorrect MD properties. 10207c478bd9Sstevel@tonic-gate */ 10217c478bd9Sstevel@tonic-gate static void 10224bac2208Snarayan init_md_broken(md_t *mdp, mde_cookie_t *cpulist) 10237c478bd9Sstevel@tonic-gate { 10241ae08745Sheppo int nrnode; 10251ae08745Sheppo mde_cookie_t *platlist, rootnode; 10261ae08745Sheppo uint64_t val = 0; 10274bac2208Snarayan char *namebuf; 10284bac2208Snarayan int namelen; 10297c478bd9Sstevel@tonic-gate 10301ae08745Sheppo rootnode = md_root_node(mdp); 10311ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 10324bac2208Snarayan ASSERT(cpulist); 10337c478bd9Sstevel@tonic-gate 10344bac2208Snarayan nrnode = md_alloc_scan_dag(mdp, rootnode, "platform", "fwd", 10351ae08745Sheppo &platlist); 10367c478bd9Sstevel@tonic-gate 1037f273041fSjm22469 if (nrnode < 1) 1038f273041fSjm22469 cmn_err(CE_PANIC, "init_md_broken: platform node missing"); 10397c478bd9Sstevel@tonic-gate 10404bac2208Snarayan if (md_get_prop_data(mdp, cpulist[0], 10414bac2208Snarayan "compatible", (uint8_t **)&namebuf, &namelen)) { 10424bac2208Snarayan cmn_err(CE_PANIC, "init_md_broken: " 10434bac2208Snarayan "Cannot read 'compatible' property of 'cpu' node"); 10444bac2208Snarayan } 10457c478bd9Sstevel@tonic-gate 10464bac2208Snarayan if (md_get_prop_val(mdp, platlist[0], 10474bac2208Snarayan "domaining-enabled", &val) == -1 && 10484bac2208Snarayan strcmp(namebuf, "SUNW,UltraSPARC-T1") == 0) 10491ae08745Sheppo broken_md_flag = 1; 10501ae08745Sheppo 10511ae08745Sheppo md_free_scan_dag(mdp, &platlist); 10527c478bd9Sstevel@tonic-gate } 1053d2365b01SPavel Tatashin 105494c894bbSVikram Hegde #define PLAT_MAX_IOALIASES 8 105594c894bbSVikram Hegde 105694c894bbSVikram Hegde static plat_alias_t *plat_ioaliases; 105794c894bbSVikram Hegde static uint64_t plat_num_ioaliases; 105894c894bbSVikram Hegde 105994c894bbSVikram Hegde /* 106094c894bbSVikram Hegde * split the aliases property into its 106194c894bbSVikram Hegde * component strings for easy searching. 106294c894bbSVikram Hegde */ 106394c894bbSVikram Hegde static void 106494c894bbSVikram Hegde split_alias(plat_alias_t *pali, char *str) 106594c894bbSVikram Hegde { 106694c894bbSVikram Hegde char *aliasv[PLAT_MAX_IOALIASES], *p; 106794c894bbSVikram Hegde int i, duplen; 106894c894bbSVikram Hegde char *dup; 106994c894bbSVikram Hegde 107094c894bbSVikram Hegde /* skip leading space */ 107194c894bbSVikram Hegde str = dup = strdup(str); 107294c894bbSVikram Hegde duplen = strlen(dup) + 1; 107394c894bbSVikram Hegde str += strspn(str, " "); 107494c894bbSVikram Hegde for (i = 0; *str != '\0'; str = p) { 107594c894bbSVikram Hegde 107694c894bbSVikram Hegde p = strpbrk(str, " "); 107794c894bbSVikram Hegde if (p != NULL) { 107894c894bbSVikram Hegde *p++ = '\0'; 107994c894bbSVikram Hegde } 108094c894bbSVikram Hegde 108194c894bbSVikram Hegde VERIFY(i < PLAT_MAX_IOALIASES); 108294c894bbSVikram Hegde aliasv[i++] = strdup(str); 108394c894bbSVikram Hegde if (p == NULL) 108494c894bbSVikram Hegde break; 108594c894bbSVikram Hegde p += strspn(p, " "); 108694c894bbSVikram Hegde } 108794c894bbSVikram Hegde 108894c894bbSVikram Hegde kmem_free(dup, duplen); 108994c894bbSVikram Hegde 109094c894bbSVikram Hegde if (i == 0) { 109194c894bbSVikram Hegde pali->pali_naliases = 0; 109294c894bbSVikram Hegde pali->pali_aliases = NULL; 109394c894bbSVikram Hegde return; 109494c894bbSVikram Hegde } 109594c894bbSVikram Hegde 109694c894bbSVikram Hegde pali->pali_naliases = i; 109794c894bbSVikram Hegde pali->pali_aliases = kmem_alloc(i * sizeof (char *), KM_SLEEP); 109894c894bbSVikram Hegde for (i = 0; i < pali->pali_naliases; i++) { 109994c894bbSVikram Hegde pali->pali_aliases[i] = aliasv[i]; 110094c894bbSVikram Hegde } 110194c894bbSVikram Hegde } 110294c894bbSVikram Hegde 110394c894bbSVikram Hegde /* 110494c894bbSVikram Hegde * retrieve the ioalias info from the MD, 110594c894bbSVikram Hegde * and init the ioalias struct. 110694c894bbSVikram Hegde * 110794c894bbSVikram Hegde * NOTE: Assumes that the ioalias info does not change at runtime 110894c894bbSVikram Hegde * This routine is invoked only once at boot time. 110994c894bbSVikram Hegde * 111094c894bbSVikram Hegde * No lock needed as this is called at boot with a DDI lock held 111194c894bbSVikram Hegde */ 111294c894bbSVikram Hegde void 111394c894bbSVikram Hegde plat_ioaliases_init(void) 111494c894bbSVikram Hegde { 111594c894bbSVikram Hegde md_t *mdp; 111694c894bbSVikram Hegde mde_cookie_t *ionodes, alinode; 111794c894bbSVikram Hegde plat_alias_t *pali; 111894c894bbSVikram Hegde int nio; 111994c894bbSVikram Hegde int i; 112094c894bbSVikram Hegde int err; 112194c894bbSVikram Hegde 112294c894bbSVikram Hegde mdp = md_get_handle(); 112394c894bbSVikram Hegde if (mdp == NULL) { 112494c894bbSVikram Hegde cmn_err(CE_PANIC, "no machine description (MD)"); 112594c894bbSVikram Hegde /*NOTREACHED*/ 112694c894bbSVikram Hegde } 112794c894bbSVikram Hegde 112894c894bbSVikram Hegde nio = md_alloc_scan_dag(mdp, md_root_node(mdp), 112994c894bbSVikram Hegde "ioaliases", "fwd", &ionodes); 113094c894bbSVikram Hegde 113194c894bbSVikram Hegde 113294c894bbSVikram Hegde /* not all platforms support aliases */ 113394c894bbSVikram Hegde if (nio < 1) { 113494c894bbSVikram Hegde (void) md_fini_handle(mdp); 113594c894bbSVikram Hegde return; 113694c894bbSVikram Hegde } 113794c894bbSVikram Hegde if (nio > 1) { 113894c894bbSVikram Hegde cmn_err(CE_PANIC, "multiple ioalias nodes in MD"); 113994c894bbSVikram Hegde /*NOTREACHED*/ 114094c894bbSVikram Hegde } 114194c894bbSVikram Hegde 114294c894bbSVikram Hegde alinode = ionodes[0]; 114394c894bbSVikram Hegde md_free_scan_dag(mdp, &ionodes); 114494c894bbSVikram Hegde 114594c894bbSVikram Hegde nio = md_alloc_scan_dag(mdp, alinode, "ioalias", "fwd", &ionodes); 114694c894bbSVikram Hegde if (nio <= 0) { 114794c894bbSVikram Hegde cmn_err(CE_PANIC, "MD alias node has no aliases"); 114894c894bbSVikram Hegde /*NOTREACHED*/ 114994c894bbSVikram Hegde } 115094c894bbSVikram Hegde 115194c894bbSVikram Hegde plat_num_ioaliases = nio; 115294c894bbSVikram Hegde plat_ioaliases = pali = kmem_zalloc(nio * sizeof (plat_alias_t), 115394c894bbSVikram Hegde KM_SLEEP); 115494c894bbSVikram Hegde 115594c894bbSVikram Hegde /* 115694c894bbSVikram Hegde * Each ioalias map will have a composite property of 115794c894bbSVikram Hegde * aliases and the current valid path. 115894c894bbSVikram Hegde */ 115994c894bbSVikram Hegde for (i = 0; i < nio; i++) { 116094c894bbSVikram Hegde char *str; 116194c894bbSVikram Hegde 116294c894bbSVikram Hegde err = md_get_prop_str(mdp, ionodes[i], "current", &str); 116394c894bbSVikram Hegde if (err != 0) { 116494c894bbSVikram Hegde cmn_err(CE_PANIC, "malformed ioalias node"); 116594c894bbSVikram Hegde /*NOTREACHED*/ 116694c894bbSVikram Hegde } 116794c894bbSVikram Hegde pali->pali_current = strdup(str); 116894c894bbSVikram Hegde 116994c894bbSVikram Hegde err = md_get_prop_str(mdp, ionodes[i], "aliases", &str); 117094c894bbSVikram Hegde if (err != 0) { 117194c894bbSVikram Hegde cmn_err(CE_PANIC, "malformed aliases"); 117294c894bbSVikram Hegde /*NOTREACHED*/ 117394c894bbSVikram Hegde } 11745633e4f8SJan Setje-Eilers DDI_MP_DBG((CE_NOTE, "path: %s aliases %s", 11755633e4f8SJan Setje-Eilers pali->pali_current, str)); 11765633e4f8SJan Setje-Eilers 117794c894bbSVikram Hegde split_alias(pali, str); 117894c894bbSVikram Hegde pali++; 117994c894bbSVikram Hegde } 118094c894bbSVikram Hegde 118194c894bbSVikram Hegde md_free_scan_dag(mdp, &ionodes); 118294c894bbSVikram Hegde 118394c894bbSVikram Hegde /* 118494c894bbSVikram Hegde * Register the io-aliases array with the DDI framework 118594c894bbSVikram Hegde * The DDI framework assumes that this array and its contents 118694c894bbSVikram Hegde * will not change post-register. The DDI framework will 118794c894bbSVikram Hegde * cache this array and is free to access this array at 118894c894bbSVikram Hegde * any time without any locks. 118994c894bbSVikram Hegde */ 119094c894bbSVikram Hegde ddi_register_aliases(plat_ioaliases, plat_num_ioaliases); 119194c894bbSVikram Hegde 119294c894bbSVikram Hegde (void) md_fini_handle(mdp); 119394c894bbSVikram Hegde } 119494c894bbSVikram Hegde 1195d2365b01SPavel Tatashin /* 1196d2365b01SPavel Tatashin * Number of bits forming a valid context for use in a sun4v TTE and the MMU 1197d2365b01SPavel Tatashin * context registers. Sun4v defines the minimum default value to be 13 if this 1198d2365b01SPavel Tatashin * property is not specified in a cpu node in machine descriptor graph. 1199d2365b01SPavel Tatashin */ 1200d2365b01SPavel Tatashin #define MMU_INFO_CTXBITS_MIN 13 1201d2365b01SPavel Tatashin 1202d2365b01SPavel Tatashin /* Convert context bits to number of contexts */ 1203d2365b01SPavel Tatashin #define MMU_INFO_BNCTXS(nbits) ((uint_t)(1u<<(nbits))) 1204d2365b01SPavel Tatashin 1205d2365b01SPavel Tatashin /* 1206d2365b01SPavel Tatashin * Read machine descriptor and load TLB to CPU mappings. 1207d2365b01SPavel Tatashin * Returned values: cpuid2pset[NCPU], nctxs[NCPU], md_gen 1208d2365b01SPavel Tatashin * - cpuid2pset is initialized so it can convert cpuids to processor set of CPUs 1209d2365b01SPavel Tatashin * that are shared between TLBs. 1210d2365b01SPavel Tatashin * - nctxs is initialized to number of contexts for each CPU 1211d2365b01SPavel Tatashin * - md_gen is set to generation number of machine descriptor from which this 1212d2365b01SPavel Tatashin * data was. 1213d2365b01SPavel Tatashin * Return: zero on success. 1214d2365b01SPavel Tatashin */ 1215d2365b01SPavel Tatashin static int 1216d2365b01SPavel Tatashin load_tlb_cpu_mappings(cpuset_t **cpuid2pset, uint_t *nctxs, uint64_t *md_gen) 1217d2365b01SPavel Tatashin { 1218d2365b01SPavel Tatashin mde_str_cookie_t cpu_sc, bck_sc; 1219d2365b01SPavel Tatashin int tlbs_idx, cp_idx; 1220d2365b01SPavel Tatashin mde_cookie_t root; 1221d2365b01SPavel Tatashin md_t *mdp = NULL; 1222d2365b01SPavel Tatashin mde_cookie_t *tlbs = NULL; 1223d2365b01SPavel Tatashin mde_cookie_t *cp = NULL; 1224d2365b01SPavel Tatashin uint64_t *cpids = NULL; 1225d2365b01SPavel Tatashin uint64_t nbit; 1226d2365b01SPavel Tatashin int ntlbs; 1227d2365b01SPavel Tatashin int ncp; 1228d2365b01SPavel Tatashin int retval = 1; 1229d2365b01SPavel Tatashin cpuset_t *ppset; 1230d2365b01SPavel Tatashin 1231d2365b01SPavel Tatashin /* get MD handle, and string cookies for cpu and back nodes */ 1232d2365b01SPavel Tatashin if ((mdp = md_get_handle()) == NULL || 1233d2365b01SPavel Tatashin (cpu_sc = md_find_name(mdp, "cpu")) == MDE_INVAL_STR_COOKIE || 1234d2365b01SPavel Tatashin (bck_sc = md_find_name(mdp, "back")) == MDE_INVAL_STR_COOKIE) 1235d2365b01SPavel Tatashin goto cleanup; 1236d2365b01SPavel Tatashin 1237d2365b01SPavel Tatashin /* set generation number of current MD handle */ 1238d2365b01SPavel Tatashin *md_gen = md_get_gen(mdp); 1239d2365b01SPavel Tatashin 1240d2365b01SPavel Tatashin /* Find root element, and search for all TLBs in MD */ 1241d2365b01SPavel Tatashin if ((root = md_root_node(mdp)) == MDE_INVAL_ELEM_COOKIE || 1242d2365b01SPavel Tatashin (ntlbs = md_alloc_scan_dag(mdp, root, "tlb", "fwd", &tlbs)) <= 0) 1243d2365b01SPavel Tatashin goto cleanup; 1244d2365b01SPavel Tatashin 1245d2365b01SPavel Tatashin cp = kmem_alloc(sizeof (mde_cookie_t) * NCPU, KM_SLEEP); 1246d2365b01SPavel Tatashin cpids = kmem_alloc(sizeof (uint64_t) * NCPU, KM_SLEEP); 1247d2365b01SPavel Tatashin 1248d2365b01SPavel Tatashin /* 1249d2365b01SPavel Tatashin * Build processor sets, one per possible context domain. For each tlb, 1250d2365b01SPavel Tatashin * search for connected CPUs. If any CPU is already in a set, then add 1251d2365b01SPavel Tatashin * all the TLB's CPUs to that set. Otherwise, create and populate a new 1252d2365b01SPavel Tatashin * pset. Thus, a single pset is built to represent multiple TLBs if 1253d2365b01SPavel Tatashin * they have CPUs in common. 1254d2365b01SPavel Tatashin */ 1255d2365b01SPavel Tatashin for (tlbs_idx = 0; tlbs_idx < ntlbs; tlbs_idx++) { 1256d2365b01SPavel Tatashin ncp = md_scan_dag(mdp, tlbs[tlbs_idx], cpu_sc, bck_sc, cp); 1257d2365b01SPavel Tatashin if (ncp < 0) 1258d2365b01SPavel Tatashin goto cleanup; 1259d2365b01SPavel Tatashin else if (ncp == 0) 1260d2365b01SPavel Tatashin continue; 1261d2365b01SPavel Tatashin 1262d2365b01SPavel Tatashin /* Get the id and number of contexts for each cpu */ 1263d2365b01SPavel Tatashin for (cp_idx = 0; cp_idx < ncp; cp_idx++) { 1264d2365b01SPavel Tatashin mde_cookie_t c = cp[cp_idx]; 1265d2365b01SPavel Tatashin 1266d2365b01SPavel Tatashin if (md_get_prop_val(mdp, c, "id", &cpids[cp_idx])) 1267d2365b01SPavel Tatashin goto cleanup; 1268d2365b01SPavel Tatashin if (md_get_prop_val(mdp, c, "mmu-#context-bits", &nbit)) 1269d2365b01SPavel Tatashin nbit = MMU_INFO_CTXBITS_MIN; 1270d2365b01SPavel Tatashin nctxs[cpids[cp_idx]] = MMU_INFO_BNCTXS(nbit); 1271d2365b01SPavel Tatashin } 1272d2365b01SPavel Tatashin 1273d2365b01SPavel Tatashin /* 1274d2365b01SPavel Tatashin * If a CPU is already in a set as shown by cpuid2pset[], then 1275d2365b01SPavel Tatashin * use that set. 1276d2365b01SPavel Tatashin */ 1277d2365b01SPavel Tatashin for (cp_idx = 0; cp_idx < ncp; cp_idx++) { 1278d2365b01SPavel Tatashin ASSERT(cpids[cp_idx] < NCPU); 1279d2365b01SPavel Tatashin ppset = cpuid2pset[cpids[cp_idx]]; 1280d2365b01SPavel Tatashin if (ppset != NULL) 1281d2365b01SPavel Tatashin break; 1282d2365b01SPavel Tatashin } 1283d2365b01SPavel Tatashin 1284d2365b01SPavel Tatashin /* No CPU has a set. Create a new one. */ 1285d2365b01SPavel Tatashin if (ppset == NULL) { 1286d2365b01SPavel Tatashin ppset = kmem_alloc(sizeof (cpuset_t), KM_SLEEP); 1287d2365b01SPavel Tatashin CPUSET_ZERO(*ppset); 1288d2365b01SPavel Tatashin } 1289d2365b01SPavel Tatashin 1290d2365b01SPavel Tatashin /* Add every CPU to the set, and record the set assignment. */ 1291d2365b01SPavel Tatashin for (cp_idx = 0; cp_idx < ncp; cp_idx++) { 1292d2365b01SPavel Tatashin cpuid2pset[cpids[cp_idx]] = ppset; 1293d2365b01SPavel Tatashin CPUSET_ADD(*ppset, cpids[cp_idx]); 1294d2365b01SPavel Tatashin } 1295d2365b01SPavel Tatashin } 1296d2365b01SPavel Tatashin 1297d2365b01SPavel Tatashin retval = 0; 1298d2365b01SPavel Tatashin 1299d2365b01SPavel Tatashin cleanup: 1300d2365b01SPavel Tatashin if (tlbs != NULL) 1301d2365b01SPavel Tatashin md_free_scan_dag(mdp, &tlbs); 1302d2365b01SPavel Tatashin if (cp != NULL) 1303d2365b01SPavel Tatashin kmem_free(cp, sizeof (mde_cookie_t) * NCPU); 1304d2365b01SPavel Tatashin if (cpids != NULL) 1305d2365b01SPavel Tatashin kmem_free(cpids, sizeof (uint64_t) * NCPU); 1306d2365b01SPavel Tatashin if (mdp != NULL) 1307d2365b01SPavel Tatashin (void) md_fini_handle(mdp); 1308d2365b01SPavel Tatashin 1309d2365b01SPavel Tatashin return (retval); 1310d2365b01SPavel Tatashin } 1311d2365b01SPavel Tatashin 1312d2365b01SPavel Tatashin /* 1313d2365b01SPavel Tatashin * Return MMU info based on cpuid. 1314d2365b01SPavel Tatashin * 1315d2365b01SPavel Tatashin * Algorithm: 1316d2365b01SPavel Tatashin * Read machine descriptor and find all CPUs that share the same TLB with CPU 1317d2365b01SPavel Tatashin * specified by cpuid. Go through found CPUs and see if any one of them already 1318d2365b01SPavel Tatashin * has MMU index, if so, set index based on that value. If CPU does not share 1319d2365b01SPavel Tatashin * TLB with any other CPU or if none of those CPUs has mmu_ctx pointer, find the 1320d2365b01SPavel Tatashin * smallest available MMU index and give it to current CPU. If no available 1321d2365b01SPavel Tatashin * domain, perform a round robin, and start assigning from the beginning. 1322d2365b01SPavel Tatashin * 1323d2365b01SPavel Tatashin * For optimization reasons, this function uses a cache to store all TLB to CPU 1324d2365b01SPavel Tatashin * mappings, and updates them only when machine descriptor graph is changed. 1325d2365b01SPavel Tatashin * Because of this, and because we search MMU table for smallest index id, this 1326d2365b01SPavel Tatashin * function needs to be serialized which is protected by cpu_lock. 1327d2365b01SPavel Tatashin */ 1328d2365b01SPavel Tatashin void 1329d2365b01SPavel Tatashin plat_cpuid_to_mmu_ctx_info(processorid_t cpuid, mmu_ctx_info_t *info) 1330d2365b01SPavel Tatashin { 1331d2365b01SPavel Tatashin static cpuset_t **cpuid2pset = NULL; 1332d2365b01SPavel Tatashin static uint_t *nctxs; 1333d2365b01SPavel Tatashin static uint_t next_domain = 0; 1334d2365b01SPavel Tatashin static uint64_t md_gen = MDESC_INVAL_GEN; 1335d2365b01SPavel Tatashin uint64_t current_gen; 1336d2365b01SPavel Tatashin int idx; 1337d2365b01SPavel Tatashin cpuset_t cpuid_pset; 1338d2365b01SPavel Tatashin processorid_t id; 1339d2365b01SPavel Tatashin cpu_t *cp; 1340d2365b01SPavel Tatashin 1341d2365b01SPavel Tatashin ASSERT(MUTEX_HELD(&cpu_lock)); 1342d2365b01SPavel Tatashin 1343d2365b01SPavel Tatashin current_gen = md_get_current_gen(); 1344d2365b01SPavel Tatashin 1345d2365b01SPavel Tatashin /* 1346d2365b01SPavel Tatashin * Load TLB CPU mappings only if MD generation has changed, FW that do 1347d2365b01SPavel Tatashin * not provide generation number, always return MDESC_INVAL_GEN, and as 1348d2365b01SPavel Tatashin * result MD is read here only once on such machines: when cpuid2pset is 1349d2365b01SPavel Tatashin * NULL 1350d2365b01SPavel Tatashin */ 1351d2365b01SPavel Tatashin if (current_gen != md_gen || cpuid2pset == NULL) { 1352d2365b01SPavel Tatashin if (cpuid2pset == NULL) { 1353d2365b01SPavel Tatashin cpuid2pset = kmem_zalloc(sizeof (cpuset_t *) * NCPU, 1354d2365b01SPavel Tatashin KM_SLEEP); 1355d2365b01SPavel Tatashin nctxs = kmem_alloc(sizeof (uint_t) * NCPU, KM_SLEEP); 1356d2365b01SPavel Tatashin } else { 1357d2365b01SPavel Tatashin /* clean cpuid2pset[NCPU], before loading new values */ 1358d2365b01SPavel Tatashin for (idx = 0; idx < NCPU; idx++) { 1359d2365b01SPavel Tatashin cpuset_t *pset = cpuid2pset[idx]; 1360d2365b01SPavel Tatashin 1361d2365b01SPavel Tatashin if (pset != NULL) { 1362d2365b01SPavel Tatashin for (;;) { 1363d2365b01SPavel Tatashin CPUSET_FIND(*pset, id); 1364d2365b01SPavel Tatashin if (id == CPUSET_NOTINSET) 1365d2365b01SPavel Tatashin break; 1366d2365b01SPavel Tatashin CPUSET_DEL(*pset, id); 1367d2365b01SPavel Tatashin ASSERT(id < NCPU); 1368d2365b01SPavel Tatashin cpuid2pset[id] = NULL; 1369d2365b01SPavel Tatashin } 1370d2365b01SPavel Tatashin ASSERT(cpuid2pset[idx] == NULL); 1371d2365b01SPavel Tatashin kmem_free(pset, sizeof (cpuset_t)); 1372d2365b01SPavel Tatashin } 1373d2365b01SPavel Tatashin } 1374d2365b01SPavel Tatashin } 1375d2365b01SPavel Tatashin 1376d2365b01SPavel Tatashin if (load_tlb_cpu_mappings(cpuid2pset, nctxs, &md_gen)) 1377d2365b01SPavel Tatashin goto error_panic; 1378d2365b01SPavel Tatashin } 1379d2365b01SPavel Tatashin 1380d2365b01SPavel Tatashin info->mmu_nctxs = nctxs[cpuid]; 1381d2365b01SPavel Tatashin 1382d2365b01SPavel Tatashin if (cpuid2pset[cpuid] == NULL) 1383d2365b01SPavel Tatashin goto error_panic; 1384d2365b01SPavel Tatashin 1385d2365b01SPavel Tatashin cpuid_pset = *cpuid2pset[cpuid]; 1386d2365b01SPavel Tatashin CPUSET_DEL(cpuid_pset, cpuid); 1387d2365b01SPavel Tatashin 1388d2365b01SPavel Tatashin /* Search for a processor in the same TLB pset with MMU context */ 1389d2365b01SPavel Tatashin for (;;) { 1390d2365b01SPavel Tatashin CPUSET_FIND(cpuid_pset, id); 1391d2365b01SPavel Tatashin 1392d2365b01SPavel Tatashin if (id == CPUSET_NOTINSET) 1393d2365b01SPavel Tatashin break; 1394d2365b01SPavel Tatashin 1395d2365b01SPavel Tatashin ASSERT(id < NCPU); 1396d2365b01SPavel Tatashin cp = cpu[id]; 1397d2365b01SPavel Tatashin if (cp != NULL && CPU_MMU_CTXP(cp) != NULL) { 1398d2365b01SPavel Tatashin info->mmu_idx = CPU_MMU_IDX(cp); 1399d2365b01SPavel Tatashin 1400d2365b01SPavel Tatashin return; 1401d2365b01SPavel Tatashin } 1402d2365b01SPavel Tatashin CPUSET_DEL(cpuid_pset, id); 1403d2365b01SPavel Tatashin } 1404d2365b01SPavel Tatashin 1405d2365b01SPavel Tatashin /* 1406d2365b01SPavel Tatashin * No CPU in the TLB pset has a context domain yet. 1407d2365b01SPavel Tatashin * Use next_domain if available, or search for an unused domain, or 1408d2365b01SPavel Tatashin * overload next_domain, in that order. Overloading is necessary when 1409d2365b01SPavel Tatashin * the number of TLB psets is greater than max_mmu_ctxdoms. 1410d2365b01SPavel Tatashin */ 1411d2365b01SPavel Tatashin idx = next_domain; 1412d2365b01SPavel Tatashin 1413d2365b01SPavel Tatashin if (mmu_ctxs_tbl[idx] != NULL) { 1414d2365b01SPavel Tatashin for (idx = 0; idx < max_mmu_ctxdoms; idx++) 1415d2365b01SPavel Tatashin if (mmu_ctxs_tbl[idx] == NULL) 1416d2365b01SPavel Tatashin break; 1417d2365b01SPavel Tatashin if (idx == max_mmu_ctxdoms) { 1418d2365b01SPavel Tatashin /* overload next_domain */ 1419d2365b01SPavel Tatashin idx = next_domain; 1420d2365b01SPavel Tatashin 1421d2365b01SPavel Tatashin if (info->mmu_nctxs < sfmmu_ctxdom_nctxs(idx)) 1422d2365b01SPavel Tatashin cmn_err(CE_PANIC, "max_mmu_ctxdoms is too small" 1423d2365b01SPavel Tatashin " to support CPUs with different nctxs"); 1424d2365b01SPavel Tatashin } 1425d2365b01SPavel Tatashin } 1426d2365b01SPavel Tatashin 1427d2365b01SPavel Tatashin info->mmu_idx = idx; 1428d2365b01SPavel Tatashin next_domain = (idx + 1) % max_mmu_ctxdoms; 1429d2365b01SPavel Tatashin 1430d2365b01SPavel Tatashin return; 1431d2365b01SPavel Tatashin 1432d2365b01SPavel Tatashin error_panic: 1433d2365b01SPavel Tatashin cmn_err(CE_PANIC, "!cpu%d: failed to get MMU CTX domain index", cpuid); 1434d2365b01SPavel Tatashin } 1435