]> git.proxmox.com Git - pve-kernel-jessie.git/blob - ie31200_edac-add-skylake-support.patch
update changelog, bump version to 4.4.16-62
[pve-kernel-jessie.git] / ie31200_edac-add-skylake-support.patch
1 From 953dee9bbd245f5515173126b9cc8b1a2c340797 Mon Sep 17 00:00:00 2001
2 From: Jason Baron <jbaron@akamai.com>
3 Date: Fri, 6 May 2016 11:18:47 -0400
4 Subject: EDAC, ie31200_edac: Add Skylake support
5
6 Skylake adjusts some register locations, but otherwise follows the
7 existing model quite closely. I was able to verify that the 'ce_count'
8 increments when 'bad dimms' are used. The accounting of 'ce_count' and
9 'ue_count' is the primary functionality of interest for us. Tested on
10 Intel(R) Xeon(R) CPU E3-1260L v5 @ 2.90GHz.
11
12 Signed-off-by: Jason Baron <jbaron@akamai.com>
13 Acked-by: Tony Luck <tony.luck@intel.com>
14 Cc: linux-edac <linux-edac@vger.kernel.org>
15 Link: http://lkml.kernel.org/r/1462547927-22679-1-git-send-email-jbaron@akamai.com
16 Signed-off-by: Borislav Petkov <bp@suse.de>
17 ---
18 drivers/edac/ie31200_edac.c | 121 ++++++++++++++++++++++++++++++++------------
19 1 file changed, 90 insertions(+), 31 deletions(-)
20
21 diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c
22 index 18d77ac..1c88d97 100644
23 --- a/drivers/edac/ie31200_edac.c
24 +++ b/drivers/edac/ie31200_edac.c
25 @@ -17,6 +17,7 @@
26 * 015c: Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller
27 * 0c04: Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller
28 * 0c08: Xeon E3-1200 v3 Processor DRAM Controller
29 + * 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers
30 *
31 * Based on Intel specification:
32 * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf
33 @@ -55,6 +56,7 @@
34 #define PCI_DEVICE_ID_INTEL_IE31200_HB_5 0x015c
35 #define PCI_DEVICE_ID_INTEL_IE31200_HB_6 0x0c04
36 #define PCI_DEVICE_ID_INTEL_IE31200_HB_7 0x0c08
37 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918
38
39 #define IE31200_DIMMS 4
40 #define IE31200_RANKS 8
41 @@ -105,8 +107,11 @@
42 * 1 Multiple Bit Error Status (MERRSTS)
43 * 0 Correctable Error Status (CERRSTS)
44 */
45 +
46 #define IE31200_C0ECCERRLOG 0x40c8
47 #define IE31200_C1ECCERRLOG 0x44c8
48 +#define IE31200_C0ECCERRLOG_SKL 0x4048
49 +#define IE31200_C1ECCERRLOG_SKL 0x4448
50 #define IE31200_ECCERRLOG_CE BIT(0)
51 #define IE31200_ECCERRLOG_UE BIT(1)
52 #define IE31200_ECCERRLOG_RANK_BITS GENMASK_ULL(28, 27)
53 @@ -123,17 +128,28 @@
54 #define IE31200_CAPID0_DDPCD BIT(6)
55 #define IE31200_CAPID0_ECC BIT(1)
56
57 -#define IE31200_MAD_DIMM_0_OFFSET 0x5004
58 -#define IE31200_MAD_DIMM_SIZE GENMASK_ULL(7, 0)
59 -#define IE31200_MAD_DIMM_A_RANK BIT(17)
60 -#define IE31200_MAD_DIMM_A_WIDTH BIT(19)
61 -
62 -#define IE31200_PAGES(n) (n << (28 - PAGE_SHIFT))
63 +#define IE31200_MAD_DIMM_0_OFFSET 0x5004
64 +#define IE31200_MAD_DIMM_0_OFFSET_SKL 0x500C
65 +#define IE31200_MAD_DIMM_SIZE GENMASK_ULL(7, 0)
66 +#define IE31200_MAD_DIMM_A_RANK BIT(17)
67 +#define IE31200_MAD_DIMM_A_RANK_SHIFT 17
68 +#define IE31200_MAD_DIMM_A_RANK_SKL BIT(10)
69 +#define IE31200_MAD_DIMM_A_RANK_SKL_SHIFT 10
70 +#define IE31200_MAD_DIMM_A_WIDTH BIT(19)
71 +#define IE31200_MAD_DIMM_A_WIDTH_SHIFT 19
72 +#define IE31200_MAD_DIMM_A_WIDTH_SKL GENMASK_ULL(9, 8)
73 +#define IE31200_MAD_DIMM_A_WIDTH_SKL_SHIFT 8
74 +
75 +/* Skylake reports 1GB increments, everything else is 256MB */
76 +#define IE31200_PAGES(n, skl) \
77 + (n << (28 + (2 * skl) - PAGE_SHIFT))
78
79 static int nr_channels;
80
81 struct ie31200_priv {
82 void __iomem *window;
83 + void __iomem *c0errlog;
84 + void __iomem *c1errlog;
85 };
86
87 enum ie31200_chips {
88 @@ -157,9 +173,9 @@ static const struct ie31200_dev_info ie31200_devs[] = {
89 };
90
91 struct dimm_data {
92 - u8 size; /* in 256MB multiples */
93 + u8 size; /* in multiples of 256MB, except Skylake is 1GB */
94 u8 dual_rank : 1,
95 - x16_width : 1; /* 0 means x8 width */
96 + x16_width : 2; /* 0 means x8 width */
97 };
98
99 static int how_many_channels(struct pci_dev *pdev)
100 @@ -197,11 +213,10 @@ static bool ecc_capable(struct pci_dev *pdev)
101 return true;
102 }
103
104 -static int eccerrlog_row(int channel, u64 log)
105 +static int eccerrlog_row(u64 log)
106 {
107 - int rank = ((log & IE31200_ECCERRLOG_RANK_BITS) >>
108 - IE31200_ECCERRLOG_RANK_SHIFT);
109 - return rank | (channel * IE31200_RANKS_PER_CHANNEL);
110 + return ((log & IE31200_ECCERRLOG_RANK_BITS) >>
111 + IE31200_ECCERRLOG_RANK_SHIFT);
112 }
113
114 static void ie31200_clear_error_info(struct mem_ctl_info *mci)
115 @@ -219,7 +234,6 @@ static void ie31200_get_and_clear_error_info(struct mem_ctl_info *mci,
116 {
117 struct pci_dev *pdev;
118 struct ie31200_priv *priv = mci->pvt_info;
119 - void __iomem *window = priv->window;
120
121 pdev = to_pci_dev(mci->pdev);
122
123 @@ -232,9 +246,9 @@ static void ie31200_get_and_clear_error_info(struct mem_ctl_info *mci,
124 if (!(info->errsts & IE31200_ERRSTS_BITS))
125 return;
126
127 - info->eccerrlog[0] = lo_hi_readq(window + IE31200_C0ECCERRLOG);
128 + info->eccerrlog[0] = lo_hi_readq(priv->c0errlog);
129 if (nr_channels == 2)
130 - info->eccerrlog[1] = lo_hi_readq(window + IE31200_C1ECCERRLOG);
131 + info->eccerrlog[1] = lo_hi_readq(priv->c1errlog);
132
133 pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts2);
134
135 @@ -245,10 +259,10 @@ static void ie31200_get_and_clear_error_info(struct mem_ctl_info *mci,
136 * should be UE info.
137 */
138 if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) {
139 - info->eccerrlog[0] = lo_hi_readq(window + IE31200_C0ECCERRLOG);
140 + info->eccerrlog[0] = lo_hi_readq(priv->c0errlog);
141 if (nr_channels == 2)
142 info->eccerrlog[1] =
143 - lo_hi_readq(window + IE31200_C1ECCERRLOG);
144 + lo_hi_readq(priv->c1errlog);
145 }
146
147 ie31200_clear_error_info(mci);
148 @@ -274,14 +288,14 @@ static void ie31200_process_error_info(struct mem_ctl_info *mci,
149 if (log & IE31200_ECCERRLOG_UE) {
150 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
151 0, 0, 0,
152 - eccerrlog_row(channel, log),
153 + eccerrlog_row(log),
154 channel, -1,
155 "ie31200 UE", "");
156 } else if (log & IE31200_ECCERRLOG_CE) {
157 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
158 0, 0,
159 IE31200_ECCERRLOG_SYNDROME(log),
160 - eccerrlog_row(channel, log),
161 + eccerrlog_row(log),
162 channel, -1,
163 "ie31200 CE", "");
164 }
165 @@ -326,6 +340,33 @@ static void __iomem *ie31200_map_mchbar(struct pci_dev *pdev)
166 return window;
167 }
168
169 +static void __skl_populate_dimm_info(struct dimm_data *dd, u32 addr_decode,
170 + int chan)
171 +{
172 + dd->size = (addr_decode >> (chan << 4)) & IE31200_MAD_DIMM_SIZE;
173 + dd->dual_rank = (addr_decode & (IE31200_MAD_DIMM_A_RANK_SKL << (chan << 4))) ? 1 : 0;
174 + dd->x16_width = ((addr_decode & (IE31200_MAD_DIMM_A_WIDTH_SKL << (chan << 4))) >>
175 + (IE31200_MAD_DIMM_A_WIDTH_SKL_SHIFT + (chan << 4)));
176 +}
177 +
178 +static void __populate_dimm_info(struct dimm_data *dd, u32 addr_decode,
179 + int chan)
180 +{
181 + dd->size = (addr_decode >> (chan << 3)) & IE31200_MAD_DIMM_SIZE;
182 + dd->dual_rank = (addr_decode & (IE31200_MAD_DIMM_A_RANK << chan)) ? 1 : 0;
183 + dd->x16_width = (addr_decode & (IE31200_MAD_DIMM_A_WIDTH << chan)) ? 1 : 0;
184 +}
185 +
186 +static void populate_dimm_info(struct dimm_data *dd, u32 addr_decode, int chan,
187 + bool skl)
188 +{
189 + if (skl)
190 + __skl_populate_dimm_info(dd, addr_decode, chan);
191 + else
192 + __populate_dimm_info(dd, addr_decode, chan);
193 +}
194 +
195 +
196 static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
197 {
198 int i, j, ret;
199 @@ -334,7 +375,8 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
200 struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL];
201 void __iomem *window;
202 struct ie31200_priv *priv;
203 - u32 addr_decode;
204 + u32 addr_decode, mad_offset;
205 + bool skl = (pdev->device == PCI_DEVICE_ID_INTEL_IE31200_HB_8);
206
207 edac_dbg(0, "MC:\n");
208
209 @@ -363,7 +405,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
210
211 edac_dbg(3, "MC: init mci\n");
212 mci->pdev = &pdev->dev;
213 - mci->mtype_cap = MEM_FLAG_DDR3;
214 + if (skl)
215 + mci->mtype_cap = MEM_FLAG_DDR4;
216 + else
217 + mci->mtype_cap = MEM_FLAG_DDR3;
218 mci->edac_ctl_cap = EDAC_FLAG_SECDED;
219 mci->edac_cap = EDAC_FLAG_SECDED;
220 mci->mod_name = EDAC_MOD_STR;
221 @@ -374,19 +419,24 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
222 mci->ctl_page_to_phys = NULL;
223 priv = mci->pvt_info;
224 priv->window = window;
225 + if (skl) {
226 + priv->c0errlog = window + IE31200_C0ECCERRLOG_SKL;
227 + priv->c1errlog = window + IE31200_C1ECCERRLOG_SKL;
228 + mad_offset = IE31200_MAD_DIMM_0_OFFSET_SKL;
229 + } else {
230 + priv->c0errlog = window + IE31200_C0ECCERRLOG;
231 + priv->c1errlog = window + IE31200_C1ECCERRLOG;
232 + mad_offset = IE31200_MAD_DIMM_0_OFFSET;
233 + }
234
235 /* populate DIMM info */
236 for (i = 0; i < IE31200_CHANNELS; i++) {
237 - addr_decode = readl(window + IE31200_MAD_DIMM_0_OFFSET +
238 + addr_decode = readl(window + mad_offset +
239 (i * 4));
240 edac_dbg(0, "addr_decode: 0x%x\n", addr_decode);
241 for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) {
242 - dimm_info[i][j].size = (addr_decode >> (j * 8)) &
243 - IE31200_MAD_DIMM_SIZE;
244 - dimm_info[i][j].dual_rank = (addr_decode &
245 - (IE31200_MAD_DIMM_A_RANK << j)) ? 1 : 0;
246 - dimm_info[i][j].x16_width = (addr_decode &
247 - (IE31200_MAD_DIMM_A_WIDTH << j)) ? 1 : 0;
248 + populate_dimm_info(&dimm_info[i][j], addr_decode, j,
249 + skl);
250 edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n",
251 dimm_info[i][j].size,
252 dimm_info[i][j].dual_rank,
253 @@ -405,7 +455,7 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
254 struct dimm_info *dimm;
255 unsigned long nr_pages;
256
257 - nr_pages = IE31200_PAGES(dimm_info[j][i].size);
258 + nr_pages = IE31200_PAGES(dimm_info[j][i].size, skl);
259 if (nr_pages == 0)
260 continue;
261
262 @@ -417,7 +467,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
263 dimm->nr_pages = nr_pages;
264 edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
265 dimm->grain = 8; /* just a guess */
266 - dimm->mtype = MEM_DDR3;
267 + if (skl)
268 + dimm->mtype = MEM_DDR4;
269 + else
270 + dimm->mtype = MEM_DDR3;
271 dimm->dtype = DEV_UNKNOWN;
272 dimm->edac_mode = EDAC_UNKNOWN;
273 }
274 @@ -426,7 +479,10 @@ static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
275 dimm->nr_pages = nr_pages;
276 edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
277 dimm->grain = 8; /* same guess */
278 - dimm->mtype = MEM_DDR3;
279 + if (skl)
280 + dimm->mtype = MEM_DDR4;
281 + else
282 + dimm->mtype = MEM_DDR3;
283 dimm->dtype = DEV_UNKNOWN;
284 dimm->edac_mode = EDAC_UNKNOWN;
285 }
286 @@ -501,6 +557,9 @@ static const struct pci_device_id ie31200_pci_tbl[] = {
287 PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
288 IE31200},
289 {
290 + PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
291 + IE31200},
292 + {
293 0,
294 } /* 0 terminated list. */
295 };
296 --
297 cgit v0.12
298