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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 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 /* 30 * Public interface to routines implemented by CPU modules 31 */ 32 33 #include <sys/x86_archext.h> 34 #include <sys/cpu_module_impl.h> 35 #include <sys/fm/util.h> 36 #include <sys/reboot.h> 37 #include <sys/modctl.h> 38 #include <sys/param.h> 39 #include <sys/cmn_err.h> 40 #include <sys/systm.h> 41 #include <sys/types.h> 42 43 #define CPUMOD_SUBDIR "cpu" 44 #define CPUMOD_PREFIX "cpu" 45 46 #define CMI_OPS(cpu) \ 47 (cpu)->cpu_m.mcpu_cmi->cmi_ops 48 #define CMI_DATA(cpu) \ 49 (cpu)->cpu_m.mcpu_cmidata 50 51 /* 52 * If cleared for debugging we will not attempt to load a model-specific 53 * cpu module but will load the generic cpu module instead. 54 */ 55 int cmi_force_generic = 0; 56 57 /* 58 * If cleared for debugging, we will suppress panicking on fatal hardware 59 * errors. This should *only* be used for debugging; it use can and will 60 * cause data corruption if actual hardware errors are detected by the system. 61 */ 62 int cmi_panic_on_uncorrectable_error = 1; 63 64 static cmi_t *cmi_list; 65 static kmutex_t cmi_load_lock; 66 67 static int 68 cmi_cpu_match(cpu_t *c1, cpu_t *c2) 69 { 70 return (cpuid_getfamily(c1) == cpuid_getfamily(c2) && 71 cpuid_getmodel(c1) == cpuid_getmodel(c2) && 72 cpuid_getstep(c1) == cpuid_getstep(c2) && 73 strcmp(cpuid_getvendorstr(c1), cpuid_getvendorstr(c2)) == 0); 74 } 75 76 static cmi_t * 77 cmi_load_modctl(modctl_t *modp) 78 { 79 uintptr_t ops; 80 cmi_t *cmi; 81 82 ASSERT(MUTEX_HELD(&cmi_load_lock)); 83 84 for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) { 85 if (cmi->cmi_modp == modp) 86 return (cmi); 87 } 88 89 if ((ops = modlookup_by_modctl(modp, "_cmi_ops")) == NULL) { 90 cmn_err(CE_WARN, "cpu module '%s' is invalid: no _cmi_ops " 91 "found", modp->mod_modname); 92 return (NULL); 93 } 94 95 /* 96 * Hold the module in memory. We call to CPU modules without using the 97 * stubs mechanism, so these modules must be manually held in memory. 98 * The mod_ref acts as if another loaded module has a dependency on us. 99 */ 100 mutex_enter(&mod_lock); 101 modp->mod_ref++; 102 mutex_exit(&mod_lock); 103 104 cmi = kmem_zalloc(sizeof (cmi_t), KM_SLEEP); 105 cmi->cmi_ops = (const cmi_ops_t *)ops; 106 cmi->cmi_modp = modp; 107 108 cmi->cmi_next = cmi_list; 109 cmi_list = cmi; 110 111 return (cmi); 112 } 113 114 static cmi_t * 115 cmi_load_module(cpu_t *cp) 116 { 117 modctl_t *modp; 118 cmi_t *cmi; 119 int i, modid; 120 uint_t s[3]; 121 122 /* 123 * Look to see if we've already got a module loaded for a CPU just 124 * like this one. If we do, then we'll re-use it. 125 */ 126 ASSERT(MUTEX_HELD(&cmi_load_lock)); 127 mutex_enter(&cpu_lock); 128 129 for (i = 0; i < NCPU; i++) { 130 cpu_t *cp2 = cpu[i]; 131 132 if (cp2 != NULL && cp2 != cp && 133 cp2->cpu_m.mcpu_cmi != NULL && cmi_cpu_match(cp, cp2)) { 134 mutex_exit(&cpu_lock); 135 return (cp2->cpu_m.mcpu_cmi); 136 } 137 } 138 139 mutex_exit(&cpu_lock); 140 141 /* 142 * If we can't find a match, attempt to load the appropriate module. 143 * If that also fails, try to load the generic CPU module. 144 */ 145 s[0] = cpuid_getfamily(cp); 146 s[1] = cpuid_getmodel(cp); 147 s[2] = cpuid_getstep(cp); 148 149 modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX, 150 cpuid_getvendorstr(cp), ".", s, sizeof (s) / sizeof (s[0])); 151 152 if (modid == -1) 153 modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic"); 154 155 if (modid == -1) 156 return (NULL); 157 158 modp = mod_hold_by_id(modid); 159 cmi = cmi_load_modctl(modp); 160 mod_release_mod(modp); 161 162 return (cmi); 163 } 164 165 static cmi_t * 166 cmi_load_generic(void) 167 { 168 modctl_t *modp; 169 cmi_t *cmi; 170 int modid; 171 172 if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1) 173 return (NULL); 174 175 modp = mod_hold_by_id(modid); 176 cmi = cmi_load_modctl(modp); 177 mod_release_mod(modp); 178 179 return (cmi); 180 } 181 182 /* 183 * Load a CPU module for the specified CPU, and then call its cmi_init routine. 184 * If the module returns ENOTSUP, try using the generic CPU module instead. 185 * If all else fails, we return -1 and the caller will panic or halt. 186 */ 187 int 188 cmi_load(cpu_t *cp) 189 { 190 int err = ENOENT; 191 cmi_t *cmi; 192 void *data; 193 194 mutex_enter(&cmi_load_lock); 195 196 if (!cmi_force_generic && ( 197 ((cmi = cmi_load_module(cp)) == NULL) || 198 ((err = cmi->cmi_ops->cmi_init(cp, &data)) != 0 && 199 err != ENOTSUP))) { 200 cmn_err(CE_WARN, 201 "cpu%d: failed to init cpu module '%s': err=%d", 202 cp->cpu_id, cmi ? cmi->cmi_modp->mod_modname : "<>", err); 203 mutex_exit(&cmi_load_lock); 204 return (-1); 205 } 206 207 if ((cmi_force_generic || err != 0) && 208 ((cmi = cmi_load_generic()) == NULL || 209 (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0)) { 210 cmn_err(CE_WARN, 211 "cpu%d: failed to init cpu module '%s': err=%d", 212 cp->cpu_id, cmi ? cmi->cmi_modp->mod_modname : "<>", err); 213 mutex_exit(&cmi_load_lock); 214 return (-1); 215 } 216 217 ASSERT(cp->cpu_m.mcpu_cmi == NULL); 218 cp->cpu_m.mcpu_cmi = cmi; 219 cp->cpu_m.mcpu_cmidata = data; 220 221 cmi->cmi_refcnt++; 222 mutex_exit(&cmi_load_lock); 223 224 if (boothowto & RB_VERBOSE) { 225 printf("cpu%d: initialized cpu module '%s'\n", 226 cp->cpu_id, cmi->cmi_modp->mod_modname); 227 } 228 229 return (0); 230 } 231 232 void 233 cmi_init(void) 234 { 235 if (cmi_load(CPU) < 0) 236 panic("failed to load module for cpu%d", CPU->cpu_id); 237 } 238 239 void 240 cmi_post_init(void) 241 { 242 CMI_OPS(CPU)->cmi_post_init(CMI_DATA(CPU)); 243 } 244 245 /* 246 * Called just once from start_other_cpus when all processors are started. 247 * This will not be called for each cpu, so the registered op must not 248 * assume it is called as such. 249 */ 250 void 251 cmi_post_mpstartup(void) 252 { 253 CMI_OPS(CPU)->cmi_post_mpstartup(CMI_DATA(CPU)); 254 } 255 256 void 257 cmi_faulted_enter(cpu_t *cp) 258 { 259 CMI_OPS(cp)->cmi_faulted_enter(CMI_DATA(cp)); 260 } 261 262 void 263 cmi_faulted_exit(cpu_t *cp) 264 { 265 CMI_OPS(cp)->cmi_faulted_exit(CMI_DATA(cp)); 266 } 267 268 int 269 cmi_scrubber_enable(cpu_t *cp, uint64_t base, uint64_t ilen, int cscontig) 270 { 271 return (CMI_OPS(cp)->cmi_scrubber_enable(CMI_DATA(cp), base, ilen, 272 cscontig)); 273 } 274 275 void 276 cmi_mca_init(void) 277 { 278 CMI_OPS(CPU)->cmi_mca_init(CMI_DATA(CPU)); 279 } 280 281 void 282 cmi_mca_trap(struct regs *rp) 283 { 284 if (CMI_OPS(CPU)->cmi_mca_trap(CMI_DATA(CPU), rp)) { 285 if (cmi_panic_on_uncorrectable_error) 286 fm_panic("Unrecoverable Machine-Check Exception"); 287 else 288 cmn_err(CE_WARN, "suppressing panic from fatal #mc"); 289 } 290 } 291 292 int 293 cmi_mca_inject(cmi_mca_regs_t *regs, uint_t nregs) 294 { 295 int err; 296 297 kpreempt_disable(); 298 err = CMI_OPS(CPU)->cmi_mca_inject(CMI_DATA(CPU), regs, nregs); 299 kpreempt_enable(); 300 301 return (err); 302 } 303 304 void 305 cmi_mca_poke(void) 306 { 307 CMI_OPS(CPU)->cmi_mca_poke(CMI_DATA(CPU)); 308 } 309 310 void 311 cmi_mc_register(cpu_t *cp, const cmi_mc_ops_t *mcops, void *mcdata) 312 { 313 CMI_OPS(cp)->cmi_mc_register(CMI_DATA(cp), mcops, mcdata); 314 } 315 316 int 317 cmi_mc_patounum(uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, uint32_t synd, 318 int syndtype, mc_unum_t *up) 319 { 320 const struct cmi_mc_ops *mcops; 321 cpu_t *cp = CPU; 322 323 if (CMI_OPS(cp) == NULL || 324 (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL) 325 return (-1); /* not registered yet */ 326 327 return (mcops->cmi_mc_patounum(CMI_DATA(cp), pa, valid_hi, valid_lo, 328 synd, syndtype, up)); 329 } 330 331 int 332 cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap) 333 { 334 const struct cmi_mc_ops *mcops; 335 cpu_t *cp = CPU; 336 337 if (up != NULL && nvl != NULL) 338 return (-1); /* only convert from one or the other form */ 339 340 if (CMI_OPS(cp) == NULL || 341 (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL) 342 return (-1); /* not registered yet */ 343 344 return (mcops->cmi_mc_unumtopa(CMI_DATA(cp), up, nvl, pap)); 345 } 346