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