1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/machsystm.h> 30*0Sstevel@tonic-gate #include <sys/archsystm.h> 31*0Sstevel@tonic-gate #include <sys/vm.h> 32*0Sstevel@tonic-gate #include <sys/cpu.h> 33*0Sstevel@tonic-gate #include <sys/atomic.h> 34*0Sstevel@tonic-gate #include <sys/reboot.h> 35*0Sstevel@tonic-gate #include <sys/kdi.h> 36*0Sstevel@tonic-gate #include <sys/bootconf.h> 37*0Sstevel@tonic-gate #include <sys/memlist_plat.h> 38*0Sstevel@tonic-gate #include <sys/memlist_impl.h> 39*0Sstevel@tonic-gate #include <sys/prom_plat.h> 40*0Sstevel@tonic-gate #include <sys/prom_isa.h> 41*0Sstevel@tonic-gate #include <sys/autoconf.h> 42*0Sstevel@tonic-gate #include <sys/intreg.h> 43*0Sstevel@tonic-gate #include <sys/ivintr.h> 44*0Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 45*0Sstevel@tonic-gate #include <sys/iommutsb.h> 46*0Sstevel@tonic-gate #include <vm/vm_dep.h> 47*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 48*0Sstevel@tonic-gate #include <vm/seg_kpm.h> 49*0Sstevel@tonic-gate #include <vm/seg_map.h> 50*0Sstevel@tonic-gate #include <vm/seg_kp.h> 51*0Sstevel@tonic-gate #include <sys/sysconf.h> 52*0Sstevel@tonic-gate #include <vm/hat_sfmmu.h> 53*0Sstevel@tonic-gate #include <sys/kobj.h> 54*0Sstevel@tonic-gate #include <sys/sun4asi.h> 55*0Sstevel@tonic-gate #include <sys/clconf.h> 56*0Sstevel@tonic-gate #include <sys/platform_module.h> 57*0Sstevel@tonic-gate #include <sys/panic.h> 58*0Sstevel@tonic-gate #include <sys/cpu_sgnblk_defs.h> 59*0Sstevel@tonic-gate #include <sys/clock.h> 60*0Sstevel@tonic-gate #include <sys/fpras_impl.h> 61*0Sstevel@tonic-gate #include <sys/prom_debug.h> 62*0Sstevel@tonic-gate #ifdef TRAPTRACE 63*0Sstevel@tonic-gate #include <sys/traptrace.h> 64*0Sstevel@tonic-gate #endif /* TRAPTRACE */ 65*0Sstevel@tonic-gate #include <sys/memnode.h> 66*0Sstevel@tonic-gate #include <sys/mem_cage.h> 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * fpRAS implementation structures. 70*0Sstevel@tonic-gate */ 71*0Sstevel@tonic-gate struct fpras_chkfn *fpras_chkfnaddrs[FPRAS_NCOPYOPS]; 72*0Sstevel@tonic-gate struct fpras_chkfngrp *fpras_chkfngrps; 73*0Sstevel@tonic-gate struct fpras_chkfngrp *fpras_chkfngrps_base; 74*0Sstevel@tonic-gate int fpras_frequency = -1; 75*0Sstevel@tonic-gate int64_t fpras_interval = -1; 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate void 78*0Sstevel@tonic-gate setup_trap_table(void) 79*0Sstevel@tonic-gate { 80*0Sstevel@tonic-gate intr_init(CPU); /* init interrupt request free list */ 81*0Sstevel@tonic-gate setwstate(WSTATE_KERN); 82*0Sstevel@tonic-gate prom_set_traptable(&trap_table); 83*0Sstevel@tonic-gate } 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate void 86*0Sstevel@tonic-gate mach_fpras() 87*0Sstevel@tonic-gate { 88*0Sstevel@tonic-gate if (fpras_implemented && !fpras_disable) { 89*0Sstevel@tonic-gate int i; 90*0Sstevel@tonic-gate struct fpras_chkfngrp *fcgp; 91*0Sstevel@tonic-gate size_t chkfngrpsallocsz; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate /* 94*0Sstevel@tonic-gate * Note that we size off of NCPU and setup for 95*0Sstevel@tonic-gate * all those possibilities regardless of whether 96*0Sstevel@tonic-gate * the cpu id is present or not. We do this so that 97*0Sstevel@tonic-gate * we don't have any construction or destruction 98*0Sstevel@tonic-gate * activity to perform at DR time, and it's not 99*0Sstevel@tonic-gate * costly in memory. We require block alignment. 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate chkfngrpsallocsz = NCPU * sizeof (struct fpras_chkfngrp); 102*0Sstevel@tonic-gate fpras_chkfngrps_base = kmem_alloc(chkfngrpsallocsz, KM_SLEEP); 103*0Sstevel@tonic-gate if (IS_P2ALIGNED((uintptr_t)fpras_chkfngrps_base, 64)) { 104*0Sstevel@tonic-gate fpras_chkfngrps = fpras_chkfngrps_base; 105*0Sstevel@tonic-gate } else { 106*0Sstevel@tonic-gate kmem_free(fpras_chkfngrps_base, chkfngrpsallocsz); 107*0Sstevel@tonic-gate chkfngrpsallocsz += 64; 108*0Sstevel@tonic-gate fpras_chkfngrps_base = kmem_alloc(chkfngrpsallocsz, 109*0Sstevel@tonic-gate KM_SLEEP); 110*0Sstevel@tonic-gate fpras_chkfngrps = (struct fpras_chkfngrp *) 111*0Sstevel@tonic-gate P2ROUNDUP((uintptr_t)fpras_chkfngrps_base, 64); 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * Copy our check function into place for each copy operation 116*0Sstevel@tonic-gate * and each cpu id. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate fcgp = &fpras_chkfngrps[0]; 119*0Sstevel@tonic-gate for (i = 0; i < FPRAS_NCOPYOPS; ++i) 120*0Sstevel@tonic-gate bcopy((void *)fpras_chkfn_type1, &fcgp->fpras_fn[i], 121*0Sstevel@tonic-gate sizeof (struct fpras_chkfn)); 122*0Sstevel@tonic-gate for (i = 1; i < NCPU; ++i) 123*0Sstevel@tonic-gate *(&fpras_chkfngrps[i]) = *fcgp; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * At definition fpras_frequency is set to -1, and it will 127*0Sstevel@tonic-gate * still have that value unless changed in /etc/system (not 128*0Sstevel@tonic-gate * strictly supported, but not preventable). The following 129*0Sstevel@tonic-gate * both sets the default and sanity checks anything from 130*0Sstevel@tonic-gate * /etc/system. 131*0Sstevel@tonic-gate */ 132*0Sstevel@tonic-gate if (fpras_frequency < 0) 133*0Sstevel@tonic-gate fpras_frequency = FPRAS_DEFAULT_FREQUENCY; 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * Now calculate fpras_interval. When fpras_interval 137*0Sstevel@tonic-gate * becomes non-negative fpras checks will commence 138*0Sstevel@tonic-gate * (copies before this point in boot will bypass fpras). 139*0Sstevel@tonic-gate * Our stores of instructions must be visible; no need 140*0Sstevel@tonic-gate * to flush as they're never been executed before. 141*0Sstevel@tonic-gate */ 142*0Sstevel@tonic-gate membar_producer(); 143*0Sstevel@tonic-gate fpras_interval = (fpras_frequency == 0) ? 144*0Sstevel@tonic-gate 0 : sys_tick_freq / fpras_frequency; 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate void 149*0Sstevel@tonic-gate mach_hw_copy_limit(void) 150*0Sstevel@tonic-gate { 151*0Sstevel@tonic-gate if (!fpu_exists) { 152*0Sstevel@tonic-gate use_hw_bcopy = 0; 153*0Sstevel@tonic-gate hw_copy_limit_1 = 0; 154*0Sstevel@tonic-gate hw_copy_limit_2 = 0; 155*0Sstevel@tonic-gate hw_copy_limit_4 = 0; 156*0Sstevel@tonic-gate hw_copy_limit_8 = 0; 157*0Sstevel@tonic-gate use_hw_bzero = 0; 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate void 162*0Sstevel@tonic-gate load_tod_module() 163*0Sstevel@tonic-gate { 164*0Sstevel@tonic-gate /* 165*0Sstevel@tonic-gate * Load tod driver module for the tod part found on this system. 166*0Sstevel@tonic-gate * Recompute the cpu frequency/delays based on tod as tod part 167*0Sstevel@tonic-gate * tends to keep time more accurately. 168*0Sstevel@tonic-gate */ 169*0Sstevel@tonic-gate if (tod_module_name == NULL || modload("tod", tod_module_name) == -1) 170*0Sstevel@tonic-gate halt("Can't load tod module"); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate void 174*0Sstevel@tonic-gate mach_memscrub(void) 175*0Sstevel@tonic-gate { 176*0Sstevel@tonic-gate /* 177*0Sstevel@tonic-gate * Startup memory scrubber, if not running fpu emulation code. 178*0Sstevel@tonic-gate */ 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate if (fpu_exists) { 181*0Sstevel@tonic-gate if (memscrub_init()) { 182*0Sstevel@tonic-gate cmn_err(CE_WARN, 183*0Sstevel@tonic-gate "Memory scrubber failed to initialize"); 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate void 189*0Sstevel@tonic-gate mach_cpu_halt_idle() 190*0Sstevel@tonic-gate { 191*0Sstevel@tonic-gate /* no suport for halting idle CPU */ 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /*ARGSUSED*/ 195*0Sstevel@tonic-gate void 196*0Sstevel@tonic-gate cpu_intrq_setup(struct cpu *cp) 197*0Sstevel@tonic-gate { 198*0Sstevel@tonic-gate /* Interrupt mondo queues not applicable to sun4u */ 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate /*ARGSUSED*/ 202*0Sstevel@tonic-gate void 203*0Sstevel@tonic-gate cpu_intrq_register(struct cpu *cp) 204*0Sstevel@tonic-gate { 205*0Sstevel@tonic-gate /* Interrupt/error queues not applicable to sun4u */ 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate #ifdef TRAPTRACE 209*0Sstevel@tonic-gate /*ARGSUSED*/ 210*0Sstevel@tonic-gate void 211*0Sstevel@tonic-gate htrap_trace_setup(caddr_t buf, int cpuid) 212*0Sstevel@tonic-gate { 213*0Sstevel@tonic-gate /* Setup hypervisor traptrace buffer, not applicable to sun4u */ 214*0Sstevel@tonic-gate } 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /*ARGSUSED*/ 217*0Sstevel@tonic-gate void 218*0Sstevel@tonic-gate htrap_trace_register(int cpuid) 219*0Sstevel@tonic-gate { 220*0Sstevel@tonic-gate /* Register hypervisor traptrace buffer, not applicable to sun4u */ 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate #endif /* TRAPTRACE */ 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate void 225*0Sstevel@tonic-gate mach_descrip_init(void) 226*0Sstevel@tonic-gate { 227*0Sstevel@tonic-gate /* Obtain Machine description - only for sun4v */ 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate /* 231*0Sstevel@tonic-gate * Return true if the machine we're running on is a Positron. 232*0Sstevel@tonic-gate * (Positron is an unsupported developers platform.) 233*0Sstevel@tonic-gate */ 234*0Sstevel@tonic-gate int 235*0Sstevel@tonic-gate iam_positron(void) 236*0Sstevel@tonic-gate { 237*0Sstevel@tonic-gate char model[32]; 238*0Sstevel@tonic-gate const char proto_model[] = "SUNW,501-2732"; 239*0Sstevel@tonic-gate dnode_t root = prom_rootnode(); 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate if (prom_getproplen(root, "model") != sizeof (proto_model)) 242*0Sstevel@tonic-gate return (0); 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate (void) prom_getprop(root, "model", model); 245*0Sstevel@tonic-gate if (strcmp(model, proto_model) == 0) 246*0Sstevel@tonic-gate return (1); 247*0Sstevel@tonic-gate return (0); 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * Find a physically contiguous area of twice the largest ecache size 252*0Sstevel@tonic-gate * to be used while doing displacement flush of ecaches. 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate uint64_t 255*0Sstevel@tonic-gate ecache_flush_address(void) 256*0Sstevel@tonic-gate { 257*0Sstevel@tonic-gate struct memlist *pmem; 258*0Sstevel@tonic-gate uint64_t flush_size; 259*0Sstevel@tonic-gate uint64_t ret_val; 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate flush_size = ecache_size * 2; 262*0Sstevel@tonic-gate for (pmem = phys_install; pmem; pmem = pmem->next) { 263*0Sstevel@tonic-gate ret_val = P2ROUNDUP(pmem->address, ecache_size); 264*0Sstevel@tonic-gate if (ret_val + flush_size <= pmem->address + pmem->size) 265*0Sstevel@tonic-gate return (ret_val); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate return ((uint64_t)-1); 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * Called with the memlist lock held to say that phys_install has 272*0Sstevel@tonic-gate * changed. 273*0Sstevel@tonic-gate */ 274*0Sstevel@tonic-gate void 275*0Sstevel@tonic-gate phys_install_has_changed(void) 276*0Sstevel@tonic-gate { 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * Get the new address into a temporary just in case panicking 279*0Sstevel@tonic-gate * involves use of ecache_flushaddr. 280*0Sstevel@tonic-gate */ 281*0Sstevel@tonic-gate uint64_t new_addr; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate new_addr = ecache_flush_address(); 284*0Sstevel@tonic-gate if (new_addr == (uint64_t)-1) { 285*0Sstevel@tonic-gate cmn_err(CE_PANIC, 286*0Sstevel@tonic-gate "ecache_flush_address(): failed, ecache_size=%x", 287*0Sstevel@tonic-gate ecache_size); 288*0Sstevel@tonic-gate /*NOTREACHED*/ 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate ecache_flushaddr = new_addr; 291*0Sstevel@tonic-gate membar_producer(); 292*0Sstevel@tonic-gate } 293