blob: d8e54b496e0f91655d0cc3241a07baf346543c5d [file] [log] [blame]
Mauro Carvalho Chehab77c5f5d2013-02-15 06:11:57 -03001/*
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
19struct ghes_edac_pvt {
20 struct list_head list;
21 struct ghes *ghes;
22 struct mem_ctl_info *mci;
23};
24
25static LIST_HEAD(ghes_reglist);
26static DEFINE_MUTEX(ghes_edac_lock);
27static int ghes_edac_mc_num;
28
29void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
30 struct cper_sec_mem_err *mem_err)
31{
32}
33EXPORT_SYMBOL_GPL(ghes_edac_report_mem_error);
34
35int 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}
98EXPORT_SYMBOL_GPL(ghes_edac_register);
99
100void 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}
114EXPORT_SYMBOL_GPL(ghes_edac_unregister);