| Borislav Petkov | b70ef01 | 2009-06-25 19:32:38 +0200 | [diff] [blame] | 1 | #include <linux/module.h> | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 2 | #include <linux/slab.h> | 
|  | 3 |  | 
| Borislav Petkov | 47ca08a | 2010-09-27 15:30:39 +0200 | [diff] [blame] | 4 | #include "mce_amd.h" | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 5 |  | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 6 | static struct amd_decoder_ops *fam_ops; | 
|  | 7 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 8 | static u8 nb_err_cpumask = 0xf; | 
|  | 9 |  | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 10 | static bool report_gart_errors; | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 11 | static void (*nb_bus_decoder)(int node_id, struct mce *m, u32 nbcfg); | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 12 |  | 
|  | 13 | void amd_report_gart_errors(bool v) | 
|  | 14 | { | 
|  | 15 | report_gart_errors = v; | 
|  | 16 | } | 
|  | 17 | EXPORT_SYMBOL_GPL(amd_report_gart_errors); | 
|  | 18 |  | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 19 | void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32)) | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 20 | { | 
|  | 21 | nb_bus_decoder = f; | 
|  | 22 | } | 
|  | 23 | EXPORT_SYMBOL_GPL(amd_register_ecc_decoder); | 
|  | 24 |  | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 25 | void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32)) | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 26 | { | 
|  | 27 | if (nb_bus_decoder) { | 
|  | 28 | WARN_ON(nb_bus_decoder != f); | 
|  | 29 |  | 
|  | 30 | nb_bus_decoder = NULL; | 
|  | 31 | } | 
|  | 32 | } | 
|  | 33 | EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder); | 
|  | 34 |  | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 35 | /* | 
|  | 36 | * string representation for the different MCA reported error types, see F3x48 | 
|  | 37 | * or MSR0000_0411. | 
|  | 38 | */ | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 39 |  | 
|  | 40 | /* transaction type */ | 
|  | 41 | const char *tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" }; | 
| Borislav Petkov | b70ef01 | 2009-06-25 19:32:38 +0200 | [diff] [blame] | 42 | EXPORT_SYMBOL_GPL(tt_msgs); | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 43 |  | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 44 | /* cache level */ | 
|  | 45 | const char *ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" }; | 
| Borislav Petkov | b70ef01 | 2009-06-25 19:32:38 +0200 | [diff] [blame] | 46 | EXPORT_SYMBOL_GPL(ll_msgs); | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 47 |  | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 48 | /* memory transaction type */ | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 49 | const char *rrrr_msgs[] = { | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 50 | "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP" | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 51 | }; | 
| Borislav Petkov | b70ef01 | 2009-06-25 19:32:38 +0200 | [diff] [blame] | 52 | EXPORT_SYMBOL_GPL(rrrr_msgs); | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 53 |  | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 54 | /* participating processor */ | 
|  | 55 | const char *pp_msgs[] = { "SRC", "RES", "OBS", "GEN" }; | 
| Borislav Petkov | b70ef01 | 2009-06-25 19:32:38 +0200 | [diff] [blame] | 56 | EXPORT_SYMBOL_GPL(pp_msgs); | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 57 |  | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 58 | /* request timeout */ | 
|  | 59 | const char *to_msgs[] = { "no timeout",	"timed out" }; | 
| Borislav Petkov | b70ef01 | 2009-06-25 19:32:38 +0200 | [diff] [blame] | 60 | EXPORT_SYMBOL_GPL(to_msgs); | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 61 |  | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 62 | /* memory or i/o */ | 
|  | 63 | const char *ii_msgs[] = { "MEM", "RESV", "IO", "GEN" }; | 
| Borislav Petkov | b70ef01 | 2009-06-25 19:32:38 +0200 | [diff] [blame] | 64 | EXPORT_SYMBOL_GPL(ii_msgs); | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 65 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 66 | static const char *f10h_nb_mce_desc[] = { | 
|  | 67 | "HT link data error", | 
|  | 68 | "Protocol error (link, L3, probe filter, etc.)", | 
|  | 69 | "Parity error in NB-internal arrays", | 
|  | 70 | "Link Retry due to IO link transmission error", | 
|  | 71 | "L3 ECC data cache error", | 
|  | 72 | "ECC error in L3 cache tag", | 
|  | 73 | "L3 LRU parity bits error", | 
|  | 74 | "ECC Error in the Probe Filter directory" | 
| Doug Thompson | b52401c | 2009-05-06 17:57:20 +0200 | [diff] [blame] | 75 | }; | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 76 |  | 
| Borislav Petkov | 9be0bb1 | 2010-09-16 15:08:14 +0200 | [diff] [blame] | 77 | static bool f12h_dc_mce(u16 ec) | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 78 | { | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 79 | bool ret = false; | 
|  | 80 |  | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 81 | if (MEM_ERROR(ec)) { | 
|  | 82 | u8 ll = ec & 0x3; | 
|  | 83 | ret = true; | 
|  | 84 |  | 
|  | 85 | if (ll == LL_L2) | 
|  | 86 | pr_cont("during L1 linefill from L2.\n"); | 
|  | 87 | else if (ll == LL_L1) | 
|  | 88 | pr_cont("Data/Tag %s error.\n", RRRR_MSG(ec)); | 
|  | 89 | else | 
|  | 90 | ret = false; | 
|  | 91 | } | 
|  | 92 | return ret; | 
|  | 93 | } | 
|  | 94 |  | 
| Borislav Petkov | 9be0bb1 | 2010-09-16 15:08:14 +0200 | [diff] [blame] | 95 | static bool f10h_dc_mce(u16 ec) | 
|  | 96 | { | 
|  | 97 | u8 r4  = (ec >> 4) & 0xf; | 
|  | 98 | u8 ll  = ec & 0x3; | 
|  | 99 |  | 
|  | 100 | if (r4 == R4_GEN && ll == LL_L1) { | 
|  | 101 | pr_cont("during data scrub.\n"); | 
|  | 102 | return true; | 
|  | 103 | } | 
|  | 104 | return f12h_dc_mce(ec); | 
|  | 105 | } | 
|  | 106 |  | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 107 | static bool k8_dc_mce(u16 ec) | 
|  | 108 | { | 
|  | 109 | if (BUS_ERROR(ec)) { | 
|  | 110 | pr_cont("during system linefill.\n"); | 
|  | 111 | return true; | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | return f10h_dc_mce(ec); | 
|  | 115 | } | 
|  | 116 |  | 
|  | 117 | static bool f14h_dc_mce(u16 ec) | 
|  | 118 | { | 
|  | 119 | u8 r4	 = (ec >> 4) & 0xf; | 
|  | 120 | u8 ll	 = ec & 0x3; | 
|  | 121 | u8 tt	 = (ec >> 2) & 0x3; | 
|  | 122 | u8 ii	 = tt; | 
|  | 123 | bool ret = true; | 
|  | 124 |  | 
|  | 125 | if (MEM_ERROR(ec)) { | 
|  | 126 |  | 
|  | 127 | if (tt != TT_DATA || ll != LL_L1) | 
|  | 128 | return false; | 
|  | 129 |  | 
|  | 130 | switch (r4) { | 
|  | 131 | case R4_DRD: | 
|  | 132 | case R4_DWR: | 
|  | 133 | pr_cont("Data/Tag parity error due to %s.\n", | 
|  | 134 | (r4 == R4_DRD ? "load/hw prf" : "store")); | 
|  | 135 | break; | 
|  | 136 | case R4_EVICT: | 
|  | 137 | pr_cont("Copyback parity error on a tag miss.\n"); | 
|  | 138 | break; | 
|  | 139 | case R4_SNOOP: | 
|  | 140 | pr_cont("Tag parity error during snoop.\n"); | 
|  | 141 | break; | 
|  | 142 | default: | 
|  | 143 | ret = false; | 
|  | 144 | } | 
|  | 145 | } else if (BUS_ERROR(ec)) { | 
|  | 146 |  | 
|  | 147 | if ((ii != II_MEM && ii != II_IO) || ll != LL_LG) | 
|  | 148 | return false; | 
|  | 149 |  | 
|  | 150 | pr_cont("System read data error on a "); | 
|  | 151 |  | 
|  | 152 | switch (r4) { | 
|  | 153 | case R4_RD: | 
|  | 154 | pr_cont("TLB reload.\n"); | 
|  | 155 | break; | 
|  | 156 | case R4_DWR: | 
|  | 157 | pr_cont("store.\n"); | 
|  | 158 | break; | 
|  | 159 | case R4_DRD: | 
|  | 160 | pr_cont("load.\n"); | 
|  | 161 | break; | 
|  | 162 | default: | 
|  | 163 | ret = false; | 
|  | 164 | } | 
|  | 165 | } else { | 
|  | 166 | ret = false; | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | return ret; | 
|  | 170 | } | 
|  | 171 |  | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 172 | static void amd_decode_dc_mce(struct mce *m) | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 173 | { | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 174 | u16 ec = m->status & 0xffff; | 
|  | 175 | u8 xec = (m->status >> 16) & 0xf; | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 176 |  | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 177 | pr_emerg(HW_ERR "Data Cache Error: "); | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 178 |  | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 179 | /* TLB error signatures are the same across families */ | 
|  | 180 | if (TLB_ERROR(ec)) { | 
|  | 181 | u8 tt = (ec >> 2) & 0x3; | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 182 |  | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 183 | if (tt == TT_DATA) { | 
|  | 184 | pr_cont("%s TLB %s.\n", LL_MSG(ec), | 
|  | 185 | (xec ? "multimatch" : "parity error")); | 
|  | 186 | return; | 
|  | 187 | } | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 188 | else | 
|  | 189 | goto wrong_dc_mce; | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 190 | } | 
|  | 191 |  | 
|  | 192 | if (!fam_ops->dc_mce(ec)) | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 193 | goto wrong_dc_mce; | 
|  | 194 |  | 
|  | 195 | return; | 
|  | 196 |  | 
|  | 197 | wrong_dc_mce: | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 198 | pr_emerg(HW_ERR "Corrupted DC MCE info?\n"); | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 199 | } | 
|  | 200 |  | 
| Borislav Petkov | dd53bce | 2010-08-26 19:05:49 +0200 | [diff] [blame] | 201 | static bool k8_ic_mce(u16 ec) | 
|  | 202 | { | 
|  | 203 | u8 ll	 = ec & 0x3; | 
|  | 204 | u8 r4	 = (ec >> 4) & 0xf; | 
|  | 205 | bool ret = true; | 
|  | 206 |  | 
|  | 207 | if (!MEM_ERROR(ec)) | 
|  | 208 | return false; | 
|  | 209 |  | 
|  | 210 | if (ll == 0x2) | 
|  | 211 | pr_cont("during a linefill from L2.\n"); | 
|  | 212 | else if (ll == 0x1) { | 
|  | 213 | switch (r4) { | 
|  | 214 | case R4_IRD: | 
|  | 215 | pr_cont("Parity error during data load.\n"); | 
|  | 216 | break; | 
|  | 217 |  | 
|  | 218 | case R4_EVICT: | 
|  | 219 | pr_cont("Copyback Parity/Victim error.\n"); | 
|  | 220 | break; | 
|  | 221 |  | 
|  | 222 | case R4_SNOOP: | 
|  | 223 | pr_cont("Tag Snoop error.\n"); | 
|  | 224 | break; | 
|  | 225 |  | 
|  | 226 | default: | 
|  | 227 | ret = false; | 
|  | 228 | break; | 
|  | 229 | } | 
|  | 230 | } else | 
|  | 231 | ret = false; | 
|  | 232 |  | 
|  | 233 | return ret; | 
|  | 234 | } | 
|  | 235 |  | 
|  | 236 | static bool f14h_ic_mce(u16 ec) | 
|  | 237 | { | 
|  | 238 | u8 ll    = ec & 0x3; | 
|  | 239 | u8 tt    = (ec >> 2) & 0x3; | 
|  | 240 | u8 r4  = (ec >> 4) & 0xf; | 
|  | 241 | bool ret = true; | 
|  | 242 |  | 
|  | 243 | if (MEM_ERROR(ec)) { | 
|  | 244 | if (tt != 0 || ll != 1) | 
|  | 245 | ret = false; | 
|  | 246 |  | 
|  | 247 | if (r4 == R4_IRD) | 
|  | 248 | pr_cont("Data/tag array parity error for a tag hit.\n"); | 
|  | 249 | else if (r4 == R4_SNOOP) | 
|  | 250 | pr_cont("Tag error during snoop/victimization.\n"); | 
|  | 251 | else | 
|  | 252 | ret = false; | 
|  | 253 | } | 
|  | 254 | return ret; | 
|  | 255 | } | 
|  | 256 |  | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 257 | static void amd_decode_ic_mce(struct mce *m) | 
| Borislav Petkov | ab5535e | 2009-07-28 14:06:26 +0200 | [diff] [blame] | 258 | { | 
| Borislav Petkov | dd53bce | 2010-08-26 19:05:49 +0200 | [diff] [blame] | 259 | u16 ec = m->status & 0xffff; | 
|  | 260 | u8 xec = (m->status >> 16) & 0xf; | 
| Borislav Petkov | ab5535e | 2009-07-28 14:06:26 +0200 | [diff] [blame] | 261 |  | 
| Borislav Petkov | dd53bce | 2010-08-26 19:05:49 +0200 | [diff] [blame] | 262 | pr_emerg(HW_ERR "Instruction Cache Error: "); | 
| Borislav Petkov | ab5535e | 2009-07-28 14:06:26 +0200 | [diff] [blame] | 263 |  | 
| Borislav Petkov | dd53bce | 2010-08-26 19:05:49 +0200 | [diff] [blame] | 264 | if (TLB_ERROR(ec)) | 
|  | 265 | pr_cont("%s TLB %s.\n", LL_MSG(ec), | 
|  | 266 | (xec ? "multimatch" : "parity error")); | 
|  | 267 | else if (BUS_ERROR(ec)) { | 
| Borislav Petkov | 525906b | 2010-10-15 15:27:02 +0200 | [diff] [blame] | 268 | bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58))); | 
| Borislav Petkov | ab5535e | 2009-07-28 14:06:26 +0200 | [diff] [blame] | 269 |  | 
| Borislav Petkov | dd53bce | 2010-08-26 19:05:49 +0200 | [diff] [blame] | 270 | pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read")); | 
|  | 271 | } else if (fam_ops->ic_mce(ec)) | 
|  | 272 | ; | 
|  | 273 | else | 
|  | 274 | pr_emerg(HW_ERR "Corrupted IC MCE info?\n"); | 
| Borislav Petkov | ab5535e | 2009-07-28 14:06:26 +0200 | [diff] [blame] | 275 | } | 
|  | 276 |  | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 277 | static void amd_decode_bu_mce(struct mce *m) | 
| Borislav Petkov | 56cad2d | 2009-07-28 14:14:24 +0200 | [diff] [blame] | 278 | { | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 279 | u32 ec = m->status & 0xffff; | 
|  | 280 | u32 xec = (m->status >> 16) & 0xf; | 
| Borislav Petkov | 56cad2d | 2009-07-28 14:14:24 +0200 | [diff] [blame] | 281 |  | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 282 | pr_emerg(HW_ERR "Bus Unit Error"); | 
| Borislav Petkov | 56cad2d | 2009-07-28 14:14:24 +0200 | [diff] [blame] | 283 |  | 
|  | 284 | if (xec == 0x1) | 
|  | 285 | pr_cont(" in the write data buffers.\n"); | 
|  | 286 | else if (xec == 0x3) | 
|  | 287 | pr_cont(" in the victim data buffers.\n"); | 
|  | 288 | else if (xec == 0x2 && MEM_ERROR(ec)) | 
|  | 289 | pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec)); | 
|  | 290 | else if (xec == 0x0) { | 
|  | 291 | if (TLB_ERROR(ec)) | 
|  | 292 | pr_cont(": %s error in a Page Descriptor Cache or " | 
|  | 293 | "Guest TLB.\n", TT_MSG(ec)); | 
|  | 294 | else if (BUS_ERROR(ec)) | 
|  | 295 | pr_cont(": %s/ECC error in data read from NB: %s.\n", | 
|  | 296 | RRRR_MSG(ec), PP_MSG(ec)); | 
|  | 297 | else if (MEM_ERROR(ec)) { | 
|  | 298 | u8 rrrr = (ec >> 4) & 0xf; | 
|  | 299 |  | 
|  | 300 | if (rrrr >= 0x7) | 
|  | 301 | pr_cont(": %s error during data copyback.\n", | 
|  | 302 | RRRR_MSG(ec)); | 
|  | 303 | else if (rrrr <= 0x1) | 
|  | 304 | pr_cont(": %s parity/ECC error during data " | 
|  | 305 | "access from L2.\n", RRRR_MSG(ec)); | 
|  | 306 | else | 
|  | 307 | goto wrong_bu_mce; | 
|  | 308 | } else | 
|  | 309 | goto wrong_bu_mce; | 
|  | 310 | } else | 
|  | 311 | goto wrong_bu_mce; | 
|  | 312 |  | 
|  | 313 | return; | 
|  | 314 |  | 
|  | 315 | wrong_bu_mce: | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 316 | pr_emerg(HW_ERR "Corrupted BU MCE info?\n"); | 
| Borislav Petkov | 56cad2d | 2009-07-28 14:14:24 +0200 | [diff] [blame] | 317 | } | 
|  | 318 |  | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 319 | static void amd_decode_ls_mce(struct mce *m) | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 320 | { | 
| Borislav Petkov | ded5062 | 2010-08-27 17:03:34 +0200 | [diff] [blame] | 321 | u16 ec = m->status & 0xffff; | 
|  | 322 | u8 xec = (m->status >> 16) & 0xf; | 
|  | 323 |  | 
|  | 324 | if (boot_cpu_data.x86 == 0x14) { | 
|  | 325 | pr_emerg("You shouldn't be seeing an LS MCE on this cpu family," | 
|  | 326 | " please report on LKML.\n"); | 
|  | 327 | return; | 
|  | 328 | } | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 329 |  | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 330 | pr_emerg(HW_ERR "Load Store Error"); | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 331 |  | 
|  | 332 | if (xec == 0x0) { | 
| Borislav Petkov | ded5062 | 2010-08-27 17:03:34 +0200 | [diff] [blame] | 333 | u8 r4 = (ec >> 4) & 0xf; | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 334 |  | 
| Borislav Petkov | ded5062 | 2010-08-27 17:03:34 +0200 | [diff] [blame] | 335 | if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR)) | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 336 | goto wrong_ls_mce; | 
|  | 337 |  | 
|  | 338 | pr_cont(" during %s.\n", RRRR_MSG(ec)); | 
| Borislav Petkov | ded5062 | 2010-08-27 17:03:34 +0200 | [diff] [blame] | 339 | } else | 
|  | 340 | goto wrong_ls_mce; | 
|  | 341 |  | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 342 | return; | 
|  | 343 |  | 
|  | 344 | wrong_ls_mce: | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 345 | pr_emerg(HW_ERR "Corrupted LS MCE info?\n"); | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 346 | } | 
|  | 347 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 348 | static bool k8_nb_mce(u16 ec, u8 xec) | 
|  | 349 | { | 
|  | 350 | bool ret = true; | 
|  | 351 |  | 
|  | 352 | switch (xec) { | 
|  | 353 | case 0x1: | 
|  | 354 | pr_cont("CRC error detected on HT link.\n"); | 
|  | 355 | break; | 
|  | 356 |  | 
|  | 357 | case 0x5: | 
|  | 358 | pr_cont("Invalid GART PTE entry during GART table walk.\n"); | 
|  | 359 | break; | 
|  | 360 |  | 
|  | 361 | case 0x6: | 
|  | 362 | pr_cont("Unsupported atomic RMW received from an IO link.\n"); | 
|  | 363 | break; | 
|  | 364 |  | 
|  | 365 | case 0x0: | 
|  | 366 | case 0x8: | 
| Borislav Petkov | f0157b3 | 2010-10-05 19:07:16 +0200 | [diff] [blame] | 367 | if (boot_cpu_data.x86 == 0x11) | 
|  | 368 | return false; | 
|  | 369 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 370 | pr_cont("DRAM ECC error detected on the NB.\n"); | 
|  | 371 | break; | 
|  | 372 |  | 
|  | 373 | case 0xd: | 
|  | 374 | pr_cont("Parity error on the DRAM addr/ctl signals.\n"); | 
|  | 375 | break; | 
|  | 376 |  | 
|  | 377 | default: | 
|  | 378 | ret = false; | 
|  | 379 | break; | 
|  | 380 | } | 
|  | 381 |  | 
|  | 382 | return ret; | 
|  | 383 | } | 
|  | 384 |  | 
|  | 385 | static bool f10h_nb_mce(u16 ec, u8 xec) | 
|  | 386 | { | 
|  | 387 | bool ret = true; | 
|  | 388 | u8 offset = 0; | 
|  | 389 |  | 
|  | 390 | if (k8_nb_mce(ec, xec)) | 
|  | 391 | return true; | 
|  | 392 |  | 
|  | 393 | switch(xec) { | 
|  | 394 | case 0xa ... 0xc: | 
|  | 395 | offset = 10; | 
|  | 396 | break; | 
|  | 397 |  | 
|  | 398 | case 0xe: | 
|  | 399 | offset = 11; | 
|  | 400 | break; | 
|  | 401 |  | 
|  | 402 | case 0xf: | 
|  | 403 | if (TLB_ERROR(ec)) | 
|  | 404 | pr_cont("GART Table Walk data error.\n"); | 
|  | 405 | else if (BUS_ERROR(ec)) | 
|  | 406 | pr_cont("DMA Exclusion Vector Table Walk error.\n"); | 
|  | 407 | else | 
|  | 408 | ret = false; | 
|  | 409 |  | 
|  | 410 | goto out; | 
|  | 411 | break; | 
|  | 412 |  | 
|  | 413 | case 0x1c ... 0x1f: | 
|  | 414 | offset = 24; | 
|  | 415 | break; | 
|  | 416 |  | 
|  | 417 | default: | 
|  | 418 | ret = false; | 
|  | 419 |  | 
|  | 420 | goto out; | 
|  | 421 | break; | 
|  | 422 | } | 
|  | 423 |  | 
|  | 424 | pr_cont("%s.\n", f10h_nb_mce_desc[xec - offset]); | 
|  | 425 |  | 
|  | 426 | out: | 
|  | 427 | return ret; | 
|  | 428 | } | 
|  | 429 |  | 
| Borislav Petkov | cb9d5ec | 2010-09-16 17:36:12 +0200 | [diff] [blame] | 430 | static bool nb_noop_mce(u16 ec, u8 xec) | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 431 | { | 
|  | 432 | return false; | 
|  | 433 | } | 
|  | 434 |  | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 435 | void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg) | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 436 | { | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 437 | u8 xec   = (m->status >> 16) & 0x1f; | 
|  | 438 | u16 ec   = m->status & 0xffff; | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 439 | u32 nbsh = (u32)(m->status >> 32); | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 440 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 441 | pr_emerg(HW_ERR "Northbridge Error, node %d: ", node_id); | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 442 |  | 
|  | 443 | /* | 
|  | 444 | * F10h, revD can disable ErrCpu[3:0] so check that first and also the | 
|  | 445 | * value encoding has changed so interpret those differently | 
|  | 446 | */ | 
|  | 447 | if ((boot_cpu_data.x86 == 0x10) && | 
| Borislav Petkov | cec7924 | 2009-10-27 19:12:02 +0100 | [diff] [blame] | 448 | (boot_cpu_data.x86_model > 7)) { | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 449 | if (nbsh & K8_NBSH_ERR_CPU_VAL) | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 450 | pr_cont(", core: %u", (u8)(nbsh & nb_err_cpumask)); | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 451 | } else { | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 452 | u8 assoc_cpus = nbsh & nb_err_cpumask; | 
| Borislav Petkov | 5b89d2f | 2010-03-09 20:38:48 +0100 | [diff] [blame] | 453 |  | 
|  | 454 | if (assoc_cpus > 0) | 
|  | 455 | pr_cont(", core: %d", fls(assoc_cpus) - 1); | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 456 | } | 
|  | 457 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 458 | switch (xec) { | 
|  | 459 | case 0x2: | 
|  | 460 | pr_cont("Sync error (sync packets on HT link detected).\n"); | 
|  | 461 | return; | 
| Borislav Petkov | d93cc22 | 2009-07-28 10:56:15 +0200 | [diff] [blame] | 462 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 463 | case 0x3: | 
|  | 464 | pr_cont("HT Master abort.\n"); | 
|  | 465 | return; | 
|  | 466 |  | 
|  | 467 | case 0x4: | 
|  | 468 | pr_cont("HT Target abort.\n"); | 
|  | 469 | return; | 
|  | 470 |  | 
|  | 471 | case 0x7: | 
|  | 472 | pr_cont("NB Watchdog timeout.\n"); | 
|  | 473 | return; | 
|  | 474 |  | 
|  | 475 | case 0x9: | 
|  | 476 | pr_cont("SVM DMA Exclusion Vector error.\n"); | 
|  | 477 | return; | 
|  | 478 |  | 
|  | 479 | default: | 
|  | 480 | break; | 
|  | 481 | } | 
|  | 482 |  | 
|  | 483 | if (!fam_ops->nb_mce(ec, xec)) | 
|  | 484 | goto wrong_nb_mce; | 
|  | 485 |  | 
|  | 486 | if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10) | 
|  | 487 | if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder) | 
|  | 488 | nb_bus_decoder(node_id, m, nbcfg); | 
|  | 489 |  | 
|  | 490 | return; | 
|  | 491 |  | 
|  | 492 | wrong_nb_mce: | 
|  | 493 | pr_emerg(HW_ERR "Corrupted NB MCE info?\n"); | 
| Borislav Petkov | d93cc22 | 2009-07-28 10:56:15 +0200 | [diff] [blame] | 494 | } | 
|  | 495 | EXPORT_SYMBOL_GPL(amd_decode_nb_mce); | 
|  | 496 |  | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 497 | static void amd_decode_fr_mce(struct mce *m) | 
| Borislav Petkov | 53bd5fe | 2009-07-28 14:20:46 +0200 | [diff] [blame] | 498 | { | 
| Borislav Petkov | f0157b3 | 2010-10-05 19:07:16 +0200 | [diff] [blame] | 499 | if (boot_cpu_data.x86 == 0xf || | 
|  | 500 | boot_cpu_data.x86 == 0x11) | 
| Borislav Petkov | fe4ea26 | 2010-08-31 18:38:24 +0200 | [diff] [blame] | 501 | goto wrong_fr_mce; | 
|  | 502 |  | 
| Borislav Petkov | 53bd5fe | 2009-07-28 14:20:46 +0200 | [diff] [blame] | 503 | /* we have only one error signature so match all fields at once. */ | 
| Borislav Petkov | fe4ea26 | 2010-08-31 18:38:24 +0200 | [diff] [blame] | 504 | if ((m->status & 0xffff) == 0x0f0f) { | 
|  | 505 | pr_emerg(HW_ERR "FR Error: CPU Watchdog timer expire.\n"); | 
|  | 506 | return; | 
|  | 507 | } | 
|  | 508 |  | 
|  | 509 | wrong_fr_mce: | 
|  | 510 | pr_emerg(HW_ERR "Corrupted FR MCE info?\n"); | 
| Borislav Petkov | 53bd5fe | 2009-07-28 14:20:46 +0200 | [diff] [blame] | 511 | } | 
|  | 512 |  | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 513 | static inline void amd_decode_err_code(u16 ec) | 
| Borislav Petkov | d93cc22 | 2009-07-28 10:56:15 +0200 | [diff] [blame] | 514 | { | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 515 | if (TLB_ERROR(ec)) { | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 516 | pr_emerg(HW_ERR "Transaction: %s, Cache Level: %s\n", | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 517 | TT_MSG(ec), LL_MSG(ec)); | 
|  | 518 | } else if (MEM_ERROR(ec)) { | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 519 | pr_emerg(HW_ERR "Transaction: %s, Type: %s, Cache Level: %s\n", | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 520 | RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec)); | 
|  | 521 | } else if (BUS_ERROR(ec)) { | 
| Borislav Petkov | 6337583 | 2010-09-06 18:13:39 +0200 | [diff] [blame] | 522 | pr_emerg(HW_ERR "Transaction: %s (%s), %s, Cache Level: %s, " | 
| Borislav Petkov | d93cc22 | 2009-07-28 10:56:15 +0200 | [diff] [blame] | 523 | "Participating Processor: %s\n", | 
|  | 524 | RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec), | 
|  | 525 | PP_MSG(ec)); | 
|  | 526 | } else | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 527 | pr_emerg(HW_ERR "Huh? Unknown MCE error 0x%x\n", ec); | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 528 | } | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 529 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 530 | /* | 
|  | 531 | * Filter out unwanted MCE signatures here. | 
|  | 532 | */ | 
|  | 533 | static bool amd_filter_mce(struct mce *m) | 
|  | 534 | { | 
|  | 535 | u8 xec = (m->status >> 16) & 0x1f; | 
|  | 536 |  | 
|  | 537 | /* | 
|  | 538 | * NB GART TLB error reporting is disabled by default. | 
|  | 539 | */ | 
|  | 540 | if (m->bank == 4 && xec == 0x5 && !report_gart_errors) | 
|  | 541 | return true; | 
|  | 542 |  | 
|  | 543 | return false; | 
|  | 544 | } | 
|  | 545 |  | 
| Borislav Petkov | 9cdeb40 | 2010-09-02 18:33:24 +0200 | [diff] [blame] | 546 | int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 547 | { | 
| Borislav Petkov | fb25319 | 2009-10-07 13:20:38 +0200 | [diff] [blame] | 548 | struct mce *m = (struct mce *)data; | 
| Borislav Petkov | b69b29d | 2009-07-27 16:21:14 +0200 | [diff] [blame] | 549 | int node, ecc; | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 550 |  | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 551 | if (amd_filter_mce(m)) | 
|  | 552 | return NOTIFY_STOP; | 
|  | 553 |  | 
| Borislav Petkov | c9f281f | 2010-08-18 18:21:42 +0200 | [diff] [blame] | 554 | pr_emerg(HW_ERR "MC%d_STATUS: ", m->bank); | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 555 |  | 
| Borislav Petkov | 37b7370 | 2010-08-24 18:21:42 +0200 | [diff] [blame] | 556 | pr_cont("%sorrected error, other errors lost: %s, " | 
| Borislav Petkov | b69b29d | 2009-07-27 16:21:14 +0200 | [diff] [blame] | 557 | "CPU context corrupt: %s", | 
|  | 558 | ((m->status & MCI_STATUS_UC) ? "Unc"  : "C"), | 
| Borislav Petkov | 37b7370 | 2010-08-24 18:21:42 +0200 | [diff] [blame] | 559 | ((m->status & MCI_STATUS_OVER) ? "yes"  : "no"), | 
| Borislav Petkov | b69b29d | 2009-07-27 16:21:14 +0200 | [diff] [blame] | 560 | ((m->status & MCI_STATUS_PCC) ? "yes" : "no")); | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 561 |  | 
| Borislav Petkov | b69b29d | 2009-07-27 16:21:14 +0200 | [diff] [blame] | 562 | /* do the two bits[14:13] together */ | 
| Borislav Petkov | 35d824b | 2010-04-30 15:19:02 +0200 | [diff] [blame] | 563 | ecc = (m->status >> 45) & 0x3; | 
| Borislav Petkov | b69b29d | 2009-07-27 16:21:14 +0200 | [diff] [blame] | 564 | if (ecc) | 
|  | 565 | pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U")); | 
|  | 566 |  | 
|  | 567 | pr_cont("\n"); | 
|  | 568 |  | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 569 | switch (m->bank) { | 
|  | 570 | case 0: | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 571 | amd_decode_dc_mce(m); | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 572 | break; | 
| Borislav Petkov | d93cc22 | 2009-07-28 10:56:15 +0200 | [diff] [blame] | 573 |  | 
| Borislav Petkov | ab5535e | 2009-07-28 14:06:26 +0200 | [diff] [blame] | 574 | case 1: | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 575 | amd_decode_ic_mce(m); | 
| Borislav Petkov | ab5535e | 2009-07-28 14:06:26 +0200 | [diff] [blame] | 576 | break; | 
|  | 577 |  | 
| Borislav Petkov | 56cad2d | 2009-07-28 14:14:24 +0200 | [diff] [blame] | 578 | case 2: | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 579 | amd_decode_bu_mce(m); | 
| Borislav Petkov | 56cad2d | 2009-07-28 14:14:24 +0200 | [diff] [blame] | 580 | break; | 
|  | 581 |  | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 582 | case 3: | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 583 | amd_decode_ls_mce(m); | 
| Borislav Petkov | f9350ef | 2009-07-28 14:17:30 +0200 | [diff] [blame] | 584 | break; | 
|  | 585 |  | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 586 | case 4: | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 587 | node = amd_get_nb_id(m->extcpu); | 
|  | 588 | amd_decode_nb_mce(node, m, 0); | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 589 | break; | 
|  | 590 |  | 
| Borislav Petkov | 53bd5fe | 2009-07-28 14:20:46 +0200 | [diff] [blame] | 591 | case 5: | 
| Borislav Petkov | 7cfd4a8 | 2010-09-01 14:45:20 +0200 | [diff] [blame] | 592 | amd_decode_fr_mce(m); | 
| Borislav Petkov | 53bd5fe | 2009-07-28 14:20:46 +0200 | [diff] [blame] | 593 | break; | 
|  | 594 |  | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 595 | default: | 
|  | 596 | break; | 
| Borislav Petkov | b69b29d | 2009-07-27 16:21:14 +0200 | [diff] [blame] | 597 | } | 
| Borislav Petkov | 5196624 | 2009-07-28 13:50:43 +0200 | [diff] [blame] | 598 |  | 
|  | 599 | amd_decode_err_code(m->status & 0xffff); | 
| Borislav Petkov | fb25319 | 2009-10-07 13:20:38 +0200 | [diff] [blame] | 600 |  | 
|  | 601 | return NOTIFY_STOP; | 
| Borislav Petkov | 549d042 | 2009-07-24 13:51:42 +0200 | [diff] [blame] | 602 | } | 
| Borislav Petkov | 9cdeb40 | 2010-09-02 18:33:24 +0200 | [diff] [blame] | 603 | EXPORT_SYMBOL_GPL(amd_decode_mce); | 
| Ingo Molnar | f436f8b | 2009-10-01 16:14:32 +0200 | [diff] [blame] | 604 |  | 
| Borislav Petkov | fb25319 | 2009-10-07 13:20:38 +0200 | [diff] [blame] | 605 | static struct notifier_block amd_mce_dec_nb = { | 
|  | 606 | .notifier_call	= amd_decode_mce, | 
|  | 607 | }; | 
|  | 608 |  | 
| Ingo Molnar | f436f8b | 2009-10-01 16:14:32 +0200 | [diff] [blame] | 609 | static int __init mce_amd_init(void) | 
|  | 610 | { | 
| Borislav Petkov | e045c29 | 2010-08-06 18:55:45 +0200 | [diff] [blame] | 611 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) | 
|  | 612 | return 0; | 
|  | 613 |  | 
| Borislav Petkov | fda7561 | 2010-09-22 16:12:03 +0200 | [diff] [blame] | 614 | if ((boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x12) && | 
| Borislav Petkov | 9530d60 | 2010-09-06 15:05:45 +0200 | [diff] [blame] | 615 | (boot_cpu_data.x86 != 0x14 || boot_cpu_data.x86_model > 0xf)) | 
| Borislav Petkov | e045c29 | 2010-08-06 18:55:45 +0200 | [diff] [blame] | 616 | return 0; | 
|  | 617 |  | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 618 | fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL); | 
|  | 619 | if (!fam_ops) | 
|  | 620 | return -ENOMEM; | 
|  | 621 |  | 
|  | 622 | switch (boot_cpu_data.x86) { | 
|  | 623 | case 0xf: | 
|  | 624 | fam_ops->dc_mce = k8_dc_mce; | 
| Borislav Petkov | dd53bce | 2010-08-26 19:05:49 +0200 | [diff] [blame] | 625 | fam_ops->ic_mce = k8_ic_mce; | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 626 | fam_ops->nb_mce = k8_nb_mce; | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 627 | break; | 
|  | 628 |  | 
|  | 629 | case 0x10: | 
|  | 630 | fam_ops->dc_mce = f10h_dc_mce; | 
| Borislav Petkov | dd53bce | 2010-08-26 19:05:49 +0200 | [diff] [blame] | 631 | fam_ops->ic_mce = k8_ic_mce; | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 632 | fam_ops->nb_mce = f10h_nb_mce; | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 633 | break; | 
|  | 634 |  | 
| Borislav Petkov | f0157b3 | 2010-10-05 19:07:16 +0200 | [diff] [blame] | 635 | case 0x11: | 
|  | 636 | fam_ops->dc_mce = k8_dc_mce; | 
|  | 637 | fam_ops->ic_mce = k8_ic_mce; | 
|  | 638 | fam_ops->nb_mce = f10h_nb_mce; | 
|  | 639 | break; | 
|  | 640 |  | 
| Borislav Petkov | 9be0bb1 | 2010-09-16 15:08:14 +0200 | [diff] [blame] | 641 | case 0x12: | 
|  | 642 | fam_ops->dc_mce = f12h_dc_mce; | 
| Borislav Petkov | e7281eb | 2010-09-16 16:45:22 +0200 | [diff] [blame] | 643 | fam_ops->ic_mce = k8_ic_mce; | 
| Borislav Petkov | cb9d5ec | 2010-09-16 17:36:12 +0200 | [diff] [blame] | 644 | fam_ops->nb_mce = nb_noop_mce; | 
| Borislav Petkov | 9be0bb1 | 2010-09-16 15:08:14 +0200 | [diff] [blame] | 645 | break; | 
|  | 646 |  | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 647 | case 0x14: | 
| Borislav Petkov | 5ce88f6 | 2010-08-31 18:28:08 +0200 | [diff] [blame] | 648 | nb_err_cpumask  = 0x3; | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 649 | fam_ops->dc_mce = f14h_dc_mce; | 
| Borislav Petkov | dd53bce | 2010-08-26 19:05:49 +0200 | [diff] [blame] | 650 | fam_ops->ic_mce = f14h_ic_mce; | 
| Borislav Petkov | cb9d5ec | 2010-09-16 17:36:12 +0200 | [diff] [blame] | 651 | fam_ops->nb_mce = nb_noop_mce; | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 652 | break; | 
|  | 653 |  | 
|  | 654 | default: | 
|  | 655 | printk(KERN_WARNING "Huh? What family is that: %d?!\n", | 
|  | 656 | boot_cpu_data.x86); | 
|  | 657 | kfree(fam_ops); | 
|  | 658 | return -EINVAL; | 
|  | 659 | } | 
|  | 660 |  | 
| Borislav Petkov | 9530d60 | 2010-09-06 15:05:45 +0200 | [diff] [blame] | 661 | pr_info("MCE: In-kernel MCE decoding enabled.\n"); | 
|  | 662 |  | 
| Borislav Petkov | e045c29 | 2010-08-06 18:55:45 +0200 | [diff] [blame] | 663 | atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb); | 
| Ingo Molnar | f436f8b | 2009-10-01 16:14:32 +0200 | [diff] [blame] | 664 |  | 
|  | 665 | return 0; | 
|  | 666 | } | 
|  | 667 | early_initcall(mce_amd_init); | 
| Borislav Petkov | 0d18b2e | 2009-10-02 15:31:48 +0200 | [diff] [blame] | 668 |  | 
|  | 669 | #ifdef MODULE | 
|  | 670 | static void __exit mce_amd_exit(void) | 
|  | 671 | { | 
| Borislav Petkov | fb25319 | 2009-10-07 13:20:38 +0200 | [diff] [blame] | 672 | atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb); | 
| Borislav Petkov | 888ab8e | 2010-08-18 15:11:35 +0200 | [diff] [blame] | 673 | kfree(fam_ops); | 
| Borislav Petkov | 0d18b2e | 2009-10-02 15:31:48 +0200 | [diff] [blame] | 674 | } | 
|  | 675 |  | 
|  | 676 | MODULE_DESCRIPTION("AMD MCE decoder"); | 
|  | 677 | MODULE_ALIAS("edac-mce-amd"); | 
|  | 678 | MODULE_LICENSE("GPL"); | 
|  | 679 | module_exit(mce_amd_exit); | 
|  | 680 | #endif |