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 #include <sys/traptrace.h> 63 #include <sys/memnode.h> 64 #include <sys/mem_cage.h> 65 66 /* 67 * fpRAS implementation structures. 68 */ 69 struct fpras_chkfn *fpras_chkfnaddrs[FPRAS_NCOPYOPS]; 70 struct fpras_chkfngrp *fpras_chkfngrps; 71 struct fpras_chkfngrp *fpras_chkfngrps_base; 72 int fpras_frequency = -1; 73 int64_t fpras_interval = -1; 74 75 void 76 setup_trap_table(void) 77 { 78 intr_init(CPU); /* init interrupt request free list */ 79 setwstate(WSTATE_KERN); 80 prom_set_traptable(&trap_table); 81 } 82 83 void 84 mach_fpras() 85 { 86 if (fpras_implemented && !fpras_disable) { 87 int i; 88 struct fpras_chkfngrp *fcgp; 89 size_t chkfngrpsallocsz; 90 91 /* 92 * Note that we size off of NCPU and setup for 93 * all those possibilities regardless of whether 94 * the cpu id is present or not. We do this so that 95 * we don't have any construction or destruction 96 * activity to perform at DR time, and it's not 97 * costly in memory. We require block alignment. 98 */ 99 chkfngrpsallocsz = NCPU * sizeof (struct fpras_chkfngrp); 100 fpras_chkfngrps_base = kmem_alloc(chkfngrpsallocsz, KM_SLEEP); 101 if (IS_P2ALIGNED((uintptr_t)fpras_chkfngrps_base, 64)) { 102 fpras_chkfngrps = fpras_chkfngrps_base; 103 } else { 104 kmem_free(fpras_chkfngrps_base, chkfngrpsallocsz); 105 chkfngrpsallocsz += 64; 106 fpras_chkfngrps_base = kmem_alloc(chkfngrpsallocsz, 107 KM_SLEEP); 108 fpras_chkfngrps = (struct fpras_chkfngrp *) 109 P2ROUNDUP((uintptr_t)fpras_chkfngrps_base, 64); 110 } 111 112 /* 113 * Copy our check function into place for each copy operation 114 * and each cpu id. 115 */ 116 fcgp = &fpras_chkfngrps[0]; 117 for (i = 0; i < FPRAS_NCOPYOPS; ++i) 118 bcopy((void *)fpras_chkfn_type1, &fcgp->fpras_fn[i], 119 sizeof (struct fpras_chkfn)); 120 for (i = 1; i < NCPU; ++i) 121 *(&fpras_chkfngrps[i]) = *fcgp; 122 123 /* 124 * At definition fpras_frequency is set to -1, and it will 125 * still have that value unless changed in /etc/system (not 126 * strictly supported, but not preventable). The following 127 * both sets the default and sanity checks anything from 128 * /etc/system. 129 */ 130 if (fpras_frequency < 0) 131 fpras_frequency = FPRAS_DEFAULT_FREQUENCY; 132 133 /* 134 * Now calculate fpras_interval. When fpras_interval 135 * becomes non-negative fpras checks will commence 136 * (copies before this point in boot will bypass fpras). 137 * Our stores of instructions must be visible; no need 138 * to flush as they're never been executed before. 139 */ 140 membar_producer(); 141 fpras_interval = (fpras_frequency == 0) ? 142 0 : sys_tick_freq / fpras_frequency; 143 } 144 } 145 146 void 147 mach_hw_copy_limit(void) 148 { 149 if (!fpu_exists) { 150 use_hw_bcopy = 0; 151 hw_copy_limit_1 = 0; 152 hw_copy_limit_2 = 0; 153 hw_copy_limit_4 = 0; 154 hw_copy_limit_8 = 0; 155 use_hw_bzero = 0; 156 } 157 } 158 159 void 160 load_tod_module() 161 { 162 /* 163 * Load tod driver module for the tod part found on this system. 164 * Recompute the cpu frequency/delays based on tod as tod part 165 * tends to keep time more accurately. 166 */ 167 if (tod_module_name == NULL || modload("tod", tod_module_name) == -1) 168 halt("Can't load tod module"); 169 } 170 171 void 172 mach_memscrub(void) 173 { 174 /* 175 * Startup memory scrubber, if not running fpu emulation code. 176 */ 177 178 if (fpu_exists) { 179 if (memscrub_init()) { 180 cmn_err(CE_WARN, 181 "Memory scrubber failed to initialize"); 182 } 183 } 184 } 185 186 void 187 mach_cpu_halt_idle() 188 { 189 /* no suport for halting idle CPU */ 190 } 191 192 /*ARGSUSED*/ 193 void 194 cpu_intrq_setup(struct cpu *cp) 195 { 196 /* Interrupt mondo queues not applicable to sun4u */ 197 } 198 199 /*ARGSUSED*/ 200 void 201 cpu_intrq_register(struct cpu *cp) 202 { 203 /* Interrupt/error queues not applicable to sun4u */ 204 } 205 206 /*ARGSUSED*/ 207 void 208 mach_htraptrace_setup(int cpuid) 209 { 210 /* Setup hypervisor traptrace buffer, not applicable to sun4u */ 211 } 212 213 /*ARGSUSED*/ 214 void 215 mach_htraptrace_configure(int cpuid) 216 { 217 /* enable/ disable hypervisor traptracing, not applicable to sun4u */ 218 } 219 220 /*ARGSUSED*/ 221 void 222 mach_htraptrace_init(void) 223 { 224 /* allocate hypervisor traptrace buffer, not applicable to sun4u */ 225 } 226 227 /*ARGSUSED*/ 228 void 229 mach_htraptrace_cleanup(int cpuid) 230 { 231 /* cleanup hypervisor traptrace buffer, not applicable to sun4u */ 232 } 233 234 void 235 mach_descrip_init(void) 236 { 237 /* Obtain Machine description - only for sun4v */ 238 } 239 240 /* 241 * Return true if the machine we're running on is a Positron. 242 * (Positron is an unsupported developers platform.) 243 */ 244 int 245 iam_positron(void) 246 { 247 char model[32]; 248 const char proto_model[] = "SUNW,501-2732"; 249 pnode_t root = prom_rootnode(); 250 251 if (prom_getproplen(root, "model") != sizeof (proto_model)) 252 return (0); 253 254 (void) prom_getprop(root, "model", model); 255 if (strcmp(model, proto_model) == 0) 256 return (1); 257 return (0); 258 } 259 260 /* 261 * Find a physically contiguous area of twice the largest ecache size 262 * to be used while doing displacement flush of ecaches. 263 */ 264 uint64_t 265 ecache_flush_address(void) 266 { 267 struct memlist *pmem; 268 uint64_t flush_size; 269 uint64_t ret_val; 270 271 flush_size = ecache_size * 2; 272 for (pmem = phys_install; pmem; pmem = pmem->next) { 273 ret_val = P2ROUNDUP(pmem->address, ecache_size); 274 if (ret_val + flush_size <= pmem->address + pmem->size) 275 return (ret_val); 276 } 277 return ((uint64_t)-1); 278 } 279 280 /* 281 * Called with the memlist lock held to say that phys_install has 282 * changed. 283 */ 284 void 285 phys_install_has_changed(void) 286 { 287 /* 288 * Get the new address into a temporary just in case panicking 289 * involves use of ecache_flushaddr. 290 */ 291 uint64_t new_addr; 292 293 new_addr = ecache_flush_address(); 294 if (new_addr == (uint64_t)-1) { 295 cmn_err(CE_PANIC, 296 "ecache_flush_address(): failed, ecache_size=%x", 297 ecache_size); 298 /*NOTREACHED*/ 299 } 300 ecache_flushaddr = new_addr; 301 membar_producer(); 302 } 303