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 2006 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 suppress panicking on fatal hardware 53 * errors. This should *only* be used for debugging; it use can and will 54 * cause data corruption if actual hardware errors are detected by the system. 55 */ 56 int cmi_panic_on_uncorrectable_error = 1; 57 58 static cmi_t *cmi_list; 59 static kmutex_t cmi_load_lock; 60 61 static int 62 cmi_cpu_match(cpu_t *c1, cpu_t *c2) 63 { 64 return (cpuid_getfamily(c1) == cpuid_getfamily(c2) && 65 cpuid_getmodel(c1) == cpuid_getmodel(c2) && 66 cpuid_getstep(c1) == cpuid_getstep(c2) && 67 strcmp(cpuid_getvendorstr(c1), cpuid_getvendorstr(c2)) == 0); 68 } 69 70 static cmi_t * 71 cmi_load_modctl(modctl_t *modp) 72 { 73 uintptr_t ops; 74 cmi_t *cmi; 75 76 ASSERT(MUTEX_HELD(&cmi_load_lock)); 77 78 for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) { 79 if (cmi->cmi_modp == modp) 80 return (cmi); 81 } 82 83 if ((ops = modlookup_by_modctl(modp, "_cmi_ops")) == NULL) { 84 cmn_err(CE_WARN, "CPU module %s is invalid: no _cmi_ops " 85 "found\n", modp->mod_modname); 86 return (NULL); 87 } 88 89 /* 90 * Hold the module in memory. We call to CPU modules without using the 91 * stubs mechanism, so these modules must be manually held in memory. 92 * The mod_ref acts as if another loaded module has a dependency on us. 93 */ 94 mutex_enter(&mod_lock); 95 modp->mod_ref++; 96 mutex_exit(&mod_lock); 97 98 cmi = kmem_zalloc(sizeof (cmi_t), KM_SLEEP); 99 cmi->cmi_ops = (const cmi_ops_t *)ops; 100 cmi->cmi_modp = modp; 101 102 cmi->cmi_next = cmi_list; 103 cmi_list = cmi; 104 105 return (cmi); 106 } 107 108 static cmi_t * 109 cmi_load_module(cpu_t *cp) 110 { 111 modctl_t *modp; 112 cmi_t *cmi; 113 int i, modid; 114 uint_t s[3]; 115 116 /* 117 * Look to see if we've already got a module loaded for a CPU just 118 * like this one. If we do, then we'll re-use it. 119 */ 120 ASSERT(MUTEX_HELD(&cmi_load_lock)); 121 mutex_enter(&cpu_lock); 122 123 for (i = 0; i < NCPU; i++) { 124 cpu_t *cp2 = cpu[i]; 125 126 if (cp2 != NULL && cp2 != cp && 127 cp2->cpu_m.mcpu_cmi != NULL && cmi_cpu_match(cp, cp2)) { 128 mutex_exit(&cpu_lock); 129 return (cp2->cpu_m.mcpu_cmi); 130 } 131 } 132 133 mutex_exit(&cpu_lock); 134 135 /* 136 * If we can't find a match, attempt to load the appropriate module. 137 * If that also fails, try to load the generic CPU module. 138 */ 139 s[0] = cpuid_getfamily(cp); 140 s[1] = cpuid_getmodel(cp); 141 s[2] = cpuid_getstep(cp); 142 143 modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX, 144 cpuid_getvendorstr(cp), ".", s, sizeof (s) / sizeof (s[0])); 145 146 if (modid == -1) 147 modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic"); 148 149 if (modid == -1) 150 return (NULL); 151 152 modp = mod_hold_by_id(modid); 153 cmi = cmi_load_modctl(modp); 154 mod_release_mod(modp); 155 156 return (cmi); 157 } 158 159 static cmi_t * 160 cmi_load_generic(void) 161 { 162 modctl_t *modp; 163 cmi_t *cmi; 164 int modid; 165 166 if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1) 167 return (NULL); 168 169 modp = mod_hold_by_id(modid); 170 cmi = cmi_load_modctl(modp); 171 mod_release_mod(modp); 172 173 return (cmi); 174 } 175 176 /* 177 * Load a CPU module for the specified CPU, and then call its cmi_init routine. 178 * If the module returns ENOTSUP, try using the generic CPU module instead. 179 * If all else fails, we return -1 and the caller will panic or halt. 180 */ 181 int 182 cmi_load(cpu_t *cp) 183 { 184 int err = ENOENT; 185 cmi_t *cmi; 186 void *data; 187 188 mutex_enter(&cmi_load_lock); 189 190 if ((cmi = cmi_load_module(cp)) == NULL || ( 191 (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0 && err != ENOTSUP)) { 192 cmn_err(CE_WARN, "CPU module %s failed to init CPU %d: err=%d", 193 cmi ? cmi->cmi_modp->mod_modname : "<>", cp->cpu_id, err); 194 mutex_exit(&cmi_load_lock); 195 return (-1); 196 } 197 198 if (err != 0 && ((cmi = cmi_load_generic()) == NULL || 199 (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0)) { 200 cmn_err(CE_WARN, "CPU module %s failed to init CPU %d: err=%d", 201 cmi ? cmi->cmi_modp->mod_modname : "<>", cp->cpu_id, err); 202 mutex_exit(&cmi_load_lock); 203 return (-1); 204 } 205 206 ASSERT(cp->cpu_m.mcpu_cmi == NULL); 207 cp->cpu_m.mcpu_cmi = cmi; 208 cp->cpu_m.mcpu_cmidata = data; 209 210 cmi->cmi_refcnt++; 211 mutex_exit(&cmi_load_lock); 212 213 if (boothowto & RB_VERBOSE) { 214 printf("cpuid %d: initialized cpumod: %s\n", 215 cp->cpu_id, cmi->cmi_modp->mod_modname); 216 } 217 218 return (0); 219 } 220 221 void 222 cmi_init(void) 223 { 224 if (cmi_load(CPU) < 0) 225 panic("failed to load module for CPU %u", CPU->cpu_id); 226 } 227 228 void 229 cmi_post_init(void) 230 { 231 CMI_OPS(CPU)->cmi_post_init(CMI_DATA(CPU)); 232 } 233 234 void 235 cmi_post_mpstartup(void) 236 { 237 CMI_OPS(CPU)->cmi_post_mpstartup(CMI_DATA(CPU)); 238 } 239 240 void 241 cmi_faulted_enter(cpu_t *cp) 242 { 243 CMI_OPS(cp)->cmi_faulted_enter(CMI_DATA(cp)); 244 } 245 246 void 247 cmi_faulted_exit(cpu_t *cp) 248 { 249 CMI_OPS(cp)->cmi_faulted_exit(CMI_DATA(cp)); 250 } 251 252 int 253 cmi_scrubber_enable(cpu_t *cp, uint64_t base, uint64_t ilen) 254 { 255 return (CMI_OPS(cp)->cmi_scrubber_enable(CMI_DATA(cp), base, ilen)); 256 } 257 258 void 259 cmi_mca_init(void) 260 { 261 CMI_OPS(CPU)->cmi_mca_init(CMI_DATA(CPU)); 262 } 263 264 void 265 cmi_mca_trap(struct regs *rp) 266 { 267 if (CMI_OPS(CPU)->cmi_mca_trap(CMI_DATA(CPU), rp)) { 268 if (cmi_panic_on_uncorrectable_error) 269 fm_panic("Unrecoverable Machine-Check Exception"); 270 else 271 cmn_err(CE_WARN, "suppressing panic from fatal #mc"); 272 } 273 } 274 275 int 276 cmi_mca_inject(cmi_mca_regs_t *regs, uint_t nregs) 277 { 278 int err; 279 280 kpreempt_disable(); 281 err = CMI_OPS(CPU)->cmi_mca_inject(CMI_DATA(CPU), regs, nregs); 282 kpreempt_enable(); 283 284 return (err); 285 } 286 287 void 288 cmi_mca_poke(void) 289 { 290 CMI_OPS(CPU)->cmi_mca_poke(CMI_DATA(CPU)); 291 } 292 293 void 294 cmi_mc_register(cpu_t *cp, const cmi_mc_ops_t *mcops, void *mcdata) 295 { 296 CMI_OPS(cp)->cmi_mc_register(CMI_DATA(cp), mcops, mcdata); 297 } 298 299 int 300 cmi_mc_patounum(uint64_t pa, uint32_t synd, int syndtype, mc_unum_t *up) 301 { 302 const struct cmi_mc_ops *mcops; 303 cpu_t *cp = CPU; 304 305 if (CMI_OPS(cp) == NULL || 306 (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL) 307 return (-1); /* not registered yet */ 308 309 return (mcops->cmi_mc_patounum(CMI_DATA(cp), pa, synd, syndtype, up)); 310 } 311 312 int 313 cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap) 314 { 315 const struct cmi_mc_ops *mcops; 316 cpu_t *cp = CPU; 317 318 if (up != NULL && nvl != NULL) 319 return (-1); /* only convert from one or the other form */ 320 321 if (CMI_OPS(cp) == NULL || 322 (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL) 323 return (-1); /* not registered yet */ 324 325 return (mcops->cmi_mc_unumtopa(CMI_DATA(cp), up, nvl, pap)); 326 } 327