Root/drivers/edac/mce_amd.c

1#include <linux/module.h>
2#include <linux/slab.h>
3
4#include "mce_amd.h"
5
6static struct amd_decoder_ops *fam_ops;
7
8static u8 xec_mask = 0xf;
9static u8 nb_err_cpumask = 0xf;
10
11static bool report_gart_errors;
12static void (*nb_bus_decoder)(int node_id, struct mce *m);
13
14void amd_report_gart_errors(bool v)
15{
16    report_gart_errors = v;
17}
18EXPORT_SYMBOL_GPL(amd_report_gart_errors);
19
20void amd_register_ecc_decoder(void (*f)(int, struct mce *))
21{
22    nb_bus_decoder = f;
23}
24EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
25
26void amd_unregister_ecc_decoder(void (*f)(int, struct mce *))
27{
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
36/*
37 * string representation for the different MCA reported error types, see F3x48
38 * or MSR0000_0411.
39 */
40
41/* transaction type */
42const char * const tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
43EXPORT_SYMBOL_GPL(tt_msgs);
44
45/* cache level */
46const char * const ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
47EXPORT_SYMBOL_GPL(ll_msgs);
48
49/* memory transaction type */
50const char * const rrrr_msgs[] = {
51       "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP"
52};
53EXPORT_SYMBOL_GPL(rrrr_msgs);
54
55/* participating processor */
56const char * const pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
57EXPORT_SYMBOL_GPL(pp_msgs);
58
59/* request timeout */
60const char * const to_msgs[] = { "no timeout", "timed out" };
61EXPORT_SYMBOL_GPL(to_msgs);
62
63/* memory or i/o */
64const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
65EXPORT_SYMBOL_GPL(ii_msgs);
66
67static const char * const f15h_ic_mce_desc[] = {
68    "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 */
80    "Microcode Patch Buffer", /* xec = 010 */
81    "uop queue",
82    "insn buffer",
83    "predecode buffer",
84    "fetch address FIFO"
85};
86
87static const char * const f15h_cu_mce_desc[] = {
88    "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",
96    "VB Data ECC or parity error",
97    "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
104static const char * const nb_mce_desc[] = {
105    "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
126static const char * const fr_ex_mce_desc[] = {
127    "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",
139    "DE error occurred"
140};
141
142static bool f12h_dc_mce(u16 ec, u8 xec)
143{
144    bool ret = false;
145
146    if (MEM_ERROR(ec)) {
147        u8 ll = LL(ec);
148        ret = true;
149
150        if (ll == LL_L2)
151            pr_cont("during L1 linefill from L2.\n");
152        else if (ll == LL_L1)
153            pr_cont("Data/Tag %s error.\n", R4_MSG(ec));
154        else
155            ret = false;
156    }
157    return ret;
158}
159
160static bool f10h_dc_mce(u16 ec, u8 xec)
161{
162    if (R4(ec) == R4_GEN && LL(ec) == LL_L1) {
163        pr_cont("during data scrub.\n");
164        return true;
165    }
166    return f12h_dc_mce(ec, xec);
167}
168
169static bool k8_dc_mce(u16 ec, u8 xec)
170{
171    if (BUS_ERROR(ec)) {
172        pr_cont("during system linefill.\n");
173        return true;
174    }
175
176    return f10h_dc_mce(ec, xec);
177}
178
179static bool f14h_dc_mce(u16 ec, u8 xec)
180{
181    u8 r4 = R4(ec);
182    bool ret = true;
183
184    if (MEM_ERROR(ec)) {
185
186        if (TT(ec) != TT_DATA || LL(ec) != LL_L1)
187            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
206        if ((II(ec) != II_MEM && II(ec) != II_IO) || LL(ec) != LL_LG)
207            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
231static bool f15h_dc_mce(u16 ec, u8 xec)
232{
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)
269            pr_cont("System Read Data Error.\n");
270        else
271            pr_cont(" Internal error condition type %d.\n", xec);
272    } else
273        ret = false;
274
275    return ret;
276}
277
278static void amd_decode_dc_mce(struct mce *m)
279{
280    u16 ec = EC(m->status);
281    u8 xec = XEC(m->status, xec_mask);
282
283    pr_emerg(HW_ERR "Data Cache Error: ");
284
285    /* TLB error signatures are the same across families */
286    if (TLB_ERROR(ec)) {
287        if (TT(ec) == TT_DATA) {
288            pr_cont("%s TLB %s.\n", LL_MSG(ec),
289                ((xec == 2) ? "locked miss"
290                        : (xec ? "multimatch" : "parity")));
291            return;
292        }
293    } else if (fam_ops->dc_mce(ec, xec))
294        ;
295    else
296        pr_emerg(HW_ERR "Corrupted DC MCE info?\n");
297}
298
299static bool k8_ic_mce(u16 ec, u8 xec)
300{
301    u8 ll = LL(ec);
302    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) {
310        switch (R4(ec)) {
311        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
333static bool f14h_ic_mce(u16 ec, u8 xec)
334{
335    u8 r4 = R4(ec);
336    bool ret = true;
337
338    if (MEM_ERROR(ec)) {
339        if (TT(ec) != 0 || LL(ec) != 1)
340            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
352static bool f15h_ic_mce(u16 ec, u8 xec)
353{
354    bool ret = true;
355
356    if (!MEM_ERROR(ec))
357        return false;
358
359    switch (xec) {
360    case 0x0 ... 0xa:
361        pr_cont("%s.\n", f15h_ic_mce_desc[xec]);
362        break;
363
364    case 0xd:
365        pr_cont("%s.\n", f15h_ic_mce_desc[xec-2]);
366        break;
367
368    case 0x10:
369        pr_cont("%s.\n", f15h_ic_mce_desc[xec-4]);
370        break;
371
372    case 0x11 ... 0x14:
373        pr_cont("Decoder %s parity error.\n", f15h_ic_mce_desc[xec-4]);
374        break;
375
376    default:
377        ret = false;
378    }
379    return ret;
380}
381
382static void amd_decode_ic_mce(struct mce *m)
383{
384    u16 ec = EC(m->status);
385    u8 xec = XEC(m->status, xec_mask);
386
387    pr_emerg(HW_ERR "Instruction Cache Error: ");
388
389    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)) {
393        bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58)));
394
395        pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read"));
396    } else if (fam_ops->ic_mce(ec, xec))
397        ;
398    else
399        pr_emerg(HW_ERR "Corrupted IC MCE info?\n");
400}
401
402static void amd_decode_bu_mce(struct mce *m)
403{
404    u16 ec = EC(m->status);
405    u8 xec = XEC(m->status, xec_mask);
406
407    pr_emerg(HW_ERR "Bus Unit Error");
408
409    if (xec == 0x1)
410        pr_cont(" in the write data buffers.\n");
411    else if (xec == 0x3)
412        pr_cont(" in the victim data buffers.\n");
413    else if (xec == 0x2 && MEM_ERROR(ec))
414        pr_cont(": %s error in the L2 cache tags.\n", R4_MSG(ec));
415    else if (xec == 0x0) {
416        if (TLB_ERROR(ec))
417            pr_cont(": %s error in a Page Descriptor Cache or "
418                "Guest TLB.\n", TT_MSG(ec));
419        else if (BUS_ERROR(ec))
420            pr_cont(": %s/ECC error in data read from NB: %s.\n",
421                R4_MSG(ec), PP_MSG(ec));
422        else if (MEM_ERROR(ec)) {
423            u8 r4 = R4(ec);
424
425            if (r4 >= 0x7)
426                pr_cont(": %s error during data copyback.\n",
427                    R4_MSG(ec));
428            else if (r4 <= 0x1)
429                pr_cont(": %s parity/ECC error during data "
430                    "access from L2.\n", R4_MSG(ec));
431            else
432                goto wrong_bu_mce;
433        } else
434            goto wrong_bu_mce;
435    } else
436        goto wrong_bu_mce;
437
438    return;
439
440wrong_bu_mce:
441    pr_emerg(HW_ERR "Corrupted BU MCE info?\n");
442}
443
444static void amd_decode_cu_mce(struct mce *m)
445{
446    u16 ec = EC(m->status);
447    u8 xec = XEC(m->status, xec_mask);
448
449    pr_emerg(HW_ERR "Combined Unit Error: ");
450
451    if (TLB_ERROR(ec)) {
452        if (xec == 0x0)
453            pr_cont("Data parity TLB read error.\n");
454        else if (xec == 0x1)
455            pr_cont("Poison data provided for TLB fill.\n");
456        else
457            goto wrong_cu_mce;
458    } else if (BUS_ERROR(ec)) {
459        if (xec > 2)
460            goto wrong_cu_mce;
461
462        pr_cont("Error during attempted NB data read.\n");
463    } else if (MEM_ERROR(ec)) {
464        switch (xec) {
465        case 0x4 ... 0xc:
466            pr_cont("%s.\n", f15h_cu_mce_desc[xec - 0x4]);
467            break;
468
469        case 0x10 ... 0x14:
470            pr_cont("%s.\n", f15h_cu_mce_desc[xec - 0x7]);
471            break;
472
473        default:
474            goto wrong_cu_mce;
475        }
476    }
477
478    return;
479
480wrong_cu_mce:
481    pr_emerg(HW_ERR "Corrupted CU MCE info?\n");
482}
483
484static void amd_decode_ls_mce(struct mce *m)
485{
486    u16 ec = EC(m->status);
487    u8 xec = XEC(m->status, xec_mask);
488
489    if (boot_cpu_data.x86 >= 0x14) {
490        pr_emerg("You shouldn't be seeing an LS MCE on this cpu family,"
491             " please report on LKML.\n");
492        return;
493    }
494
495    pr_emerg(HW_ERR "Load Store Error");
496
497    if (xec == 0x0) {
498        u8 r4 = R4(ec);
499
500        if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR))
501            goto wrong_ls_mce;
502
503        pr_cont(" during %s.\n", R4_MSG(ec));
504    } else
505        goto wrong_ls_mce;
506
507    return;
508
509wrong_ls_mce:
510    pr_emerg(HW_ERR "Corrupted LS MCE info?\n");
511}
512
513void amd_decode_nb_mce(struct mce *m)
514{
515    struct cpuinfo_x86 *c = &boot_cpu_data;
516    int node_id = amd_get_nb_id(m->extcpu);
517    u16 ec = EC(m->status);
518    u8 xec = XEC(m->status, 0x1f);
519    u8 offset = 0;
520
521    pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id);
522
523    switch (xec) {
524    case 0x0 ... 0xe:
525
526        /* special handling for DRAM ECCs */
527        if (xec == 0x0 || xec == 0x8) {
528            /* no ECCs on F11h */
529            if (c->x86 == 0x11)
530                goto wrong_nb_mce;
531
532            pr_cont("%s.\n", nb_mce_desc[xec]);
533
534            if (nb_bus_decoder)
535                nb_bus_decoder(node_id, m);
536            return;
537        }
538        break;
539
540    case 0xf:
541        if (TLB_ERROR(ec))
542            pr_cont("GART Table Walk data error.\n");
543        else if (BUS_ERROR(ec))
544            pr_cont("DMA Exclusion Vector Table Walk error.\n");
545        else
546            goto wrong_nb_mce;
547        return;
548
549    case 0x19:
550        if (boot_cpu_data.x86 == 0x15)
551            pr_cont("Compute Unit Data Error.\n");
552        else
553            goto wrong_nb_mce;
554        return;
555
556    case 0x1c ... 0x1f:
557        offset = 13;
558        break;
559
560    default:
561        goto wrong_nb_mce;
562    }
563
564    pr_cont("%s.\n", nb_mce_desc[xec - offset]);
565    return;
566
567wrong_nb_mce:
568    pr_emerg(HW_ERR "Corrupted NB MCE info?\n");
569}
570EXPORT_SYMBOL_GPL(amd_decode_nb_mce);
571
572static void amd_decode_fr_mce(struct mce *m)
573{
574    struct cpuinfo_x86 *c = &boot_cpu_data;
575    u8 xec = XEC(m->status, xec_mask);
576
577    if (c->x86 == 0xf || c->x86 == 0x11)
578        goto wrong_fr_mce;
579
580    pr_emerg(HW_ERR "%s Error: ",
581         (c->x86 == 0x15 ? "Execution Unit" : "FIROB"));
582
583    if (xec == 0x0 || xec == 0xc)
584        pr_cont("%s.\n", fr_ex_mce_desc[xec]);
585    else if (xec < 0xd)
586        pr_cont("%s parity error.\n", fr_ex_mce_desc[xec]);
587    else
588        goto wrong_fr_mce;
589
590    return;
591
592wrong_fr_mce:
593    pr_emerg(HW_ERR "Corrupted FR MCE info?\n");
594}
595
596static void amd_decode_fp_mce(struct mce *m)
597{
598    u8 xec = XEC(m->status, xec_mask);
599
600    pr_emerg(HW_ERR "Floating Point Unit Error: ");
601
602    switch (xec) {
603    case 0x1:
604        pr_cont("Free List");
605        break;
606
607    case 0x2:
608        pr_cont("Physical Register File");
609        break;
610
611    case 0x3:
612        pr_cont("Retire Queue");
613        break;
614
615    case 0x4:
616        pr_cont("Scheduler table");
617        break;
618
619    case 0x5:
620        pr_cont("Status Register File");
621        break;
622
623    default:
624        goto wrong_fp_mce;
625        break;
626    }
627
628    pr_cont(" parity error.\n");
629
630    return;
631
632wrong_fp_mce:
633    pr_emerg(HW_ERR "Corrupted FP MCE info?\n");
634}
635
636static inline void amd_decode_err_code(u16 ec)
637{
638
639    pr_emerg(HW_ERR "cache level: %s", LL_MSG(ec));
640
641    if (BUS_ERROR(ec))
642        pr_cont(", mem/io: %s", II_MSG(ec));
643    else
644        pr_cont(", tx: %s", TT_MSG(ec));
645
646    if (MEM_ERROR(ec) || BUS_ERROR(ec)) {
647        pr_cont(", mem-tx: %s", R4_MSG(ec));
648
649        if (BUS_ERROR(ec))
650            pr_cont(", part-proc: %s (%s)", PP_MSG(ec), TO_MSG(ec));
651    }
652
653    pr_cont("\n");
654}
655
656/*
657 * Filter out unwanted MCE signatures here.
658 */
659static bool amd_filter_mce(struct mce *m)
660{
661    u8 xec = (m->status >> 16) & 0x1f;
662
663    /*
664     * NB GART TLB error reporting is disabled by default.
665     */
666    if (m->bank == 4 && xec == 0x5 && !report_gart_errors)
667        return true;
668
669    return false;
670}
671
672int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
673{
674    struct mce *m = (struct mce *)data;
675    struct cpuinfo_x86 *c = &boot_cpu_data;
676    int ecc;
677
678    if (amd_filter_mce(m))
679        return NOTIFY_STOP;
680
681    pr_emerg(HW_ERR "CPU:%d\tMC%d_STATUS[%s|%s|%s|%s|%s",
682        m->extcpu, m->bank,
683        ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
684        ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
685        ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
686        ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
687        ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
688
689    if (c->x86 == 0x15)
690        pr_cont("|%s|%s",
691            ((m->status & BIT_64(44)) ? "Deferred" : "-"),
692            ((m->status & BIT_64(43)) ? "Poison" : "-"));
693
694    /* do the two bits[14:13] together */
695    ecc = (m->status >> 45) & 0x3;
696    if (ecc)
697        pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
698
699    pr_cont("]: 0x%016llx\n", m->status);
700
701    if (m->status & MCI_STATUS_ADDRV)
702        pr_emerg(HW_ERR "\tMC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
703
704    switch (m->bank) {
705    case 0:
706        amd_decode_dc_mce(m);
707        break;
708
709    case 1:
710        amd_decode_ic_mce(m);
711        break;
712
713    case 2:
714        if (c->x86 == 0x15)
715            amd_decode_cu_mce(m);
716        else
717            amd_decode_bu_mce(m);
718        break;
719
720    case 3:
721        amd_decode_ls_mce(m);
722        break;
723
724    case 4:
725        amd_decode_nb_mce(m);
726        break;
727
728    case 5:
729        amd_decode_fr_mce(m);
730        break;
731
732    case 6:
733        amd_decode_fp_mce(m);
734        break;
735
736    default:
737        break;
738    }
739
740    amd_decode_err_code(m->status & 0xffff);
741
742    return NOTIFY_STOP;
743}
744EXPORT_SYMBOL_GPL(amd_decode_mce);
745
746static struct notifier_block amd_mce_dec_nb = {
747    .notifier_call = amd_decode_mce,
748};
749
750static int __init mce_amd_init(void)
751{
752    struct cpuinfo_x86 *c = &boot_cpu_data;
753
754    if (c->x86_vendor != X86_VENDOR_AMD)
755        return 0;
756
757    if (c->x86 < 0xf || c->x86 > 0x15)
758        return 0;
759
760    fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
761    if (!fam_ops)
762        return -ENOMEM;
763
764    switch (c->x86) {
765    case 0xf:
766        fam_ops->dc_mce = k8_dc_mce;
767        fam_ops->ic_mce = k8_ic_mce;
768        break;
769
770    case 0x10:
771        fam_ops->dc_mce = f10h_dc_mce;
772        fam_ops->ic_mce = k8_ic_mce;
773        break;
774
775    case 0x11:
776        fam_ops->dc_mce = k8_dc_mce;
777        fam_ops->ic_mce = k8_ic_mce;
778        break;
779
780    case 0x12:
781        fam_ops->dc_mce = f12h_dc_mce;
782        fam_ops->ic_mce = k8_ic_mce;
783        break;
784
785    case 0x14:
786        nb_err_cpumask = 0x3;
787        fam_ops->dc_mce = f14h_dc_mce;
788        fam_ops->ic_mce = f14h_ic_mce;
789        break;
790
791    case 0x15:
792        xec_mask = 0x1f;
793        fam_ops->dc_mce = f15h_dc_mce;
794        fam_ops->ic_mce = f15h_ic_mce;
795        break;
796
797    default:
798        printk(KERN_WARNING "Huh? What family is it: 0x%x?!\n", c->x86);
799        kfree(fam_ops);
800        return -EINVAL;
801    }
802
803    pr_info("MCE: In-kernel MCE decoding enabled.\n");
804
805    mce_register_decode_chain(&amd_mce_dec_nb);
806
807    return 0;
808}
809early_initcall(mce_amd_init);
810
811#ifdef MODULE
812static void __exit mce_amd_exit(void)
813{
814    mce_unregister_decode_chain(&amd_mce_dec_nb);
815    kfree(fam_ops);
816}
817
818MODULE_DESCRIPTION("AMD MCE decoder");
819MODULE_ALIAS("edac-mce-amd");
820MODULE_LICENSE("GPL");
821module_exit(mce_amd_exit);
822#endif
823

Archive Download this file



interactive