blob: e4752bec502308820ca58aa0ef76a47a7c0da980 [file] [log] [blame]
Borislav Petkovb70ef012009-06-25 19:32:38 +02001#include <linux/module.h>
Borislav Petkov888ab8e2010-08-18 15:11:35 +02002#include <linux/slab.h>
3
Borislav Petkov47ca08a2010-09-27 15:30:39 +02004#include "mce_amd.h"
Doug Thompsonb52401ce2009-05-06 17:57:20 +02005
Borislav Petkov888ab8e2010-08-18 15:11:35 +02006static struct amd_decoder_ops *fam_ops;
7
Borislav Petkov2be64bf2010-09-17 19:11:47 +02008static u8 xec_mask = 0xf;
Borislav Petkov5ce88f62010-08-31 18:28:08 +02009static u8 nb_err_cpumask = 0xf;
10
Borislav Petkov549d0422009-07-24 13:51:42 +020011static bool report_gart_errors;
Borislav Petkovb0b07a22011-08-24 18:44:22 +020012static void (*nb_bus_decoder)(int node_id, struct mce *m);
Borislav Petkov549d0422009-07-24 13:51:42 +020013
14void amd_report_gart_errors(bool v)
15{
16 report_gart_errors = v;
17}
18EXPORT_SYMBOL_GPL(amd_report_gart_errors);
19
Borislav Petkovb0b07a22011-08-24 18:44:22 +020020void amd_register_ecc_decoder(void (*f)(int, struct mce *))
Borislav Petkov549d0422009-07-24 13:51:42 +020021{
22 nb_bus_decoder = f;
23}
24EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
25
Borislav Petkovb0b07a22011-08-24 18:44:22 +020026void amd_unregister_ecc_decoder(void (*f)(int, struct mce *))
Borislav Petkov549d0422009-07-24 13:51:42 +020027{
28 if (nb_bus_decoder) {
29 WARN_ON(nb_bus_decoder != f);
30
31 nb_bus_decoder = NULL;
32 }
33}
34EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder);
35
Doug Thompsonb52401ce2009-05-06 17:57:20 +020036/*
37 * string representation for the different MCA reported error types, see F3x48
38 * or MSR0000_0411.
39 */
Borislav Petkov63375832010-09-06 18:13:39 +020040
41/* transaction type */
Borislav Petkovebe2aea2011-11-29 19:03:25 +010042const char * const tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
Borislav Petkovb70ef012009-06-25 19:32:38 +020043EXPORT_SYMBOL_GPL(tt_msgs);
Doug Thompsonb52401ce2009-05-06 17:57:20 +020044
Borislav Petkov63375832010-09-06 18:13:39 +020045/* cache level */
Borislav Petkovebe2aea2011-11-29 19:03:25 +010046const char * const ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
Borislav Petkovb70ef012009-06-25 19:32:38 +020047EXPORT_SYMBOL_GPL(ll_msgs);
Doug Thompsonb52401ce2009-05-06 17:57:20 +020048
Borislav Petkov63375832010-09-06 18:13:39 +020049/* memory transaction type */
Borislav Petkovebe2aea2011-11-29 19:03:25 +010050const char * const rrrr_msgs[] = {
Borislav Petkov63375832010-09-06 18:13:39 +020051 "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP"
Doug Thompsonb52401ce2009-05-06 17:57:20 +020052};
Borislav Petkovb70ef012009-06-25 19:32:38 +020053EXPORT_SYMBOL_GPL(rrrr_msgs);
Doug Thompsonb52401ce2009-05-06 17:57:20 +020054
Borislav Petkov63375832010-09-06 18:13:39 +020055/* participating processor */
Borislav Petkovebe2aea2011-11-29 19:03:25 +010056const char * const pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
Borislav Petkovb70ef012009-06-25 19:32:38 +020057EXPORT_SYMBOL_GPL(pp_msgs);
Doug Thompsonb52401ce2009-05-06 17:57:20 +020058
Borislav Petkov63375832010-09-06 18:13:39 +020059/* request timeout */
Borislav Petkovebe2aea2011-11-29 19:03:25 +010060const char * const to_msgs[] = { "no timeout", "timed out" };
Borislav Petkovb70ef012009-06-25 19:32:38 +020061EXPORT_SYMBOL_GPL(to_msgs);
Doug Thompsonb52401ce2009-05-06 17:57:20 +020062
Borislav Petkov63375832010-09-06 18:13:39 +020063/* memory or i/o */
Borislav Petkovebe2aea2011-11-29 19:03:25 +010064const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
Borislav Petkovb70ef012009-06-25 19:32:38 +020065EXPORT_SYMBOL_GPL(ii_msgs);
Doug Thompsonb52401ce2009-05-06 17:57:20 +020066
Borislav Petkovf05c41a2012-09-11 18:57:43 +020067static const char * const f15h_mc1_mce_desc[] = {
Borislav Petkov86039cd2010-11-08 15:03:35 +010068 "UC during a demand linefill from L2",
69 "Parity error during data load from IC",
70 "Parity error for IC valid bit",
71 "Main tag parity error",
72 "Parity error in prediction queue",
73 "PFB data/address parity error",
74 "Parity error in the branch status reg",
75 "PFB promotion address error",
76 "Tag error during probe/victimization",
77 "Parity error for IC probe tag valid bit",
78 "PFB non-cacheable bit parity error",
79 "PFB valid bit parity error", /* xec = 0xd */
Borislav Petkov6c1173a2011-11-21 19:45:34 +010080 "Microcode Patch Buffer", /* xec = 010 */
Borislav Petkov86039cd2010-11-08 15:03:35 +010081 "uop queue",
82 "insn buffer",
83 "predecode buffer",
84 "fetch address FIFO"
85};
86
Borislav Petkovf05c41a2012-09-11 18:57:43 +020087static const char * const f15h_mc2_mce_desc[] = {
Borislav Petkov70fdb492010-09-21 20:45:10 +020088 "Fill ECC error on data fills", /* xec = 0x4 */
89 "Fill parity error on insn fills",
90 "Prefetcher request FIFO parity error",
91 "PRQ address parity error",
92 "PRQ data parity error",
93 "WCC Tag ECC error",
94 "WCC Data ECC error",
95 "WCB Data parity error",
Borislav Petkovb64a99c2011-11-23 14:50:44 +010096 "VB Data ECC or parity error",
Borislav Petkov70fdb492010-09-21 20:45:10 +020097 "L2 Tag ECC error", /* xec = 0x10 */
98 "Hard L2 Tag ECC error",
99 "Multiple hits on L2 tag",
100 "XAB parity error",
101 "PRB address parity error"
102};
103
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200104static const char * const mc4_mce_desc[] = {
Borislav Petkov68782672011-11-24 21:29:57 +0100105 "DRAM ECC error detected on the NB",
106 "CRC error detected on HT link",
107 "Link-defined sync error packets detected on HT link",
108 "HT Master abort",
109 "HT Target abort",
110 "Invalid GART PTE entry during GART table walk",
111 "Unsupported atomic RMW received from an IO link",
112 "Watchdog timeout due to lack of progress",
113 "DRAM ECC error detected on the NB",
114 "SVM DMA Exclusion Vector error",
115 "HT data error detected on link",
116 "Protocol error (link, L3, probe filter)",
117 "NB internal arrays parity error",
118 "DRAM addr/ctl signals parity error",
119 "IO link transmission error",
120 "L3 data cache ECC error", /* xec = 0x1c */
121 "L3 cache tag error",
122 "L3 LRU parity bits error",
123 "ECC Error in the Probe Filter directory"
124};
125
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200126static const char * const mc5_mce_desc[] = {
Borislav Petkov8259a7e2010-09-22 15:28:59 +0200127 "CPU Watchdog timer expire",
128 "Wakeup array dest tag",
129 "AG payload array",
130 "EX payload array",
131 "IDRF array",
132 "Retire dispatch queue",
133 "Mapper checkpoint array",
134 "Physical register file EX0 port",
135 "Physical register file EX1 port",
136 "Physical register file AG0 port",
137 "Physical register file AG1 port",
138 "Flag register file",
Borislav Petkovae615b42011-11-25 15:42:59 +0100139 "DE error occurred"
Borislav Petkov8259a7e2010-09-22 15:28:59 +0200140};
141
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200142static bool f12h_mc0_mce(u16 ec, u8 xec)
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200143{
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200144 bool ret = false;
145
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200146 if (MEM_ERROR(ec)) {
Borislav Petkov62452882010-09-22 16:08:37 +0200147 u8 ll = LL(ec);
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200148 ret = true;
149
150 if (ll == LL_L2)
151 pr_cont("during L1 linefill from L2.\n");
152 else if (ll == LL_L1)
Borislav Petkov62452882010-09-22 16:08:37 +0200153 pr_cont("Data/Tag %s error.\n", R4_MSG(ec));
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200154 else
155 ret = false;
156 }
157 return ret;
158}
159
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200160static bool f10h_mc0_mce(u16 ec, u8 xec)
Borislav Petkov9be0bb12010-09-16 15:08:14 +0200161{
Borislav Petkov62452882010-09-22 16:08:37 +0200162 if (R4(ec) == R4_GEN && LL(ec) == LL_L1) {
Borislav Petkov9be0bb12010-09-16 15:08:14 +0200163 pr_cont("during data scrub.\n");
164 return true;
165 }
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200166 return f12h_mc0_mce(ec, xec);
Borislav Petkov9be0bb12010-09-16 15:08:14 +0200167}
168
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200169static bool k8_mc0_mce(u16 ec, u8 xec)
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200170{
171 if (BUS_ERROR(ec)) {
172 pr_cont("during system linefill.\n");
173 return true;
174 }
175
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200176 return f10h_mc0_mce(ec, xec);
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200177}
178
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200179static bool f14h_mc0_mce(u16 ec, u8 xec)
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200180{
Borislav Petkov62452882010-09-22 16:08:37 +0200181 u8 r4 = R4(ec);
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200182 bool ret = true;
183
184 if (MEM_ERROR(ec)) {
185
Borislav Petkov62452882010-09-22 16:08:37 +0200186 if (TT(ec) != TT_DATA || LL(ec) != LL_L1)
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200187 return false;
188
189 switch (r4) {
190 case R4_DRD:
191 case R4_DWR:
192 pr_cont("Data/Tag parity error due to %s.\n",
193 (r4 == R4_DRD ? "load/hw prf" : "store"));
194 break;
195 case R4_EVICT:
196 pr_cont("Copyback parity error on a tag miss.\n");
197 break;
198 case R4_SNOOP:
199 pr_cont("Tag parity error during snoop.\n");
200 break;
201 default:
202 ret = false;
203 }
204 } else if (BUS_ERROR(ec)) {
205
Borislav Petkov62452882010-09-22 16:08:37 +0200206 if ((II(ec) != II_MEM && II(ec) != II_IO) || LL(ec) != LL_LG)
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200207 return false;
208
209 pr_cont("System read data error on a ");
210
211 switch (r4) {
212 case R4_RD:
213 pr_cont("TLB reload.\n");
214 break;
215 case R4_DWR:
216 pr_cont("store.\n");
217 break;
218 case R4_DRD:
219 pr_cont("load.\n");
220 break;
221 default:
222 ret = false;
223 }
224 } else {
225 ret = false;
226 }
227
228 return ret;
229}
230
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200231static bool f15h_mc0_mce(u16 ec, u8 xec)
Borislav Petkov25a4f8b2010-09-17 19:22:34 +0200232{
233 bool ret = true;
234
235 if (MEM_ERROR(ec)) {
236
237 switch (xec) {
238 case 0x0:
239 pr_cont("Data Array access error.\n");
240 break;
241
242 case 0x1:
243 pr_cont("UC error during a linefill from L2/NB.\n");
244 break;
245
246 case 0x2:
247 case 0x11:
248 pr_cont("STQ access error.\n");
249 break;
250
251 case 0x3:
252 pr_cont("SCB access error.\n");
253 break;
254
255 case 0x10:
256 pr_cont("Tag error.\n");
257 break;
258
259 case 0x12:
260 pr_cont("LDQ access error.\n");
261 break;
262
263 default:
264 ret = false;
265 }
266 } else if (BUS_ERROR(ec)) {
267
268 if (!xec)
Borislav Petkov344f0a02011-11-15 17:10:58 +0100269 pr_cont("System Read Data Error.\n");
Borislav Petkov25a4f8b2010-09-17 19:22:34 +0200270 else
Borislav Petkov344f0a02011-11-15 17:10:58 +0100271 pr_cont(" Internal error condition type %d.\n", xec);
Borislav Petkov25a4f8b2010-09-17 19:22:34 +0200272 } else
273 ret = false;
274
275 return ret;
276}
277
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200278static void decode_mc0_mce(struct mce *m)
Borislav Petkov51966242009-07-28 13:50:43 +0200279{
Borislav Petkov62452882010-09-22 16:08:37 +0200280 u16 ec = EC(m->status);
281 u8 xec = XEC(m->status, xec_mask);
Borislav Petkov51966242009-07-28 13:50:43 +0200282
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200283 pr_emerg(HW_ERR "MC0 Error: ");
Borislav Petkov51966242009-07-28 13:50:43 +0200284
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200285 /* TLB error signatures are the same across families */
286 if (TLB_ERROR(ec)) {
Borislav Petkov62452882010-09-22 16:08:37 +0200287 if (TT(ec) == TT_DATA) {
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200288 pr_cont("%s TLB %s.\n", LL_MSG(ec),
Borislav Petkov25a4f8b2010-09-17 19:22:34 +0200289 ((xec == 2) ? "locked miss"
290 : (xec ? "multimatch" : "parity")));
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200291 return;
292 }
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200293 } else if (fam_ops->mc0_mce(ec, xec))
Borislav Petkov25a4f8b2010-09-17 19:22:34 +0200294 ;
295 else
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200296 pr_emerg(HW_ERR "Corrupted MC0 MCE info?\n");
Borislav Petkov51966242009-07-28 13:50:43 +0200297}
298
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200299static bool k8_mc1_mce(u16 ec, u8 xec)
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200300{
Borislav Petkov62452882010-09-22 16:08:37 +0200301 u8 ll = LL(ec);
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200302 bool ret = true;
303
304 if (!MEM_ERROR(ec))
305 return false;
306
307 if (ll == 0x2)
308 pr_cont("during a linefill from L2.\n");
309 else if (ll == 0x1) {
Borislav Petkov62452882010-09-22 16:08:37 +0200310 switch (R4(ec)) {
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200311 case R4_IRD:
312 pr_cont("Parity error during data load.\n");
313 break;
314
315 case R4_EVICT:
316 pr_cont("Copyback Parity/Victim error.\n");
317 break;
318
319 case R4_SNOOP:
320 pr_cont("Tag Snoop error.\n");
321 break;
322
323 default:
324 ret = false;
325 break;
326 }
327 } else
328 ret = false;
329
330 return ret;
331}
332
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200333static bool f14h_mc1_mce(u16 ec, u8 xec)
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200334{
Borislav Petkov62452882010-09-22 16:08:37 +0200335 u8 r4 = R4(ec);
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200336 bool ret = true;
337
338 if (MEM_ERROR(ec)) {
Borislav Petkov62452882010-09-22 16:08:37 +0200339 if (TT(ec) != 0 || LL(ec) != 1)
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200340 ret = false;
341
342 if (r4 == R4_IRD)
343 pr_cont("Data/tag array parity error for a tag hit.\n");
344 else if (r4 == R4_SNOOP)
345 pr_cont("Tag error during snoop/victimization.\n");
346 else
347 ret = false;
348 }
349 return ret;
350}
351
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200352static bool f15h_mc1_mce(u16 ec, u8 xec)
Borislav Petkov86039cd2010-11-08 15:03:35 +0100353{
354 bool ret = true;
355
356 if (!MEM_ERROR(ec))
357 return false;
358
359 switch (xec) {
360 case 0x0 ... 0xa:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200361 pr_cont("%s.\n", f15h_mc1_mce_desc[xec]);
Borislav Petkov86039cd2010-11-08 15:03:35 +0100362 break;
363
364 case 0xd:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200365 pr_cont("%s.\n", f15h_mc1_mce_desc[xec-2]);
Borislav Petkov86039cd2010-11-08 15:03:35 +0100366 break;
367
Borislav Petkov6c1173a2011-11-21 19:45:34 +0100368 case 0x10:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200369 pr_cont("%s.\n", f15h_mc1_mce_desc[xec-4]);
Borislav Petkov6c1173a2011-11-21 19:45:34 +0100370 break;
371
372 case 0x11 ... 0x14:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200373 pr_cont("Decoder %s parity error.\n", f15h_mc1_mce_desc[xec-4]);
Borislav Petkov86039cd2010-11-08 15:03:35 +0100374 break;
375
376 default:
377 ret = false;
378 }
379 return ret;
380}
381
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200382static void decode_mc1_mce(struct mce *m)
Borislav Petkovab5535e2009-07-28 14:06:26 +0200383{
Borislav Petkov62452882010-09-22 16:08:37 +0200384 u16 ec = EC(m->status);
385 u8 xec = XEC(m->status, xec_mask);
Borislav Petkovab5535e2009-07-28 14:06:26 +0200386
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200387 pr_emerg(HW_ERR "MC1 Error: ");
Borislav Petkovab5535e2009-07-28 14:06:26 +0200388
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200389 if (TLB_ERROR(ec))
390 pr_cont("%s TLB %s.\n", LL_MSG(ec),
391 (xec ? "multimatch" : "parity error"));
392 else if (BUS_ERROR(ec)) {
Borislav Petkov525906b2010-10-15 15:27:02 +0200393 bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58)));
Borislav Petkovab5535e2009-07-28 14:06:26 +0200394
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200395 pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read"));
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200396 } else if (fam_ops->mc1_mce(ec, xec))
Borislav Petkovdd53bce2010-08-26 19:05:49 +0200397 ;
398 else
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200399 pr_emerg(HW_ERR "Corrupted MC1 MCE info?\n");
Borislav Petkovab5535e2009-07-28 14:06:26 +0200400}
401
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600402static bool k8_mc2_mce(u16 ec, u8 xec)
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200403{
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600404 bool ret = true;
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200405
406 if (xec == 0x1)
407 pr_cont(" in the write data buffers.\n");
408 else if (xec == 0x3)
409 pr_cont(" in the victim data buffers.\n");
410 else if (xec == 0x2 && MEM_ERROR(ec))
Borislav Petkov62452882010-09-22 16:08:37 +0200411 pr_cont(": %s error in the L2 cache tags.\n", R4_MSG(ec));
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200412 else if (xec == 0x0) {
413 if (TLB_ERROR(ec))
414 pr_cont(": %s error in a Page Descriptor Cache or "
415 "Guest TLB.\n", TT_MSG(ec));
416 else if (BUS_ERROR(ec))
417 pr_cont(": %s/ECC error in data read from NB: %s.\n",
Borislav Petkov62452882010-09-22 16:08:37 +0200418 R4_MSG(ec), PP_MSG(ec));
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200419 else if (MEM_ERROR(ec)) {
Borislav Petkov62452882010-09-22 16:08:37 +0200420 u8 r4 = R4(ec);
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200421
Borislav Petkov62452882010-09-22 16:08:37 +0200422 if (r4 >= 0x7)
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200423 pr_cont(": %s error during data copyback.\n",
Borislav Petkov62452882010-09-22 16:08:37 +0200424 R4_MSG(ec));
425 else if (r4 <= 0x1)
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200426 pr_cont(": %s parity/ECC error during data "
Borislav Petkov62452882010-09-22 16:08:37 +0200427 "access from L2.\n", R4_MSG(ec));
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200428 else
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600429 ret = false;
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200430 } else
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600431 ret = false;
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200432 } else
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600433 ret = false;
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200434
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600435 return ret;
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200436}
437
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600438static bool f15h_mc2_mce(u16 ec, u8 xec)
Borislav Petkov70fdb492010-09-21 20:45:10 +0200439{
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600440 bool ret = true;
Borislav Petkov70fdb492010-09-21 20:45:10 +0200441
442 if (TLB_ERROR(ec)) {
443 if (xec == 0x0)
444 pr_cont("Data parity TLB read error.\n");
445 else if (xec == 0x1)
446 pr_cont("Poison data provided for TLB fill.\n");
447 else
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600448 ret = false;
Borislav Petkov70fdb492010-09-21 20:45:10 +0200449 } else if (BUS_ERROR(ec)) {
450 if (xec > 2)
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600451 ret = false;
Borislav Petkov70fdb492010-09-21 20:45:10 +0200452
453 pr_cont("Error during attempted NB data read.\n");
454 } else if (MEM_ERROR(ec)) {
455 switch (xec) {
456 case 0x4 ... 0xc:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200457 pr_cont("%s.\n", f15h_mc2_mce_desc[xec - 0x4]);
Borislav Petkov70fdb492010-09-21 20:45:10 +0200458 break;
459
460 case 0x10 ... 0x14:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200461 pr_cont("%s.\n", f15h_mc2_mce_desc[xec - 0x7]);
Borislav Petkov70fdb492010-09-21 20:45:10 +0200462 break;
463
464 default:
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600465 ret = false;
Borislav Petkov70fdb492010-09-21 20:45:10 +0200466 }
467 }
468
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600469 return ret;
470}
Borislav Petkov70fdb492010-09-21 20:45:10 +0200471
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600472static void decode_mc2_mce(struct mce *m)
473{
474 u16 ec = EC(m->status);
475 u8 xec = XEC(m->status, xec_mask);
476
477 pr_emerg(HW_ERR "MC2 Error: ");
478
479 if (!fam_ops->mc2_mce(ec, xec))
480 pr_cont(HW_ERR "Corrupted MC2 MCE info?\n");
Borislav Petkov70fdb492010-09-21 20:45:10 +0200481}
482
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200483static void decode_mc3_mce(struct mce *m)
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200484{
Borislav Petkov62452882010-09-22 16:08:37 +0200485 u16 ec = EC(m->status);
486 u8 xec = XEC(m->status, xec_mask);
Borislav Petkovded50622010-08-27 17:03:34 +0200487
Borislav Petkovb18434c2010-09-22 11:53:32 +0200488 if (boot_cpu_data.x86 >= 0x14) {
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200489 pr_emerg("You shouldn't be seeing MC3 MCE on this cpu family,"
Borislav Petkovded50622010-08-27 17:03:34 +0200490 " please report on LKML.\n");
491 return;
492 }
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200493
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200494 pr_emerg(HW_ERR "MC3 Error");
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200495
496 if (xec == 0x0) {
Borislav Petkov62452882010-09-22 16:08:37 +0200497 u8 r4 = R4(ec);
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200498
Borislav Petkovded50622010-08-27 17:03:34 +0200499 if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR))
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200500 goto wrong_mc3_mce;
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200501
Borislav Petkov62452882010-09-22 16:08:37 +0200502 pr_cont(" during %s.\n", R4_MSG(ec));
Borislav Petkovded50622010-08-27 17:03:34 +0200503 } else
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200504 goto wrong_mc3_mce;
Borislav Petkovded50622010-08-27 17:03:34 +0200505
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200506 return;
507
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200508 wrong_mc3_mce:
509 pr_emerg(HW_ERR "Corrupted MC3 MCE info?\n");
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200510}
511
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200512static void decode_mc4_mce(struct mce *m)
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200513{
Borislav Petkov68782672011-11-24 21:29:57 +0100514 struct cpuinfo_x86 *c = &boot_cpu_data;
515 int node_id = amd_get_nb_id(m->extcpu);
516 u16 ec = EC(m->status);
517 u8 xec = XEC(m->status, 0x1f);
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200518 u8 offset = 0;
519
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200520 pr_emerg(HW_ERR "MC4 Error (node %d): ", node_id);
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200521
Borislav Petkov68782672011-11-24 21:29:57 +0100522 switch (xec) {
523 case 0x0 ... 0xe:
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200524
Borislav Petkov68782672011-11-24 21:29:57 +0100525 /* special handling for DRAM ECCs */
526 if (xec == 0x0 || xec == 0x8) {
527 /* no ECCs on F11h */
528 if (c->x86 == 0x11)
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200529 goto wrong_mc4_mce;
Borislav Petkov68782672011-11-24 21:29:57 +0100530
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200531 pr_cont("%s.\n", mc4_mce_desc[xec]);
Borislav Petkov68782672011-11-24 21:29:57 +0100532
533 if (nb_bus_decoder)
534 nb_bus_decoder(node_id, m);
535 return;
536 }
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200537 break;
538
539 case 0xf:
540 if (TLB_ERROR(ec))
541 pr_cont("GART Table Walk data error.\n");
542 else if (BUS_ERROR(ec))
543 pr_cont("DMA Exclusion Vector Table Walk error.\n");
544 else
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200545 goto wrong_mc4_mce;
Borislav Petkov68782672011-11-24 21:29:57 +0100546 return;
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200547
Borislav Petkov05cd6672010-09-22 15:06:24 +0200548 case 0x19:
549 if (boot_cpu_data.x86 == 0x15)
550 pr_cont("Compute Unit Data Error.\n");
551 else
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200552 goto wrong_mc4_mce;
Borislav Petkov68782672011-11-24 21:29:57 +0100553 return;
Borislav Petkov05cd6672010-09-22 15:06:24 +0200554
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200555 case 0x1c ... 0x1f:
Borislav Petkov68782672011-11-24 21:29:57 +0100556 offset = 13;
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200557 break;
558
559 default:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200560 goto wrong_mc4_mce;
Borislav Petkov68782672011-11-24 21:29:57 +0100561 }
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200562
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200563 pr_cont("%s.\n", mc4_mce_desc[xec - offset]);
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200564 return;
565
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200566 wrong_mc4_mce:
567 pr_emerg(HW_ERR "Corrupted MC4 MCE info?\n");
Borislav Petkovd93cc222009-07-28 10:56:15 +0200568}
Borislav Petkovd93cc222009-07-28 10:56:15 +0200569
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200570static void decode_mc5_mce(struct mce *m)
Borislav Petkov53bd5fe2009-07-28 14:20:46 +0200571{
Borislav Petkov8259a7e2010-09-22 15:28:59 +0200572 struct cpuinfo_x86 *c = &boot_cpu_data;
Borislav Petkov62452882010-09-22 16:08:37 +0200573 u8 xec = XEC(m->status, xec_mask);
Borislav Petkov8259a7e2010-09-22 15:28:59 +0200574
575 if (c->x86 == 0xf || c->x86 == 0x11)
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200576 goto wrong_mc5_mce;
Borislav Petkovfe4ea262010-08-31 18:38:24 +0200577
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200578 pr_emerg(HW_ERR "MC5 Error: ");
Borislav Petkov8259a7e2010-09-22 15:28:59 +0200579
580 if (xec == 0x0 || xec == 0xc)
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200581 pr_cont("%s.\n", mc5_mce_desc[xec]);
Borislav Petkov8259a7e2010-09-22 15:28:59 +0200582 else if (xec < 0xd)
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200583 pr_cont("%s parity error.\n", mc5_mce_desc[xec]);
Borislav Petkov8259a7e2010-09-22 15:28:59 +0200584 else
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200585 goto wrong_mc5_mce;
Borislav Petkov8259a7e2010-09-22 15:28:59 +0200586
587 return;
Borislav Petkovfe4ea262010-08-31 18:38:24 +0200588
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200589 wrong_mc5_mce:
590 pr_emerg(HW_ERR "Corrupted MC5 MCE info?\n");
Borislav Petkov53bd5fe2009-07-28 14:20:46 +0200591}
592
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200593static void decode_mc6_mce(struct mce *m)
Borislav Petkovb8f85c42010-09-22 15:37:58 +0200594{
Borislav Petkov62452882010-09-22 16:08:37 +0200595 u8 xec = XEC(m->status, xec_mask);
Borislav Petkovb8f85c42010-09-22 15:37:58 +0200596
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200597 pr_emerg(HW_ERR "MC6 Error: ");
Borislav Petkovb8f85c42010-09-22 15:37:58 +0200598
599 switch (xec) {
600 case 0x1:
601 pr_cont("Free List");
602 break;
603
604 case 0x2:
605 pr_cont("Physical Register File");
606 break;
607
608 case 0x3:
609 pr_cont("Retire Queue");
610 break;
611
612 case 0x4:
613 pr_cont("Scheduler table");
614 break;
615
616 case 0x5:
617 pr_cont("Status Register File");
618 break;
619
620 default:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200621 goto wrong_mc6_mce;
Borislav Petkovb8f85c42010-09-22 15:37:58 +0200622 break;
623 }
624
625 pr_cont(" parity error.\n");
626
627 return;
628
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200629 wrong_mc6_mce:
630 pr_emerg(HW_ERR "Corrupted MC6 MCE info?\n");
Borislav Petkovb8f85c42010-09-22 15:37:58 +0200631}
632
Borislav Petkov63375832010-09-06 18:13:39 +0200633static inline void amd_decode_err_code(u16 ec)
Borislav Petkovd93cc222009-07-28 10:56:15 +0200634{
Borislav Petkovfa7ae8c2010-09-22 17:42:27 +0200635
636 pr_emerg(HW_ERR "cache level: %s", LL_MSG(ec));
637
638 if (BUS_ERROR(ec))
639 pr_cont(", mem/io: %s", II_MSG(ec));
640 else
641 pr_cont(", tx: %s", TT_MSG(ec));
642
643 if (MEM_ERROR(ec) || BUS_ERROR(ec)) {
644 pr_cont(", mem-tx: %s", R4_MSG(ec));
645
646 if (BUS_ERROR(ec))
647 pr_cont(", part-proc: %s (%s)", PP_MSG(ec), TO_MSG(ec));
648 }
649
650 pr_cont("\n");
Borislav Petkov549d0422009-07-24 13:51:42 +0200651}
Borislav Petkov549d0422009-07-24 13:51:42 +0200652
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200653/*
654 * Filter out unwanted MCE signatures here.
655 */
656static bool amd_filter_mce(struct mce *m)
657{
658 u8 xec = (m->status >> 16) & 0x1f;
659
660 /*
661 * NB GART TLB error reporting is disabled by default.
662 */
663 if (m->bank == 4 && xec == 0x5 && !report_gart_errors)
664 return true;
665
666 return false;
667}
668
Borislav Petkovd5c67702012-09-14 20:25:37 +0200669static const char *decode_error_status(struct mce *m)
670{
671 if (m->status & MCI_STATUS_UC) {
672 if (m->status & MCI_STATUS_PCC)
673 return "System Fatal error.";
674 if (m->mcgstatus & MCG_STATUS_RIPV)
675 return "Uncorrected, software restartable error.";
676 return "Uncorrected, software containable error.";
677 }
678
679 if (m->status & MCI_STATUS_DEFERRED)
680 return "Deferred error.";
681
682 return "Corrected error, no action required.";
683}
684
Borislav Petkov9cdeb402010-09-02 18:33:24 +0200685int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
Borislav Petkov549d0422009-07-24 13:51:42 +0200686{
Borislav Petkovfb253192009-10-07 13:20:38 +0200687 struct mce *m = (struct mce *)data;
Borislav Petkovf89f8382012-09-13 15:14:22 +0200688 struct cpuinfo_x86 *c = &cpu_data(m->extcpu);
Borislav Petkovb0b07a22011-08-24 18:44:22 +0200689 int ecc;
Borislav Petkov549d0422009-07-24 13:51:42 +0200690
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200691 if (amd_filter_mce(m))
692 return NOTIFY_STOP;
693
Borislav Petkov51966242009-07-28 13:50:43 +0200694 switch (m->bank) {
695 case 0:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200696 decode_mc0_mce(m);
Borislav Petkov51966242009-07-28 13:50:43 +0200697 break;
Borislav Petkovd93cc222009-07-28 10:56:15 +0200698
Borislav Petkovab5535e2009-07-28 14:06:26 +0200699 case 1:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200700 decode_mc1_mce(m);
Borislav Petkovab5535e2009-07-28 14:06:26 +0200701 break;
702
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200703 case 2:
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600704 decode_mc2_mce(m);
Borislav Petkov56cad2d2009-07-28 14:14:24 +0200705 break;
706
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200707 case 3:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200708 decode_mc3_mce(m);
Borislav Petkovf9350ef2009-07-28 14:17:30 +0200709 break;
710
Borislav Petkov51966242009-07-28 13:50:43 +0200711 case 4:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200712 decode_mc4_mce(m);
Borislav Petkov51966242009-07-28 13:50:43 +0200713 break;
714
Borislav Petkov53bd5fe2009-07-28 14:20:46 +0200715 case 5:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200716 decode_mc5_mce(m);
Borislav Petkov53bd5fe2009-07-28 14:20:46 +0200717 break;
718
Borislav Petkovb8f85c42010-09-22 15:37:58 +0200719 case 6:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200720 decode_mc6_mce(m);
Borislav Petkovb8f85c42010-09-22 15:37:58 +0200721 break;
722
Borislav Petkov51966242009-07-28 13:50:43 +0200723 default:
724 break;
Borislav Petkovb69b29d2009-07-27 16:21:14 +0200725 }
Borislav Petkov51966242009-07-28 13:50:43 +0200726
Borislav Petkovd5c67702012-09-14 20:25:37 +0200727 pr_emerg(HW_ERR "Error Status: %s\n", decode_error_status(m));
728
Borislav Petkovd824c772012-09-14 20:10:59 +0200729 pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
730 m->extcpu,
731 c->x86, c->x86_model, c->x86_mask,
732 m->bank,
733 ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
734 ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
735 ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
736 ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
737 ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
738
739 if (c->x86 == 0x15)
740 pr_cont("|%s|%s",
Borislav Petkovd5c67702012-09-14 20:25:37 +0200741 ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
742 ((m->status & MCI_STATUS_POISON) ? "Poison" : "-"));
Borislav Petkovd824c772012-09-14 20:10:59 +0200743
744 /* do the two bits[14:13] together */
745 ecc = (m->status >> 45) & 0x3;
746 if (ecc)
747 pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
748
749 pr_cont("]: 0x%016llx\n", m->status);
750
751 if (m->status & MCI_STATUS_ADDRV)
752 pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
753
Borislav Petkov51966242009-07-28 13:50:43 +0200754 amd_decode_err_code(m->status & 0xffff);
Borislav Petkovfb253192009-10-07 13:20:38 +0200755
756 return NOTIFY_STOP;
Borislav Petkov549d0422009-07-24 13:51:42 +0200757}
Borislav Petkov9cdeb402010-09-02 18:33:24 +0200758EXPORT_SYMBOL_GPL(amd_decode_mce);
Ingo Molnarf436f8b2009-10-01 16:14:32 +0200759
Borislav Petkovfb253192009-10-07 13:20:38 +0200760static struct notifier_block amd_mce_dec_nb = {
761 .notifier_call = amd_decode_mce,
762};
763
Ingo Molnarf436f8b2009-10-01 16:14:32 +0200764static int __init mce_amd_init(void)
765{
Borislav Petkovbad11e02010-09-22 17:44:51 +0200766 struct cpuinfo_x86 *c = &boot_cpu_data;
767
768 if (c->x86_vendor != X86_VENDOR_AMD)
Borislav Petkove045c292010-08-06 18:55:45 +0200769 return 0;
770
Borislav Petkovec3e82d2012-04-04 14:21:02 +0200771 if (c->x86 < 0xf || c->x86 > 0x15)
Borislav Petkove045c292010-08-06 18:55:45 +0200772 return 0;
773
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200774 fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
775 if (!fam_ops)
776 return -ENOMEM;
777
Borislav Petkovbad11e02010-09-22 17:44:51 +0200778 switch (c->x86) {
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200779 case 0xf:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200780 fam_ops->mc0_mce = k8_mc0_mce;
781 fam_ops->mc1_mce = k8_mc1_mce;
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600782 fam_ops->mc2_mce = k8_mc2_mce;
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200783 break;
784
785 case 0x10:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200786 fam_ops->mc0_mce = f10h_mc0_mce;
787 fam_ops->mc1_mce = k8_mc1_mce;
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600788 fam_ops->mc2_mce = k8_mc2_mce;
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200789 break;
790
Borislav Petkovf0157b32010-10-05 19:07:16 +0200791 case 0x11:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200792 fam_ops->mc0_mce = k8_mc0_mce;
793 fam_ops->mc1_mce = k8_mc1_mce;
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600794 fam_ops->mc2_mce = k8_mc2_mce;
Borislav Petkovf0157b32010-10-05 19:07:16 +0200795 break;
796
Borislav Petkov9be0bb12010-09-16 15:08:14 +0200797 case 0x12:
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200798 fam_ops->mc0_mce = f12h_mc0_mce;
799 fam_ops->mc1_mce = k8_mc1_mce;
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600800 fam_ops->mc2_mce = k8_mc2_mce;
Borislav Petkov9be0bb12010-09-16 15:08:14 +0200801 break;
802
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200803 case 0x14:
Borislav Petkov5ce88f62010-08-31 18:28:08 +0200804 nb_err_cpumask = 0x3;
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200805 fam_ops->mc0_mce = f14h_mc0_mce;
806 fam_ops->mc1_mce = f14h_mc1_mce;
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600807 fam_ops->mc2_mce = k8_mc2_mce;
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200808 break;
809
Borislav Petkov2be64bf2010-09-17 19:11:47 +0200810 case 0x15:
811 xec_mask = 0x1f;
Borislav Petkovf05c41a2012-09-11 18:57:43 +0200812 fam_ops->mc0_mce = f15h_mc0_mce;
813 fam_ops->mc1_mce = f15h_mc1_mce;
Jacob Shin4a73d3d2012-12-18 15:06:10 -0600814 fam_ops->mc2_mce = f15h_mc2_mce;
Borislav Petkov2be64bf2010-09-17 19:11:47 +0200815 break;
816
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200817 default:
Borislav Petkovec3e82d2012-04-04 14:21:02 +0200818 printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86);
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200819 kfree(fam_ops);
820 return -EINVAL;
821 }
822
Borislav Petkov9530d602010-09-06 15:05:45 +0200823 pr_info("MCE: In-kernel MCE decoding enabled.\n");
824
Borislav Petkov3653ada2011-12-04 15:12:09 +0100825 mce_register_decode_chain(&amd_mce_dec_nb);
Ingo Molnarf436f8b2009-10-01 16:14:32 +0200826
827 return 0;
828}
829early_initcall(mce_amd_init);
Borislav Petkov0d18b2e2009-10-02 15:31:48 +0200830
831#ifdef MODULE
832static void __exit mce_amd_exit(void)
833{
Borislav Petkov3653ada2011-12-04 15:12:09 +0100834 mce_unregister_decode_chain(&amd_mce_dec_nb);
Borislav Petkov888ab8e2010-08-18 15:11:35 +0200835 kfree(fam_ops);
Borislav Petkov0d18b2e2009-10-02 15:31:48 +0200836}
837
838MODULE_DESCRIPTION("AMD MCE decoder");
839MODULE_ALIAS("edac-mce-amd");
840MODULE_LICENSE("GPL");
841module_exit(mce_amd_exit);
842#endif