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 5*1ae08745Sheppo * Common Development and Distribution License (the "License"). 6*1ae08745Sheppo * 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 /* 22*1ae08745Sheppo * Copyright 2006 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> 46*1ae08745Sheppo #include <vm/hat_sfmmu.h> 47*1ae08745Sheppo #include <sys/sysmacros.h> 48*1ae08745Sheppo #include <sys/mach_descrip.h> 49*1ae08745Sheppo #include <sys/mdesc.h> 50*1ae08745Sheppo #include <sys/archsystm.h> 51*1ae08745Sheppo #include <sys/error.h> 52*1ae08745Sheppo #include <sys/mmu.h> 53*1ae08745Sheppo #include <sys/bitmap.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate int ncpunode; 567c478bd9Sstevel@tonic-gate struct cpu_node cpunodes[NCPU]; 577c478bd9Sstevel@tonic-gate 58*1ae08745Sheppo uint64_t cpu_q_entries; 59*1ae08745Sheppo uint64_t dev_q_entries; 60*1ae08745Sheppo uint64_t cpu_rq_entries; 61*1ae08745Sheppo uint64_t cpu_nrq_entries; 62*1ae08745Sheppo 63*1ae08745Sheppo void fill_cpu(md_t *, mde_cookie_t); 64*1ae08745Sheppo 65*1ae08745Sheppo static uint64_t get_mmu_ctx_bits(md_t *, mde_cookie_t); 66*1ae08745Sheppo static uint64_t get_cpu_pagesizes(md_t *, mde_cookie_t); 67*1ae08745Sheppo static char *construct_isalist(md_t *, mde_cookie_t, char **); 68*1ae08745Sheppo static void set_at_flags(char *, int, char **); 69*1ae08745Sheppo static void init_md_broken(md_t *); 70*1ae08745Sheppo static int get_l2_cache_info(md_t *, mde_cookie_t, uint64_t *, uint64_t *, 71*1ae08745Sheppo uint64_t *); 72*1ae08745Sheppo static id_t get_exec_unit_mapping(md_t *, mde_cookie_t, mde_cookie_t *); 73*1ae08745Sheppo static int find_exec_unit_id(mde_cookie_t, mde_cookie_t *); 74*1ae08745Sheppo static void get_q_sizes(md_t *, mde_cookie_t); 75*1ae08745Sheppo static void get_va_bits(md_t *, mde_cookie_t); 76*1ae08745Sheppo static size_t get_ra_limit(md_t *); 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate uint64_t system_clock_freq; 797c478bd9Sstevel@tonic-gate int niobus = 0; 807c478bd9Sstevel@tonic-gate uint_t niommu_tsbs = 0; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate void 837c478bd9Sstevel@tonic-gate map_wellknown_devices() 847c478bd9Sstevel@tonic-gate { 85*1ae08745Sheppo } 86*1ae08745Sheppo 87*1ae08745Sheppo #define S_VAC_SIZE MMU_PAGESIZE 88*1ae08745Sheppo #define S_VAC_SHIFT MMU_PAGESHIFT 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 91*1ae08745Sheppo * For backward compatibility we need to verify that we can handle 92*1ae08745Sheppo * running on platforms which shipped with missing MD properties. 937c478bd9Sstevel@tonic-gate */ 94*1ae08745Sheppo #define ONTARIO_PLATNAME1 "SUNW,Sun-Fire-T200" 95*1ae08745Sheppo #define ONTARIO_PLATNAME2 "SUNW,Sun-Fire-T2000" 96*1ae08745Sheppo #define ERIE_PLATNAME1 "SUNW,Sun-Fire-T100" 97*1ae08745Sheppo #define ERIE_PLATNAME2 "SUNW,Sun-Fire-T1000" 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate void 100*1ae08745Sheppo fill_cpu(md_t *mdp, mde_cookie_t cpuc) 1017c478bd9Sstevel@tonic-gate { 1027c478bd9Sstevel@tonic-gate struct cpu_node *cpunode; 103*1ae08745Sheppo uint64_t cpuid; 104*1ae08745Sheppo uint64_t clk_freq; 105*1ae08745Sheppo char *namebuf; 1067c478bd9Sstevel@tonic-gate char *namebufp; 107*1ae08745Sheppo int namelen; 108*1ae08745Sheppo uint64_t associativity = 0, linesize = 0, size = 0; 109*1ae08745Sheppo int status; 1107c478bd9Sstevel@tonic-gate 111*1ae08745Sheppo if (md_get_prop_val(mdp, cpuc, "id", &cpuid)) { 112*1ae08745Sheppo return; 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 115*1ae08745Sheppo if (cpuid >= NCPU) { 116*1ae08745Sheppo cmn_err(CE_CONT, "fill_cpu: out of range cpuid %ld - " 117*1ae08745Sheppo "cpu excluded from configuration", cpuid); 118*1ae08745Sheppo 119*1ae08745Sheppo mutex_enter(&cpu_lock); 120*1ae08745Sheppo 121*1ae08745Sheppo /* 122*1ae08745Sheppo * Since the CPU cannot be used, make sure it 123*1ae08745Sheppo * is in a safe place. If the firmware does not 124*1ae08745Sheppo * support CPU stop, this is known to be true. 125*1ae08745Sheppo * If it fails to stop for any other reason, the 126*1ae08745Sheppo * system is in an inconsistent state and cannot 127*1ae08745Sheppo * be allowed to continue. 128*1ae08745Sheppo */ 129*1ae08745Sheppo status = stopcpu_bycpuid(cpuid); 130*1ae08745Sheppo 131*1ae08745Sheppo if ((status != 0) && (status != ENOTSUP)) { 132*1ae08745Sheppo cmn_err(CE_PANIC, "failed to stop cpu %lu (%d)", 133*1ae08745Sheppo cpuid, status); 134*1ae08745Sheppo } 135*1ae08745Sheppo 136*1ae08745Sheppo mutex_exit(&cpu_lock); 1377c478bd9Sstevel@tonic-gate return; 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate cpunode = &cpunodes[cpuid]; 141*1ae08745Sheppo cpunode->cpuid = (int)cpuid; 1427c478bd9Sstevel@tonic-gate cpunode->device_id = cpuid; 1437c478bd9Sstevel@tonic-gate 144*1ae08745Sheppo if (sizeof (cpunode->fru_fmri) > strlen(CPU_FRU_FMRI)) 145*1ae08745Sheppo (void) strcpy(cpunode->fru_fmri, CPU_FRU_FMRI); 146*1ae08745Sheppo 147*1ae08745Sheppo if (md_get_prop_data(mdp, cpuc, 148*1ae08745Sheppo "compatible", (uint8_t **)&namebuf, &namelen)) { 149*1ae08745Sheppo cmn_err(CE_PANIC, "fill_cpu: Cannot read compatible " 150*1ae08745Sheppo "property"); 151*1ae08745Sheppo } 1527c478bd9Sstevel@tonic-gate namebufp = namebuf; 1537c478bd9Sstevel@tonic-gate if (strncmp(namebufp, "SUNW,", 5) == 0) 1547c478bd9Sstevel@tonic-gate namebufp += 5; 155*1ae08745Sheppo if (strlen(namebufp) > sizeof (cpunode->name)) 156*1ae08745Sheppo cmn_err(CE_PANIC, "Compatible property too big to " 157*1ae08745Sheppo "fit into the cpunode name buffer"); 1587c478bd9Sstevel@tonic-gate (void) strcpy(cpunode->name, namebufp); 1597c478bd9Sstevel@tonic-gate 160*1ae08745Sheppo if (md_get_prop_val(mdp, cpuc, 161*1ae08745Sheppo "clock-frequency", &clk_freq)) { 1627c478bd9Sstevel@tonic-gate clk_freq = 0; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate cpunode->clock_freq = clk_freq; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate ASSERT(cpunode->clock_freq != 0); 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Compute scaling factor based on rate of %tick. This is used 1697c478bd9Sstevel@tonic-gate * to convert from ticks derived from %tick to nanoseconds. See 1707c478bd9Sstevel@tonic-gate * comment in sun4u/sys/clock.h for details. 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << 1737c478bd9Sstevel@tonic-gate (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); 1747c478bd9Sstevel@tonic-gate 175*1ae08745Sheppo /* 176*1ae08745Sheppo * The nodeid is not used in sun4v at all. Setting it 177*1ae08745Sheppo * to positive value to make starting of slave CPUs 178*1ae08745Sheppo * code happy. 179*1ae08745Sheppo */ 180*1ae08745Sheppo cpunode->nodeid = cpuid + 1; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* 183*1ae08745Sheppo * Obtain the L2 cache information from MD. 184*1ae08745Sheppo * If "Cache" node exists, then set L2 cache properties 185*1ae08745Sheppo * as read from MD. 186*1ae08745Sheppo * If node does not exists, then set the L2 cache properties 187*1ae08745Sheppo * in individual CPU module. 1887c478bd9Sstevel@tonic-gate */ 189*1ae08745Sheppo if ((!get_l2_cache_info(mdp, cpuc, 190*1ae08745Sheppo &associativity, &size, &linesize)) || 191*1ae08745Sheppo associativity == 0 || size == 0 || linesize == 0) { 1927c478bd9Sstevel@tonic-gate cpu_fiximp(cpunode); 193*1ae08745Sheppo } else { 194*1ae08745Sheppo /* 195*1ae08745Sheppo * Do not expect L2 cache properties to be bigger 196*1ae08745Sheppo * than 32-bit quantity. 197*1ae08745Sheppo */ 198*1ae08745Sheppo cpunode->ecache_associativity = (int)associativity; 199*1ae08745Sheppo cpunode->ecache_size = (int)size; 200*1ae08745Sheppo cpunode->ecache_linesize = (int)linesize; 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 203*1ae08745Sheppo cpunode->ecache_setsize = 204*1ae08745Sheppo cpunode->ecache_size / cpunode->ecache_associativity; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* 207*1ae08745Sheppo * Start off by assigning the cpu id as the default 208*1ae08745Sheppo * mapping index. 209*1ae08745Sheppo */ 210*1ae08745Sheppo 211*1ae08745Sheppo cpunode->exec_unit_mapping = NO_EU_MAPPING_FOUND; 212*1ae08745Sheppo 213*1ae08745Sheppo if (ecache_setsize == 0) 214*1ae08745Sheppo ecache_setsize = cpunode->ecache_setsize; 215*1ae08745Sheppo if (ecache_alignsize == 0) 216*1ae08745Sheppo ecache_alignsize = cpunode->ecache_linesize; 217*1ae08745Sheppo 218*1ae08745Sheppo ncpunode++; 219*1ae08745Sheppo } 220*1ae08745Sheppo 221*1ae08745Sheppo void 222*1ae08745Sheppo empty_cpu(int cpuid) 223*1ae08745Sheppo { 224*1ae08745Sheppo bzero(&cpunodes[cpuid], sizeof (struct cpu_node)); 225*1ae08745Sheppo ncpunode--; 226*1ae08745Sheppo } 227*1ae08745Sheppo 228*1ae08745Sheppo void 229*1ae08745Sheppo setup_exec_unit_mappings(md_t *mdp) 230*1ae08745Sheppo { 231*1ae08745Sheppo uint64_t num, num_eunits; 232*1ae08745Sheppo mde_cookie_t cpus_node; 233*1ae08745Sheppo mde_cookie_t *node, *eunit; 234*1ae08745Sheppo int idx, i, j; 235*1ae08745Sheppo processorid_t cpuid; 236*1ae08745Sheppo char *eunit_name = broken_md_flag ? "exec_unit" : "exec-unit"; 237*1ae08745Sheppo 238*1ae08745Sheppo /* 239*1ae08745Sheppo * Find the cpu integer exec units - and 240*1ae08745Sheppo * setup the mappings appropriately. 241*1ae08745Sheppo */ 242*1ae08745Sheppo num = md_alloc_scan_dag(mdp, md_root_node(mdp), "cpus", "fwd", &node); 243*1ae08745Sheppo if (num < 1) 244*1ae08745Sheppo cmn_err(CE_PANIC, "No cpus node in machine desccription"); 245*1ae08745Sheppo if (num > 1) 246*1ae08745Sheppo cmn_err(CE_PANIC, "More than 1 cpus node in machine" 247*1ae08745Sheppo " description"); 248*1ae08745Sheppo 249*1ae08745Sheppo cpus_node = node[0]; 250*1ae08745Sheppo md_free_scan_dag(mdp, &node); 251*1ae08745Sheppo 252*1ae08745Sheppo num_eunits = md_alloc_scan_dag(mdp, cpus_node, eunit_name, 253*1ae08745Sheppo "fwd", &eunit); 254*1ae08745Sheppo if (num_eunits > 0) { 255*1ae08745Sheppo char *match_type = broken_md_flag ? "int" : "integer"; 256*1ae08745Sheppo 257*1ae08745Sheppo /* Spin through and find all the integer exec units */ 258*1ae08745Sheppo for (i = 0; i < num_eunits; i++) { 259*1ae08745Sheppo char *p; 260*1ae08745Sheppo char *val; 261*1ae08745Sheppo int vallen; 262*1ae08745Sheppo uint64_t lcpuid; 263*1ae08745Sheppo 264*1ae08745Sheppo /* ignore nodes with no type */ 265*1ae08745Sheppo if (md_get_prop_data(mdp, eunit[i], "type", 266*1ae08745Sheppo (uint8_t **)&val, &vallen)) continue; 267*1ae08745Sheppo 268*1ae08745Sheppo for (p = val; *p != '\0'; p += strlen(p) + 1) { 269*1ae08745Sheppo if (strcmp(p, match_type) == 0) 270*1ae08745Sheppo goto found; 271*1ae08745Sheppo } 272*1ae08745Sheppo 273*1ae08745Sheppo continue; 274*1ae08745Sheppo found: 275*1ae08745Sheppo idx = NCPU + i; 276*1ae08745Sheppo /* 277*1ae08745Sheppo * find the cpus attached to this EU and 278*1ae08745Sheppo * update their mapping indices 279*1ae08745Sheppo */ 280*1ae08745Sheppo num = md_alloc_scan_dag(mdp, eunit[i], "cpu", 281*1ae08745Sheppo "back", &node); 282*1ae08745Sheppo 283*1ae08745Sheppo if (num < 1) 284*1ae08745Sheppo cmn_err(CE_PANIC, "exec-unit node in MD" 285*1ae08745Sheppo " not attached to a cpu node"); 286*1ae08745Sheppo 287*1ae08745Sheppo for (j = 0; j < num; j++) { 288*1ae08745Sheppo if (md_get_prop_val(mdp, node[j], "id", 289*1ae08745Sheppo &lcpuid)) 290*1ae08745Sheppo continue; 291*1ae08745Sheppo if (lcpuid >= NCPU) 292*1ae08745Sheppo continue; 293*1ae08745Sheppo cpuid = (processorid_t)lcpuid; 294*1ae08745Sheppo cpunodes[cpuid].exec_unit_mapping = idx; 295*1ae08745Sheppo } 296*1ae08745Sheppo md_free_scan_dag(mdp, &node); 297*1ae08745Sheppo } 298*1ae08745Sheppo 299*1ae08745Sheppo 300*1ae08745Sheppo md_free_scan_dag(mdp, &eunit); 301*1ae08745Sheppo } 302*1ae08745Sheppo } 303*1ae08745Sheppo 304*1ae08745Sheppo /* 305*1ae08745Sheppo * All the common setup of sun4v CPU modules is done by this routine. 306*1ae08745Sheppo */ 307*1ae08745Sheppo void 308*1ae08745Sheppo cpu_setup_common(char **cpu_module_isa_set) 309*1ae08745Sheppo { 310*1ae08745Sheppo extern int disable_delay_tlb_flush, delay_tlb_flush; 311*1ae08745Sheppo extern int mmu_exported_pagesize_mask; 312*1ae08745Sheppo extern int vac_size, vac_shift; 313*1ae08745Sheppo extern uint_t vac_mask; 314*1ae08745Sheppo int nocpus, i; 315*1ae08745Sheppo size_t ra_limit; 316*1ae08745Sheppo mde_cookie_t *cpulist; 317*1ae08745Sheppo md_t *mdp; 318*1ae08745Sheppo 319*1ae08745Sheppo if ((mdp = md_get_handle()) == NULL) 320*1ae08745Sheppo cmn_err(CE_PANIC, "Unable to initialize machine description"); 321*1ae08745Sheppo 322*1ae08745Sheppo init_md_broken(mdp); 323*1ae08745Sheppo 324*1ae08745Sheppo nocpus = md_alloc_scan_dag(mdp, 325*1ae08745Sheppo md_root_node(mdp), "cpu", "fwd", &cpulist); 326*1ae08745Sheppo if (nocpus < 1) { 327*1ae08745Sheppo cmn_err(CE_PANIC, "cpu_common_setup: cpulist allocation " 328*1ae08745Sheppo "failed or incorrect number of CPUs in MD"); 329*1ae08745Sheppo } 330*1ae08745Sheppo 331*1ae08745Sheppo if (use_page_coloring) { 332*1ae08745Sheppo do_pg_coloring = 1; 333*1ae08745Sheppo if (use_virtual_coloring) { 334*1ae08745Sheppo /* 335*1ae08745Sheppo * XXX Sun4v cpus don't have virtual caches 336*1ae08745Sheppo */ 337*1ae08745Sheppo do_virtual_coloring = 1; 338*1ae08745Sheppo } 339*1ae08745Sheppo } 340*1ae08745Sheppo 341*1ae08745Sheppo /* 342*1ae08745Sheppo * Get the valid contexts, mmu page sizes mask, Q sizes and isalist/r 343*1ae08745Sheppo * from the MD for the first available CPU in cpulist. 344*1ae08745Sheppo */ 345*1ae08745Sheppo 346*1ae08745Sheppo if (nctxs == 0) 347*1ae08745Sheppo nctxs = (uint_t)(1 << get_mmu_ctx_bits(mdp, cpulist[0])); 348*1ae08745Sheppo 349*1ae08745Sheppo if (nctxs > MAX_NCTXS) 350*1ae08745Sheppo nctxs = MAX_NCTXS; 351*1ae08745Sheppo 352*1ae08745Sheppo /* Do not expect the MMU page sizes mask to be more than 32-bit. */ 353*1ae08745Sheppo mmu_exported_pagesize_mask = (int)get_cpu_pagesizes(mdp, cpulist[0]); 354*1ae08745Sheppo 355*1ae08745Sheppo for (i = 0; i < nocpus; i++) 356*1ae08745Sheppo fill_cpu(mdp, cpulist[i]); 357*1ae08745Sheppo 358*1ae08745Sheppo setup_exec_unit_mappings(mdp); 359*1ae08745Sheppo 360*1ae08745Sheppo vac_size = S_VAC_SIZE; 361*1ae08745Sheppo vac_mask = MMU_PAGEMASK & (vac_size - 1); 362*1ae08745Sheppo vac_shift = S_VAC_SHIFT; 363*1ae08745Sheppo shm_alignment = vac_size; 364*1ae08745Sheppo vac = 0; 365*1ae08745Sheppo 366*1ae08745Sheppo /* 367*1ae08745Sheppo * If MD is broken then append the passed ISA set, 368*1ae08745Sheppo * otherwise trust the MD. 369*1ae08745Sheppo */ 370*1ae08745Sheppo 371*1ae08745Sheppo if (broken_md_flag) 372*1ae08745Sheppo isa_list = construct_isalist(mdp, cpulist[0], 373*1ae08745Sheppo cpu_module_isa_set); 374*1ae08745Sheppo else 375*1ae08745Sheppo isa_list = construct_isalist(mdp, cpulist[0], NULL); 376*1ae08745Sheppo 377*1ae08745Sheppo get_q_sizes(mdp, cpulist[0]); 378*1ae08745Sheppo 379*1ae08745Sheppo get_va_bits(mdp, cpulist[0]); 380*1ae08745Sheppo 381*1ae08745Sheppo /* 382*1ae08745Sheppo * ra_limit is the highest real address in the machine. 383*1ae08745Sheppo */ 384*1ae08745Sheppo ra_limit = get_ra_limit(mdp); 385*1ae08745Sheppo 386*1ae08745Sheppo md_free_scan_dag(mdp, &cpulist); 387*1ae08745Sheppo 388*1ae08745Sheppo (void) md_fini_handle(mdp); 389*1ae08745Sheppo 390*1ae08745Sheppo /* 391*1ae08745Sheppo * Block stores invalidate all pages of the d$ so pagecopy 392*1ae08745Sheppo * et. al. do not need virtual translations with virtual 393*1ae08745Sheppo * coloring taken into consideration. 394*1ae08745Sheppo */ 395*1ae08745Sheppo pp_consistent_coloring = 0; 396*1ae08745Sheppo 397*1ae08745Sheppo /* 398*1ae08745Sheppo * The kpm mapping window. 399*1ae08745Sheppo * kpm_size: 400*1ae08745Sheppo * The size of a single kpm range. 401*1ae08745Sheppo * The overall size will be: kpm_size * vac_colors. 402*1ae08745Sheppo * kpm_vbase: 403*1ae08745Sheppo * The virtual start address of the kpm range within the kernel 404*1ae08745Sheppo * virtual address space. kpm_vbase has to be kpm_size aligned. 405*1ae08745Sheppo */ 406*1ae08745Sheppo 407*1ae08745Sheppo /* 408*1ae08745Sheppo * Make kpm_vbase, kpm_size aligned to kpm_size_shift. 409*1ae08745Sheppo * To do this find the nearest power of 2 size that the 410*1ae08745Sheppo * actual ra_limit fits within. 411*1ae08745Sheppo * If it is an even power of two use that, otherwise use the 412*1ae08745Sheppo * next power of two larger than ra_limit. 413*1ae08745Sheppo */ 414*1ae08745Sheppo 415*1ae08745Sheppo ASSERT(ra_limit != 0); 416*1ae08745Sheppo 417*1ae08745Sheppo kpm_size_shift = (ra_limit & (ra_limit - 1)) != 0 ? 418*1ae08745Sheppo highbit(ra_limit) : highbit(ra_limit) - 1; 419*1ae08745Sheppo 420*1ae08745Sheppo /* 421*1ae08745Sheppo * No virtual caches on sun4v so size matches size shift 422*1ae08745Sheppo */ 423*1ae08745Sheppo kpm_size = 1ul << kpm_size_shift; 424*1ae08745Sheppo 425*1ae08745Sheppo if (va_bits < VA_ADDRESS_SPACE_BITS) { 426*1ae08745Sheppo /* 427*1ae08745Sheppo * In case of VA hole 428*1ae08745Sheppo * kpm_base = hole_end + 1TB 429*1ae08745Sheppo * Starting 1TB beyond where VA hole ends because on Niagara 430*1ae08745Sheppo * processor software must not use pages within 4GB of the 431*1ae08745Sheppo * VA hole as instruction pages to avoid problems with 432*1ae08745Sheppo * prefetching into the VA hole. 433*1ae08745Sheppo */ 434*1ae08745Sheppo kpm_vbase = (caddr_t)((0ull - (1ull << (va_bits - 1))) + 435*1ae08745Sheppo (1ull << 40)); 436*1ae08745Sheppo } else { /* Number of VA bits 64 ... no VA hole */ 437*1ae08745Sheppo kpm_vbase = (caddr_t)0x8000000000000000ull; /* 8 EB */ 438*1ae08745Sheppo } 439*1ae08745Sheppo 440*1ae08745Sheppo /* 441*1ae08745Sheppo * The traptrace code uses either %tick or %stick for 442*1ae08745Sheppo * timestamping. The sun4v require use of %stick. 443*1ae08745Sheppo */ 444*1ae08745Sheppo traptrace_use_stick = 1; 445*1ae08745Sheppo 446*1ae08745Sheppo /* 447*1ae08745Sheppo * sun4v provides demap_all 448*1ae08745Sheppo */ 449*1ae08745Sheppo if (!disable_delay_tlb_flush) 450*1ae08745Sheppo delay_tlb_flush = 1; 451*1ae08745Sheppo } 452*1ae08745Sheppo 453*1ae08745Sheppo /* 454*1ae08745Sheppo * Get the nctxs from MD. If absent panic. 455*1ae08745Sheppo */ 456*1ae08745Sheppo static uint64_t 457*1ae08745Sheppo get_mmu_ctx_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 458*1ae08745Sheppo { 459*1ae08745Sheppo uint64_t ctx_bits; 460*1ae08745Sheppo 461*1ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#context-bits", 462*1ae08745Sheppo &ctx_bits)) 463*1ae08745Sheppo ctx_bits = 0; 464*1ae08745Sheppo 465*1ae08745Sheppo if (ctx_bits < MIN_NCTXS_BITS || ctx_bits > MAX_NCTXS_BITS) 466*1ae08745Sheppo cmn_err(CE_PANIC, "Incorrect %ld number of contexts bits " 467*1ae08745Sheppo "returned by MD", ctx_bits); 468*1ae08745Sheppo 469*1ae08745Sheppo return (ctx_bits); 470*1ae08745Sheppo } 471*1ae08745Sheppo 472*1ae08745Sheppo /* 473*1ae08745Sheppo * Initalize supported page sizes information. 474*1ae08745Sheppo * Set to 0, if the page sizes mask information is absent in MD. 475*1ae08745Sheppo */ 476*1ae08745Sheppo static uint64_t 477*1ae08745Sheppo get_cpu_pagesizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 478*1ae08745Sheppo { 479*1ae08745Sheppo uint64_t mmu_page_size_list; 480*1ae08745Sheppo 481*1ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-page-size-list", 482*1ae08745Sheppo &mmu_page_size_list)) 483*1ae08745Sheppo mmu_page_size_list = 0; 484*1ae08745Sheppo 485*1ae08745Sheppo if (mmu_page_size_list == 0 || mmu_page_size_list > MAX_PAGESIZE_MASK) 486*1ae08745Sheppo cmn_err(CE_PANIC, "Incorrect 0x%lx pagesize mask returned" 487*1ae08745Sheppo "by MD", mmu_page_size_list); 488*1ae08745Sheppo 489*1ae08745Sheppo return (mmu_page_size_list); 490*1ae08745Sheppo } 491*1ae08745Sheppo 492*1ae08745Sheppo /* 493*1ae08745Sheppo * This routine gets the isalist information from MD and appends 494*1ae08745Sheppo * the CPU module ISA set if required. 495*1ae08745Sheppo */ 496*1ae08745Sheppo static char * 497*1ae08745Sheppo construct_isalist(md_t *mdp, mde_cookie_t cpu_node_cookie, 498*1ae08745Sheppo char **cpu_module_isa_set) 499*1ae08745Sheppo { 500*1ae08745Sheppo extern int at_flags; 501*1ae08745Sheppo char *md_isalist; 502*1ae08745Sheppo int md_isalen; 503*1ae08745Sheppo char *isabuf; 504*1ae08745Sheppo int isalen; 505*1ae08745Sheppo char **isa_set; 506*1ae08745Sheppo char *p, *q; 507*1ae08745Sheppo int cpu_module_isalen = 0, found = 0; 508*1ae08745Sheppo 509*1ae08745Sheppo (void) md_get_prop_data(mdp, cpu_node_cookie, 510*1ae08745Sheppo "isalist", (uint8_t **)&isabuf, &isalen); 511*1ae08745Sheppo 512*1ae08745Sheppo /* 513*1ae08745Sheppo * We support binaries for all the cpus that have shipped so far. 514*1ae08745Sheppo * The kernel emulates instructions that are not supported by hardware. 515*1ae08745Sheppo */ 516*1ae08745Sheppo at_flags = EF_SPARC_SUN_US3 | EF_SPARC_32PLUS | EF_SPARC_SUN_US1; 517*1ae08745Sheppo 518*1ae08745Sheppo /* 519*1ae08745Sheppo * Construct the space separated isa_list. 520*1ae08745Sheppo */ 521*1ae08745Sheppo if (cpu_module_isa_set != NULL) { 522*1ae08745Sheppo for (isa_set = cpu_module_isa_set; *isa_set != NULL; 523*1ae08745Sheppo isa_set++) { 524*1ae08745Sheppo cpu_module_isalen += strlen(*isa_set); 525*1ae08745Sheppo cpu_module_isalen++; /* for space character */ 526*1ae08745Sheppo } 527*1ae08745Sheppo } 528*1ae08745Sheppo 529*1ae08745Sheppo /* 530*1ae08745Sheppo * Allocate the buffer of MD isa buffer length + CPU module 531*1ae08745Sheppo * isa buffer length. 532*1ae08745Sheppo */ 533*1ae08745Sheppo md_isalen = isalen + cpu_module_isalen + 2; 534*1ae08745Sheppo md_isalist = (char *)prom_alloc((caddr_t)0, md_isalen, 0); 535*1ae08745Sheppo if (md_isalist == NULL) 536*1ae08745Sheppo cmn_err(CE_PANIC, "construct_isalist: Allocation failed for " 537*1ae08745Sheppo "md_isalist"); 538*1ae08745Sheppo 539*1ae08745Sheppo md_isalist[0] = '\0'; /* create an empty string to start */ 540*1ae08745Sheppo for (p = isabuf, q = p + isalen; p < q; p += strlen(p) + 1) { 541*1ae08745Sheppo (void) strlcat(md_isalist, p, md_isalen); 542*1ae08745Sheppo (void) strcat(md_isalist, " "); 543*1ae08745Sheppo } 544*1ae08745Sheppo 545*1ae08745Sheppo /* 546*1ae08745Sheppo * Check if the isa_set is present in isalist returned by MD. 547*1ae08745Sheppo * If yes, then no need to append it, if no then append it to 548*1ae08745Sheppo * isalist returned by MD. 549*1ae08745Sheppo */ 550*1ae08745Sheppo if (cpu_module_isa_set != NULL) { 551*1ae08745Sheppo for (isa_set = cpu_module_isa_set; *isa_set != NULL; 552*1ae08745Sheppo isa_set++) { 553*1ae08745Sheppo found = 0; 554*1ae08745Sheppo for (p = isabuf, q = p + isalen; p < q; 555*1ae08745Sheppo p += strlen(p) + 1) { 556*1ae08745Sheppo if (strcmp(p, *isa_set) == 0) { 557*1ae08745Sheppo found = 1; 558*1ae08745Sheppo break; 559*1ae08745Sheppo } 560*1ae08745Sheppo } 561*1ae08745Sheppo if (!found) { 562*1ae08745Sheppo (void) strlcat(md_isalist, *isa_set, md_isalen); 563*1ae08745Sheppo (void) strcat(md_isalist, " "); 564*1ae08745Sheppo } 565*1ae08745Sheppo } 566*1ae08745Sheppo } 567*1ae08745Sheppo 568*1ae08745Sheppo /* Get rid of any trailing white spaces */ 569*1ae08745Sheppo md_isalist[strlen(md_isalist) - 1] = '\0'; 570*1ae08745Sheppo 571*1ae08745Sheppo return (md_isalist); 572*1ae08745Sheppo } 573*1ae08745Sheppo 574*1ae08745Sheppo uint64_t 575*1ae08745Sheppo get_ra_limit(md_t *mdp) 576*1ae08745Sheppo { 577*1ae08745Sheppo mde_cookie_t *mem_list; 578*1ae08745Sheppo mde_cookie_t *mblock_list; 579*1ae08745Sheppo int i; 580*1ae08745Sheppo int memnodes; 581*1ae08745Sheppo int nmblock; 582*1ae08745Sheppo uint64_t base; 583*1ae08745Sheppo uint64_t size; 584*1ae08745Sheppo uint64_t ra_limit = 0, new_limit = 0; 585*1ae08745Sheppo 586*1ae08745Sheppo memnodes = md_alloc_scan_dag(mdp, 587*1ae08745Sheppo md_root_node(mdp), "memory", "fwd", &mem_list); 588*1ae08745Sheppo 589*1ae08745Sheppo ASSERT(memnodes == 1); 590*1ae08745Sheppo 591*1ae08745Sheppo nmblock = md_alloc_scan_dag(mdp, 592*1ae08745Sheppo mem_list[0], "mblock", "fwd", &mblock_list); 593*1ae08745Sheppo if (nmblock < 1) 594*1ae08745Sheppo cmn_err(CE_PANIC, "cannot find mblock nodes in MD"); 595*1ae08745Sheppo 596*1ae08745Sheppo for (i = 0; i < nmblock; i++) { 597*1ae08745Sheppo if (md_get_prop_val(mdp, mblock_list[i], "base", &base)) 598*1ae08745Sheppo cmn_err(CE_PANIC, "base property missing from MD" 599*1ae08745Sheppo " mblock node"); 600*1ae08745Sheppo if (md_get_prop_val(mdp, mblock_list[i], "size", &size)) 601*1ae08745Sheppo cmn_err(CE_PANIC, "size property missing from MD" 602*1ae08745Sheppo " mblock node"); 603*1ae08745Sheppo 604*1ae08745Sheppo ASSERT(size != 0); 605*1ae08745Sheppo 606*1ae08745Sheppo new_limit = base + size; 607*1ae08745Sheppo 608*1ae08745Sheppo if (base > new_limit) 609*1ae08745Sheppo cmn_err(CE_PANIC, "mblock in MD wrapped around"); 610*1ae08745Sheppo 611*1ae08745Sheppo if (new_limit > ra_limit) 612*1ae08745Sheppo ra_limit = new_limit; 613*1ae08745Sheppo } 614*1ae08745Sheppo 615*1ae08745Sheppo ASSERT(ra_limit != 0); 616*1ae08745Sheppo 617*1ae08745Sheppo if (ra_limit > MAX_REAL_ADDRESS) { 618*1ae08745Sheppo cmn_err(CE_WARN, "Highest real address in MD too large" 619*1ae08745Sheppo " clipping to %llx\n", MAX_REAL_ADDRESS); 620*1ae08745Sheppo ra_limit = MAX_REAL_ADDRESS; 621*1ae08745Sheppo } 622*1ae08745Sheppo 623*1ae08745Sheppo md_free_scan_dag(mdp, &mblock_list); 624*1ae08745Sheppo 625*1ae08745Sheppo md_free_scan_dag(mdp, &mem_list); 626*1ae08745Sheppo 627*1ae08745Sheppo return (ra_limit); 628*1ae08745Sheppo } 629*1ae08745Sheppo 630*1ae08745Sheppo /* 631*1ae08745Sheppo * This routine sets the globals for CPU and DEV mondo queue entries and 632*1ae08745Sheppo * resumable and non-resumable error queue entries. 633*1ae08745Sheppo */ 634*1ae08745Sheppo static uint64_t 635*1ae08745Sheppo get_single_q_size(md_t *mdp, mde_cookie_t cpu_node_cookie, 636*1ae08745Sheppo char *qnamep, uint64_t default_entries) 637*1ae08745Sheppo { 638*1ae08745Sheppo uint64_t entries; 639*1ae08745Sheppo 640*1ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, qnamep, &entries)) { 641*1ae08745Sheppo if (!broken_md_flag) 642*1ae08745Sheppo cmn_err(CE_PANIC, "Missing %s property in MD cpu node", 643*1ae08745Sheppo qnamep); 644*1ae08745Sheppo entries = default_entries; 645*1ae08745Sheppo } else { 646*1ae08745Sheppo entries = 1 << entries; 647*1ae08745Sheppo } 648*1ae08745Sheppo return (entries); 649*1ae08745Sheppo } 650*1ae08745Sheppo 651*1ae08745Sheppo 652*1ae08745Sheppo static void 653*1ae08745Sheppo get_q_sizes(md_t *mdp, mde_cookie_t cpu_node_cookie) 654*1ae08745Sheppo { 655*1ae08745Sheppo cpu_q_entries = get_single_q_size(mdp, cpu_node_cookie, 656*1ae08745Sheppo "q-cpu-mondo-#bits", DEFAULT_CPU_Q_ENTRIES); 657*1ae08745Sheppo 658*1ae08745Sheppo dev_q_entries = get_single_q_size(mdp, cpu_node_cookie, 659*1ae08745Sheppo "q-dev-mondo-#bits", DEFAULT_DEV_Q_ENTRIES); 660*1ae08745Sheppo 661*1ae08745Sheppo cpu_rq_entries = get_single_q_size(mdp, cpu_node_cookie, 662*1ae08745Sheppo "q-resumable-#bits", CPU_RQ_ENTRIES); 663*1ae08745Sheppo 664*1ae08745Sheppo cpu_nrq_entries = get_single_q_size(mdp, cpu_node_cookie, 665*1ae08745Sheppo "q-nonresumable-#bits", CPU_NRQ_ENTRIES); 666*1ae08745Sheppo } 667*1ae08745Sheppo 668*1ae08745Sheppo 669*1ae08745Sheppo static void 670*1ae08745Sheppo get_va_bits(md_t *mdp, mde_cookie_t cpu_node_cookie) 671*1ae08745Sheppo { 672*1ae08745Sheppo uint64_t value = VA_ADDRESS_SPACE_BITS; 673*1ae08745Sheppo 674*1ae08745Sheppo if (md_get_prop_val(mdp, cpu_node_cookie, "mmu-#va-bits", &value)) 675*1ae08745Sheppo cmn_err(CE_PANIC, "mmu-#va-bits property not found in MD"); 676*1ae08745Sheppo 677*1ae08745Sheppo 678*1ae08745Sheppo if (value == 0 || value > VA_ADDRESS_SPACE_BITS) 679*1ae08745Sheppo cmn_err(CE_PANIC, "Incorrect number of va bits in MD"); 680*1ae08745Sheppo 681*1ae08745Sheppo /* Do not expect number of VA bits to be more than 32-bit quantity */ 682*1ae08745Sheppo 683*1ae08745Sheppo va_bits = (int)value; 684*1ae08745Sheppo 685*1ae08745Sheppo /* 686*1ae08745Sheppo * Correct the value for VA bits on UltraSPARC-T1 based systems 687*1ae08745Sheppo * in case of broken MD. 688*1ae08745Sheppo */ 689*1ae08745Sheppo if (broken_md_flag) 690*1ae08745Sheppo va_bits = DEFAULT_VA_ADDRESS_SPACE_BITS; 691*1ae08745Sheppo } 692*1ae08745Sheppo 693*1ae08745Sheppo /* 694*1ae08745Sheppo * This routine returns the L2 cache information such as -- associativity, 695*1ae08745Sheppo * size and linesize. 696*1ae08745Sheppo */ 697*1ae08745Sheppo static int 698*1ae08745Sheppo get_l2_cache_info(md_t *mdp, mde_cookie_t cpu_node_cookie, 699*1ae08745Sheppo uint64_t *associativity, uint64_t *size, uint64_t *linesize) 700*1ae08745Sheppo { 701*1ae08745Sheppo mde_cookie_t *cachelist; 702*1ae08745Sheppo int ncaches, i; 703*1ae08745Sheppo uint64_t max_level; 704*1ae08745Sheppo 705*1ae08745Sheppo ncaches = md_alloc_scan_dag(mdp, cpu_node_cookie, "cache", 706*1ae08745Sheppo "fwd", &cachelist); 707*1ae08745Sheppo /* 708*1ae08745Sheppo * The "cache" node is optional in MD, therefore ncaches can be 0. 709*1ae08745Sheppo */ 710*1ae08745Sheppo if (ncaches < 1) { 711*1ae08745Sheppo return (0); 712*1ae08745Sheppo } 713*1ae08745Sheppo 714*1ae08745Sheppo max_level = 0; 715*1ae08745Sheppo for (i = 0; i < ncaches; i++) { 716*1ae08745Sheppo uint64_t cache_level; 717*1ae08745Sheppo uint64_t local_assoc; 718*1ae08745Sheppo uint64_t local_size; 719*1ae08745Sheppo uint64_t local_lsize; 720*1ae08745Sheppo 721*1ae08745Sheppo if (md_get_prop_val(mdp, cachelist[i], "level", &cache_level)) 722*1ae08745Sheppo continue; 723*1ae08745Sheppo 724*1ae08745Sheppo if (cache_level <= max_level) continue; 725*1ae08745Sheppo 726*1ae08745Sheppo /* If properties are missing from this cache ignore it */ 727*1ae08745Sheppo 728*1ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 729*1ae08745Sheppo "associativity", &local_assoc))) { 730*1ae08745Sheppo continue; 731*1ae08745Sheppo } 732*1ae08745Sheppo 733*1ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 734*1ae08745Sheppo "size", &local_size))) { 735*1ae08745Sheppo continue; 736*1ae08745Sheppo } 737*1ae08745Sheppo 738*1ae08745Sheppo if ((md_get_prop_val(mdp, cachelist[i], 739*1ae08745Sheppo "line-size", &local_lsize))) { 740*1ae08745Sheppo continue; 741*1ae08745Sheppo } 742*1ae08745Sheppo 743*1ae08745Sheppo max_level = cache_level; 744*1ae08745Sheppo *associativity = local_assoc; 745*1ae08745Sheppo *size = local_size; 746*1ae08745Sheppo *linesize = local_lsize; 747*1ae08745Sheppo } 748*1ae08745Sheppo 749*1ae08745Sheppo md_free_scan_dag(mdp, &cachelist); 750*1ae08745Sheppo 751*1ae08745Sheppo return ((max_level > 0) ? 1 : 0); 752*1ae08745Sheppo } 753*1ae08745Sheppo 754*1ae08745Sheppo /* 755*1ae08745Sheppo * The broken_md_flag is set to 1, if the MD doesn't have 756*1ae08745Sheppo * the domaining-enabled property in the platform node and the platforms 757*1ae08745Sheppo * are Ontario and Erie. This flag is used to workaround some of the 758*1ae08745Sheppo * incorrect MD properties. 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate static void 761*1ae08745Sheppo init_md_broken(md_t *mdp) 7627c478bd9Sstevel@tonic-gate { 763*1ae08745Sheppo int nrnode; 764*1ae08745Sheppo mde_cookie_t *platlist, rootnode; 765*1ae08745Sheppo char *vbuf; 766*1ae08745Sheppo uint64_t val = 0; 7677c478bd9Sstevel@tonic-gate 768*1ae08745Sheppo rootnode = md_root_node(mdp); 769*1ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 7707c478bd9Sstevel@tonic-gate 771*1ae08745Sheppo nrnode = md_alloc_scan_dag(mdp, md_root_node(mdp), "platform", "fwd", 772*1ae08745Sheppo &platlist); 7737c478bd9Sstevel@tonic-gate 774*1ae08745Sheppo ASSERT(nrnode == 1); 7757c478bd9Sstevel@tonic-gate 776*1ae08745Sheppo if (md_get_prop_str(mdp, platlist[0], "name", &vbuf) != 0) 777*1ae08745Sheppo panic("platform name not found in machine description"); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* 780*1ae08745Sheppo * If domaining-enable prop doesn't exist and the platform name is 781*1ae08745Sheppo * Ontario or Erie the md is broken. 7827c478bd9Sstevel@tonic-gate */ 7837c478bd9Sstevel@tonic-gate 784*1ae08745Sheppo if (md_get_prop_val(mdp, platlist[0], "domaining-enabled", &val) != 0 && 785*1ae08745Sheppo ((strcmp(vbuf, ONTARIO_PLATNAME1) == 0) || 786*1ae08745Sheppo (strcmp(vbuf, ONTARIO_PLATNAME2) == 0) || 787*1ae08745Sheppo (strcmp(vbuf, ERIE_PLATNAME1) == 0) || 788*1ae08745Sheppo (strcmp(vbuf, ERIE_PLATNAME2) == 0))) 789*1ae08745Sheppo broken_md_flag = 1; 790*1ae08745Sheppo 791*1ae08745Sheppo md_free_scan_dag(mdp, &platlist); 7927c478bd9Sstevel@tonic-gate } 793