ghes_edac: Register at EDAC core the BIOS report
[firefly-linux-kernel-4.4.55.git] / drivers / edac / ghes_edac.c
1 /*
2  * GHES/EDAC Linux driver
3  *
4  * This file may be distributed under the terms of the GNU General Public
5  * License version 2.
6  *
7  * Copyright (c) 2013 by Mauro Carvalho Chehab <mchehab@redhat.com>
8  *
9  * Red Hat Inc. http://www.redhat.com
10  */
11
12 #include <acpi/ghes.h>
13 #include <linux/edac.h>
14 #include "edac_core.h"
15
16 #define GHES_PFX   "ghes_edac: "
17 #define GHES_EDAC_REVISION " Ver: 1.0.0"
18
19 struct ghes_edac_pvt {
20         struct list_head list;
21         struct ghes *ghes;
22         struct mem_ctl_info *mci;
23 };
24
25 static LIST_HEAD(ghes_reglist);
26 static DEFINE_MUTEX(ghes_edac_lock);
27 static int ghes_edac_mc_num;
28
29 void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
30                                struct cper_sec_mem_err *mem_err)
31 {
32 }
33 EXPORT_SYMBOL_GPL(ghes_edac_report_mem_error);
34
35 int ghes_edac_register(struct ghes *ghes, struct device *dev)
36 {
37         int rc;
38         struct mem_ctl_info *mci;
39         struct edac_mc_layer layers[1];
40         struct csrow_info *csrow;
41         struct dimm_info *dimm;
42         struct ghes_edac_pvt *pvt;
43
44         layers[0].type = EDAC_MC_LAYER_ALL_MEM;
45         layers[0].size = 1;
46         layers[0].is_virt_csrow = true;
47
48         /*
49          * We need to serialize edac_mc_alloc() and edac_mc_add_mc(),
50          * to avoid duplicated memory controller numbers
51          */
52         mutex_lock(&ghes_edac_lock);
53         mci = edac_mc_alloc(ghes_edac_mc_num, ARRAY_SIZE(layers), layers,
54                             sizeof(*pvt));
55         if (!mci) {
56                 pr_info(GHES_PFX "Can't allocate memory for EDAC data\n");
57                 mutex_unlock(&ghes_edac_lock);
58                 return -ENOMEM;
59         }
60
61         pvt = mci->pvt_info;
62         memset(pvt, 0, sizeof(*pvt));
63         list_add_tail(&pvt->list, &ghes_reglist);
64         pvt->ghes = ghes;
65         pvt->mci  = mci;
66         mci->pdev = dev;
67
68         mci->mtype_cap = MEM_FLAG_EMPTY;
69         mci->edac_ctl_cap = EDAC_FLAG_NONE;
70         mci->edac_cap = EDAC_FLAG_NONE;
71         mci->mod_name = "ghes_edac.c";
72         mci->mod_ver = GHES_EDAC_REVISION;
73         mci->ctl_name = "ghes_edac";
74         mci->dev_name = "ghes";
75
76         csrow = mci->csrows[0];
77         dimm = csrow->channels[0]->dimm;
78
79         /* FIXME: FAKE DATA */
80         dimm->nr_pages = 1000;
81         dimm->grain = 128;
82         dimm->mtype = MEM_UNKNOWN;
83         dimm->dtype = DEV_UNKNOWN;
84         dimm->edac_mode = EDAC_SECDED;
85
86         rc = edac_mc_add_mc(mci);
87         if (rc < 0) {
88                 pr_info(GHES_PFX "Can't register at EDAC core\n");
89                 edac_mc_free(mci);
90                 mutex_unlock(&ghes_edac_lock);
91                 return -ENODEV;
92         }
93
94         ghes_edac_mc_num++;
95         mutex_unlock(&ghes_edac_lock);
96         return 0;
97 }
98 EXPORT_SYMBOL_GPL(ghes_edac_register);
99
100 void ghes_edac_unregister(struct ghes *ghes)
101 {
102         struct mem_ctl_info *mci;
103         struct ghes_edac_pvt *pvt;
104
105         list_for_each_entry(pvt, &ghes_reglist, list) {
106                 if (ghes == pvt->ghes) {
107                         mci = pvt->mci;
108                         edac_mc_del_mc(mci->pdev);
109                         edac_mc_free(mci);
110                         list_del(&pvt->list);
111                 }
112         }
113 }
114 EXPORT_SYMBOL_GPL(ghes_edac_unregister);