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