aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-04 12:34:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-04 12:34:49 -0400
commitc2df436bd2504f52808c10ab7d7da832f61ad3f0 (patch)
treeb75aed765e66bad349f80d57b911b3f2822f6784
parentf74ad8df4e74db550e5a2372cc1f025e56e1d523 (diff)
parenteba4bfb34d45a2219d1d7534905c026eea6fcd49 (diff)
Merge tag 'edac_for_3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp
Pull EDAC changes from Borislav Petkov: "EDAC queue for 3.17: - One new edac driver for Intel E3-12xx DRAM controllers. - Out-of-subsystem changes are making the non-atomic iomem 64-bit accessors' naming explicit to show both exact order of the 32-bit accesses and the non-atomicity of the 64-bit access. Usage locations are more verbose now as to what access is exactly being done vs having a not-very telling "readq" there, for example. This is needed by E3-12xx hardware where certain mmapped registers cannot be accessed with requests crossing a dword boundary. From Jason Baron. - Extending AMD MCE signatures to a new model 60h in family 15h, from Aravind Gopalakrishnan. - An unsigned check cleanup, from Fabian Frederick" * tag 'edac_for_3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp: EDAC, MCE, AMD: Add MCE decoding for F15h M60h MAINTAINERS: add ie31200_edac entry ie31200_edac: Allocate mci and map mchbar first ie31200_edac: Introduce the driver x38_edac: make use of lo_hi_readq() readq/writeq: Add explicit lo_hi_[read|write]_q and hi_lo_[read|write]_q EDAC, edac_module.c: Remove unnecessary test on unsigned value
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/edac/Kconfig7
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/edac_module.c2
-rw-r--r--drivers/edac/ie31200_edac.c536
-rw-r--r--drivers/edac/mce_amd.c44
-rw-r--r--drivers/edac/x38_edac.c15
-rw-r--r--include/asm-generic/io-64-nonatomic-hi-lo.h14
-rw-r--r--include/asm-generic/io-64-nonatomic-lo-hi.h14
9 files changed, 616 insertions, 24 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index c2066f4c3286..4f05c699daf8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3350,6 +3350,13 @@ W: bluesmoke.sourceforge.net
3350S: Maintained 3350S: Maintained
3351F: drivers/edac/i82975x_edac.c 3351F: drivers/edac/i82975x_edac.c
3352 3352
3353EDAC-IE31200
3354M: Jason Baron <jbaron@akamai.com>
3355L: linux-edac@vger.kernel.org
3356W: bluesmoke.sourceforge.net
3357S: Maintained
3358F: drivers/edac/ie31200_edac.c
3359
3353EDAC-MPC85XX 3360EDAC-MPC85XX
3354M: Johannes Thumshirn <johannes.thumshirn@men.de> 3361M: Johannes Thumshirn <johannes.thumshirn@men.de>
3355L: linux-edac@vger.kernel.org 3362L: linux-edac@vger.kernel.org
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 878f09005fad..e339c6b91425 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -186,6 +186,13 @@ config EDAC_I3200
186 Support for error detection and correction on the Intel 186 Support for error detection and correction on the Intel
187 3200 and 3210 server chipsets. 187 3200 and 3210 server chipsets.
188 188
189config EDAC_IE31200
190 tristate "Intel e312xx"
191 depends on EDAC_MM_EDAC && PCI && X86
192 help
193 Support for error detection and correction on the Intel
194 E3-1200 based DRAM controllers.
195
189config EDAC_X38 196config EDAC_X38
190 tristate "Intel X38" 197 tristate "Intel X38"
191 depends on EDAC_MM_EDAC && PCI && X86 198 depends on EDAC_MM_EDAC && PCI && X86
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 4154ed6a02c6..c479a24d8f77 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_EDAC_I82875P) += i82875p_edac.o
37obj-$(CONFIG_EDAC_I82975X) += i82975x_edac.o 37obj-$(CONFIG_EDAC_I82975X) += i82975x_edac.o
38obj-$(CONFIG_EDAC_I3000) += i3000_edac.o 38obj-$(CONFIG_EDAC_I3000) += i3000_edac.o
39obj-$(CONFIG_EDAC_I3200) += i3200_edac.o 39obj-$(CONFIG_EDAC_I3200) += i3200_edac.o
40obj-$(CONFIG_EDAC_IE31200) += ie31200_edac.o
40obj-$(CONFIG_EDAC_X38) += x38_edac.o 41obj-$(CONFIG_EDAC_X38) += x38_edac.o
41obj-$(CONFIG_EDAC_I82860) += i82860_edac.o 42obj-$(CONFIG_EDAC_I82860) += i82860_edac.o
42obj-$(CONFIG_EDAC_R82600) += r82600_edac.o 43obj-$(CONFIG_EDAC_R82600) += r82600_edac.o
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index a66941fea5a4..e6d1691dfa45 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -28,7 +28,7 @@ static int edac_set_debug_level(const char *buf, struct kernel_param *kp)
28 if (ret) 28 if (ret)
29 return ret; 29 return ret;
30 30
31 if (val < 0 || val > 4) 31 if (val > 4)
32 return -EINVAL; 32 return -EINVAL;
33 33
34 return param_set_int(buf, kp); 34 return param_set_int(buf, kp);
diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c
new file mode 100644
index 000000000000..a981dc6fd88e
--- /dev/null
+++ b/drivers/edac/ie31200_edac.c
@@ -0,0 +1,536 @@
1/*
2 * Intel E3-1200
3 * Copyright (C) 2014 Jason Baron <jbaron@akamai.com>
4 *
5 * Support for the E3-1200 processor family. Heavily based on previous
6 * Intel EDAC drivers.
7 *
8 * Since the DRAM controller is on the cpu chip, we can use its PCI device
9 * id to identify these processors.
10 *
11 * PCI DRAM controller device ids (Taken from The PCI ID Repository - http://pci-ids.ucw.cz/)
12 *
13 * 0108: Xeon E3-1200 Processor Family DRAM Controller
14 * 010c: Xeon E3-1200/2nd Generation Core Processor Family DRAM Controller
15 * 0150: Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller
16 * 0158: Xeon E3-1200 v2/Ivy Bridge DRAM Controller
17 * 015c: Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller
18 * 0c04: Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller
19 * 0c08: Xeon E3-1200 v3 Processor DRAM Controller
20 *
21 * Based on Intel specification:
22 * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf
23 * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html
24 *
25 * According to the above datasheet (p.16):
26 * "
27 * 6. Software must not access B0/D0/F0 32-bit memory-mapped registers with
28 * requests that cross a DW boundary.
29 * "
30 *
31 * Thus, we make use of the explicit: lo_hi_readq(), which breaks the readq into
32 * 2 readl() calls. This restriction may be lifted in subsequent chip releases,
33 * but lo_hi_readq() ensures that we are safe across all e3-1200 processors.
34 */
35
36#include <linux/module.h>
37#include <linux/init.h>
38#include <linux/pci.h>
39#include <linux/pci_ids.h>
40#include <linux/edac.h>
41
42#include <asm-generic/io-64-nonatomic-lo-hi.h>
43#include "edac_core.h"
44
45#define IE31200_REVISION "1.0"
46#define EDAC_MOD_STR "ie31200_edac"
47
48#define ie31200_printk(level, fmt, arg...) \
49 edac_printk(level, "ie31200", fmt, ##arg)
50
51#define PCI_DEVICE_ID_INTEL_IE31200_HB_1 0x0108
52#define PCI_DEVICE_ID_INTEL_IE31200_HB_2 0x010c
53#define PCI_DEVICE_ID_INTEL_IE31200_HB_3 0x0150
54#define PCI_DEVICE_ID_INTEL_IE31200_HB_4 0x0158
55#define PCI_DEVICE_ID_INTEL_IE31200_HB_5 0x015c
56#define PCI_DEVICE_ID_INTEL_IE31200_HB_6 0x0c04
57#define PCI_DEVICE_ID_INTEL_IE31200_HB_7 0x0c08
58
59#define IE31200_DIMMS 4
60#define IE31200_RANKS 8
61#define IE31200_RANKS_PER_CHANNEL 4
62#define IE31200_DIMMS_PER_CHANNEL 2
63#define IE31200_CHANNELS 2
64
65/* Intel IE31200 register addresses - device 0 function 0 - DRAM Controller */
66#define IE31200_MCHBAR_LOW 0x48
67#define IE31200_MCHBAR_HIGH 0x4c
68#define IE31200_MCHBAR_MASK GENMASK_ULL(38, 15)
69#define IE31200_MMR_WINDOW_SIZE BIT(15)
70
71/*
72 * Error Status Register (16b)
73 *
74 * 15 reserved
75 * 14 Isochronous TBWRR Run Behind FIFO Full
76 * (ITCV)
77 * 13 Isochronous TBWRR Run Behind FIFO Put
78 * (ITSTV)
79 * 12 reserved
80 * 11 MCH Thermal Sensor Event
81 * for SMI/SCI/SERR (GTSE)
82 * 10 reserved
83 * 9 LOCK to non-DRAM Memory Flag (LCKF)
84 * 8 reserved
85 * 7 DRAM Throttle Flag (DTF)
86 * 6:2 reserved
87 * 1 Multi-bit DRAM ECC Error Flag (DMERR)
88 * 0 Single-bit DRAM ECC Error Flag (DSERR)
89 */
90#define IE31200_ERRSTS 0xc8
91#define IE31200_ERRSTS_UE BIT(1)
92#define IE31200_ERRSTS_CE BIT(0)
93#define IE31200_ERRSTS_BITS (IE31200_ERRSTS_UE | IE31200_ERRSTS_CE)
94
95/*
96 * Channel 0 ECC Error Log (64b)
97 *
98 * 63:48 Error Column Address (ERRCOL)
99 * 47:32 Error Row Address (ERRROW)
100 * 31:29 Error Bank Address (ERRBANK)
101 * 28:27 Error Rank Address (ERRRANK)
102 * 26:24 reserved
103 * 23:16 Error Syndrome (ERRSYND)
104 * 15: 2 reserved
105 * 1 Multiple Bit Error Status (MERRSTS)
106 * 0 Correctable Error Status (CERRSTS)
107 */
108#define IE31200_C0ECCERRLOG 0x40c8
109#define IE31200_C1ECCERRLOG 0x44c8
110#define IE31200_ECCERRLOG_CE BIT(0)
111#define IE31200_ECCERRLOG_UE BIT(1)
112#define IE31200_ECCERRLOG_RANK_BITS GENMASK_ULL(28, 27)
113#define IE31200_ECCERRLOG_RANK_SHIFT 27
114#define IE31200_ECCERRLOG_SYNDROME_BITS GENMASK_ULL(23, 16)
115#define IE31200_ECCERRLOG_SYNDROME_SHIFT 16
116
117#define IE31200_ECCERRLOG_SYNDROME(log) \
118 ((log & IE31200_ECCERRLOG_SYNDROME_BITS) >> \
119 IE31200_ECCERRLOG_SYNDROME_SHIFT)
120
121#define IE31200_CAPID0 0xe4
122#define IE31200_CAPID0_PDCD BIT(4)
123#define IE31200_CAPID0_DDPCD BIT(6)
124#define IE31200_CAPID0_ECC BIT(1)
125
126#define IE31200_MAD_DIMM_0_OFFSET 0x5004
127#define IE31200_MAD_DIMM_SIZE GENMASK_ULL(7, 0)
128#define IE31200_MAD_DIMM_A_RANK BIT(17)
129#define IE31200_MAD_DIMM_A_WIDTH BIT(19)
130
131#define IE31200_PAGES(n) (n << (28 - PAGE_SHIFT))
132
133static int nr_channels;
134
135struct ie31200_priv {
136 void __iomem *window;
137};
138
139enum ie31200_chips {
140 IE31200 = 0,
141};
142
143struct ie31200_dev_info {
144 const char *ctl_name;
145};
146
147struct ie31200_error_info {
148 u16 errsts;
149 u16 errsts2;
150 u64 eccerrlog[IE31200_CHANNELS];
151};
152
153static const struct ie31200_dev_info ie31200_devs[] = {
154 [IE31200] = {
155 .ctl_name = "IE31200"
156 },
157};
158
159struct dimm_data {
160 u8 size; /* in 256MB multiples */
161 u8 dual_rank : 1,
162 x16_width : 1; /* 0 means x8 width */
163};
164
165static int how_many_channels(struct pci_dev *pdev)
166{
167 int n_channels;
168 unsigned char capid0_2b; /* 2nd byte of CAPID0 */
169
170 pci_read_config_byte(pdev, IE31200_CAPID0 + 1, &capid0_2b);
171
172 /* check PDCD: Dual Channel Disable */
173 if (capid0_2b & IE31200_CAPID0_PDCD) {
174 edac_dbg(0, "In single channel mode\n");
175 n_channels = 1;
176 } else {
177 edac_dbg(0, "In dual channel mode\n");
178 n_channels = 2;
179 }
180
181 /* check DDPCD - check if both channels are filled */
182 if (capid0_2b & IE31200_CAPID0_DDPCD)
183 edac_dbg(0, "2 DIMMS per channel disabled\n");
184 else
185 edac_dbg(0, "2 DIMMS per channel enabled\n");
186
187 return n_channels;
188}
189
190static bool ecc_capable(struct pci_dev *pdev)
191{
192 unsigned char capid0_4b; /* 4th byte of CAPID0 */
193
194 pci_read_config_byte(pdev, IE31200_CAPID0 + 3, &capid0_4b);
195 if (capid0_4b & IE31200_CAPID0_ECC)
196 return false;
197 return true;
198}
199
200static int eccerrlog_row(int channel, u64 log)
201{
202 int rank = ((log & IE31200_ECCERRLOG_RANK_BITS) >>
203 IE31200_ECCERRLOG_RANK_SHIFT);
204 return rank | (channel * IE31200_RANKS_PER_CHANNEL);
205}
206
207static void ie31200_clear_error_info(struct mem_ctl_info *mci)
208{
209 /*
210 * Clear any error bits.
211 * (Yes, we really clear bits by writing 1 to them.)
212 */
213 pci_write_bits16(to_pci_dev(mci->pdev), IE31200_ERRSTS,
214 IE31200_ERRSTS_BITS, IE31200_ERRSTS_BITS);
215}
216
217static void ie31200_get_and_clear_error_info(struct mem_ctl_info *mci,
218 struct ie31200_error_info *info)
219{
220 struct pci_dev *pdev;
221 struct ie31200_priv *priv = mci->pvt_info;
222 void __iomem *window = priv->window;
223
224 pdev = to_pci_dev(mci->pdev);
225
226 /*
227 * This is a mess because there is no atomic way to read all the
228 * registers at once and the registers can transition from CE being
229 * overwritten by UE.
230 */
231 pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts);
232 if (!(info->errsts & IE31200_ERRSTS_BITS))
233 return;
234
235 info->eccerrlog[0] = lo_hi_readq(window + IE31200_C0ECCERRLOG);
236 if (nr_channels == 2)
237 info->eccerrlog[1] = lo_hi_readq(window + IE31200_C1ECCERRLOG);
238
239 pci_read_config_word(pdev, IE31200_ERRSTS, &info->errsts2);
240
241 /*
242 * If the error is the same for both reads then the first set
243 * of reads is valid. If there is a change then there is a CE
244 * with no info and the second set of reads is valid and
245 * should be UE info.
246 */
247 if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) {
248 info->eccerrlog[0] = lo_hi_readq(window + IE31200_C0ECCERRLOG);
249 if (nr_channels == 2)
250 info->eccerrlog[1] =
251 lo_hi_readq(window + IE31200_C1ECCERRLOG);
252 }
253
254 ie31200_clear_error_info(mci);
255}
256
257static void ie31200_process_error_info(struct mem_ctl_info *mci,
258 struct ie31200_error_info *info)
259{
260 int channel;
261 u64 log;
262
263 if (!(info->errsts & IE31200_ERRSTS_BITS))
264 return;
265
266 if ((info->errsts ^ info->errsts2) & IE31200_ERRSTS_BITS) {
267 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 0, 0, 0,
268 -1, -1, -1, "UE overwrote CE", "");
269 info->errsts = info->errsts2;
270 }
271
272 for (channel = 0; channel < nr_channels; channel++) {
273 log = info->eccerrlog[channel];
274 if (log & IE31200_ECCERRLOG_UE) {
275 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
276 0, 0, 0,
277 eccerrlog_row(channel, log),
278 channel, -1,
279 "ie31200 UE", "");
280 } else if (log & IE31200_ECCERRLOG_CE) {
281 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
282 0, 0,
283 IE31200_ECCERRLOG_SYNDROME(log),
284 eccerrlog_row(channel, log),
285 channel, -1,
286 "ie31200 CE", "");
287 }
288 }
289}
290
291static void ie31200_check(struct mem_ctl_info *mci)
292{
293 struct ie31200_error_info info;
294
295 edac_dbg(1, "MC%d\n", mci->mc_idx);
296 ie31200_get_and_clear_error_info(mci, &info);
297 ie31200_process_error_info(mci, &info);
298}
299
300static void __iomem *ie31200_map_mchbar(struct pci_dev *pdev)
301{
302 union {
303 u64 mchbar;
304 struct {
305 u32 mchbar_low;
306 u32 mchbar_high;
307 };
308 } u;
309 void __iomem *window;
310
311 pci_read_config_dword(pdev, IE31200_MCHBAR_LOW, &u.mchbar_low);
312 pci_read_config_dword(pdev, IE31200_MCHBAR_HIGH, &u.mchbar_high);
313 u.mchbar &= IE31200_MCHBAR_MASK;
314
315 if (u.mchbar != (resource_size_t)u.mchbar) {
316 ie31200_printk(KERN_ERR, "mmio space beyond accessible range (0x%llx)\n",
317 (unsigned long long)u.mchbar);
318 return NULL;
319 }
320
321 window = ioremap_nocache(u.mchbar, IE31200_MMR_WINDOW_SIZE);
322 if (!window)
323 ie31200_printk(KERN_ERR, "Cannot map mmio space at 0x%llx\n",
324 (unsigned long long)u.mchbar);
325
326 return window;
327}
328
329static int ie31200_probe1(struct pci_dev *pdev, int dev_idx)
330{
331 int i, j, ret;
332 struct mem_ctl_info *mci = NULL;
333 struct edac_mc_layer layers[2];
334 struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL];
335 void __iomem *window;
336 struct ie31200_priv *priv;
337 u32 addr_decode;
338
339 edac_dbg(0, "MC:\n");
340
341 if (!ecc_capable(pdev)) {
342 ie31200_printk(KERN_INFO, "No ECC support\n");
343 return -ENODEV;
344 }
345
346 nr_channels = how_many_channels(pdev);
347 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
348 layers[0].size = IE31200_DIMMS;
349 layers[0].is_virt_csrow = true;
350 layers[1].type = EDAC_MC_LAYER_CHANNEL;
351 layers[1].size = nr_channels;
352 layers[1].is_virt_csrow = false;
353 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
354 sizeof(struct ie31200_priv));
355 if (!mci)
356 return -ENOMEM;
357
358 window = ie31200_map_mchbar(pdev);
359 if (!window) {
360 ret = -ENODEV;
361 goto fail_free;
362 }
363
364 edac_dbg(3, "MC: init mci\n");
365 mci->pdev = &pdev->dev;
366 mci->mtype_cap = MEM_FLAG_DDR3;
367 mci->edac_ctl_cap = EDAC_FLAG_SECDED;
368 mci->edac_cap = EDAC_FLAG_SECDED;
369 mci->mod_name = EDAC_MOD_STR;
370 mci->mod_ver = IE31200_REVISION;
371 mci->ctl_name = ie31200_devs[dev_idx].ctl_name;
372 mci->dev_name = pci_name(pdev);
373 mci->edac_check = ie31200_check;
374 mci->ctl_page_to_phys = NULL;
375 priv = mci->pvt_info;
376 priv->window = window;
377
378 /* populate DIMM info */
379 for (i = 0; i < IE31200_CHANNELS; i++) {
380 addr_decode = readl(window + IE31200_MAD_DIMM_0_OFFSET +
381 (i * 4));
382 edac_dbg(0, "addr_decode: 0x%x\n", addr_decode);
383 for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) {
384 dimm_info[i][j].size = (addr_decode >> (j * 8)) &
385 IE31200_MAD_DIMM_SIZE;
386 dimm_info[i][j].dual_rank = (addr_decode &
387 (IE31200_MAD_DIMM_A_RANK << j)) ? 1 : 0;
388 dimm_info[i][j].x16_width = (addr_decode &
389 (IE31200_MAD_DIMM_A_WIDTH << j)) ? 1 : 0;
390 edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n",
391 dimm_info[i][j].size,
392 dimm_info[i][j].dual_rank,
393 dimm_info[i][j].x16_width);
394 }
395 }
396
397 /*
398 * The dram rank boundary (DRB) reg values are boundary addresses
399 * for each DRAM rank with a granularity of 64MB. DRB regs are
400 * cumulative; the last one will contain the total memory
401 * contained in all ranks.
402 */
403 for (i = 0; i < IE31200_DIMMS_PER_CHANNEL; i++) {
404 for (j = 0; j < IE31200_CHANNELS; j++) {
405 struct dimm_info *dimm;
406 unsigned long nr_pages;
407
408 nr_pages = IE31200_PAGES(dimm_info[j][i].size);
409 if (nr_pages == 0)
410 continue;
411
412 if (dimm_info[j][i].dual_rank) {
413 nr_pages = nr_pages / 2;
414 dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
415 mci->n_layers, (i * 2) + 1,
416 j, 0);
417 dimm->nr_pages = nr_pages;
418 edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
419 dimm->grain = 8; /* just a guess */
420 dimm->mtype = MEM_DDR3;
421 dimm->dtype = DEV_UNKNOWN;
422 dimm->edac_mode = EDAC_UNKNOWN;
423 }
424 dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
425 mci->n_layers, i * 2, j, 0);
426 dimm->nr_pages = nr_pages;
427 edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
428 dimm->grain = 8; /* same guess */
429 dimm->mtype = MEM_DDR3;
430 dimm->dtype = DEV_UNKNOWN;
431 dimm->edac_mode = EDAC_UNKNOWN;
432 }
433 }
434
435 ie31200_clear_error_info(mci);
436
437 if (edac_mc_add_mc(mci)) {
438 edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
439 ret = -ENODEV;
440 goto fail_unmap;
441 }
442
443 /* get this far and it's successful */
444 edac_dbg(3, "MC: success\n");
445 return 0;
446
447fail_unmap:
448 iounmap(window);
449
450fail_free:
451 edac_mc_free(mci);
452
453 return ret;
454}
455
456static int ie31200_init_one(struct pci_dev *pdev,
457 const struct pci_device_id *ent)
458{
459 edac_dbg(0, "MC:\n");
460
461 if (pci_enable_device(pdev) < 0)
462 return -EIO;
463
464 return ie31200_probe1(pdev, ent->driver_data);
465}
466
467static void ie31200_remove_one(struct pci_dev *pdev)
468{
469 struct mem_ctl_info *mci;
470 struct ie31200_priv *priv;
471
472 edac_dbg(0, "\n");
473 mci = edac_mc_del_mc(&pdev->dev);
474 if (!mci)
475 return;
476 priv = mci->pvt_info;
477 iounmap(priv->window);
478 edac_mc_free(mci);
479}
480
481static const struct pci_device_id ie31200_pci_tbl[] = {
482 {
483 PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
484 IE31200},
485 {
486 PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
487 IE31200},
488 {
489 PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
490 IE31200},
491 {
492 PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
493 IE31200},
494 {
495 PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
496 IE31200},
497 {
498 PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
499 IE31200},
500 {
501 PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
502 IE31200},
503 {
504 0,
505 } /* 0 terminated list. */
506};
507MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl);
508
509static struct pci_driver ie31200_driver = {
510 .name = EDAC_MOD_STR,
511 .probe = ie31200_init_one,
512 .remove = ie31200_remove_one,
513 .id_table = ie31200_pci_tbl,
514};
515
516static int __init ie31200_init(void)
517{
518 edac_dbg(3, "MC:\n");
519 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
520 opstate_init();
521
522 return pci_register_driver(&ie31200_driver);
523}
524
525static void __exit ie31200_exit(void)
526{
527 edac_dbg(3, "MC:\n");
528 pci_unregister_driver(&ie31200_driver);
529}
530
531module_init(ie31200_init);
532module_exit(ie31200_exit);
533
534MODULE_LICENSE("GPL");
535MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>");
536MODULE_DESCRIPTION("MC support for Intel Processor E31200 memory hub controllers");
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index 5f43620d580a..f78c1c54dbd5 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -78,7 +78,8 @@ static const char * const f15h_mc1_mce_desc[] = {
78 "uop queue", 78 "uop queue",
79 "insn buffer", 79 "insn buffer",
80 "predecode buffer", 80 "predecode buffer",
81 "fetch address FIFO" 81 "fetch address FIFO",
82 "dispatch uop queue"
82}; 83};
83 84
84static const char * const f15h_mc2_mce_desc[] = { 85static const char * const f15h_mc2_mce_desc[] = {
@@ -267,6 +268,12 @@ static bool f15h_mc0_mce(u16 ec, u8 xec)
267 pr_cont("System Read Data Error.\n"); 268 pr_cont("System Read Data Error.\n");
268 else 269 else
269 pr_cont(" Internal error condition type %d.\n", xec); 270 pr_cont(" Internal error condition type %d.\n", xec);
271 } else if (INT_ERROR(ec)) {
272 if (xec <= 0x1f)
273 pr_cont("Hardware Assert.\n");
274 else
275 ret = false;
276
270 } else 277 } else
271 ret = false; 278 ret = false;
272 279
@@ -373,7 +380,7 @@ static bool f15h_mc1_mce(u16 ec, u8 xec)
373 pr_cont("%s.\n", f15h_mc1_mce_desc[xec-4]); 380 pr_cont("%s.\n", f15h_mc1_mce_desc[xec-4]);
374 break; 381 break;
375 382
376 case 0x11 ... 0x14: 383 case 0x11 ... 0x15:
377 pr_cont("Decoder %s parity error.\n", f15h_mc1_mce_desc[xec-4]); 384 pr_cont("Decoder %s parity error.\n", f15h_mc1_mce_desc[xec-4]);
378 break; 385 break;
379 386
@@ -397,10 +404,20 @@ static void decode_mc1_mce(struct mce *m)
397 bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58))); 404 bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58)));
398 405
399 pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read")); 406 pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read"));
407 } else if (INT_ERROR(ec)) {
408 if (xec <= 0x3f)
409 pr_cont("Hardware Assert.\n");
410 else
411 goto wrong_mc1_mce;
400 } else if (fam_ops->mc1_mce(ec, xec)) 412 } else if (fam_ops->mc1_mce(ec, xec))
401 ; 413 ;
402 else 414 else
403 pr_emerg(HW_ERR "Corrupted MC1 MCE info?\n"); 415 goto wrong_mc1_mce;
416
417 return;
418
419wrong_mc1_mce:
420 pr_emerg(HW_ERR "Corrupted MC1 MCE info?\n");
404} 421}
405 422
406static bool k8_mc2_mce(u16 ec, u8 xec) 423static bool k8_mc2_mce(u16 ec, u8 xec)
@@ -468,6 +485,11 @@ static bool f15h_mc2_mce(u16 ec, u8 xec)
468 default: 485 default:
469 ret = false; 486 ret = false;
470 } 487 }
488 } else if (INT_ERROR(ec)) {
489 if (xec <= 0x3f)
490 pr_cont("Hardware Assert.\n");
491 else
492 ret = false;
471 } 493 }
472 494
473 return ret; 495 return ret;
@@ -615,6 +637,7 @@ static void decode_mc4_mce(struct mce *m)
615static void decode_mc5_mce(struct mce *m) 637static void decode_mc5_mce(struct mce *m)
616{ 638{
617 struct cpuinfo_x86 *c = &boot_cpu_data; 639 struct cpuinfo_x86 *c = &boot_cpu_data;
640 u16 ec = EC(m->status);
618 u8 xec = XEC(m->status, xec_mask); 641 u8 xec = XEC(m->status, xec_mask);
619 642
620 if (c->x86 == 0xf || c->x86 == 0x11) 643 if (c->x86 == 0xf || c->x86 == 0x11)
@@ -622,6 +645,14 @@ static void decode_mc5_mce(struct mce *m)
622 645
623 pr_emerg(HW_ERR "MC5 Error: "); 646 pr_emerg(HW_ERR "MC5 Error: ");
624 647
648 if (INT_ERROR(ec)) {
649 if (xec <= 0x1f) {
650 pr_cont("Hardware Assert.\n");
651 return;
652 } else
653 goto wrong_mc5_mce;
654 }
655
625 if (xec == 0x0 || xec == 0xc) 656 if (xec == 0x0 || xec == 0xc)
626 pr_cont("%s.\n", mc5_mce_desc[xec]); 657 pr_cont("%s.\n", mc5_mce_desc[xec]);
627 else if (xec <= 0xd) 658 else if (xec <= 0xd)
@@ -642,6 +673,10 @@ static void decode_mc6_mce(struct mce *m)
642 pr_emerg(HW_ERR "MC6 Error: "); 673 pr_emerg(HW_ERR "MC6 Error: ");
643 674
644 switch (xec) { 675 switch (xec) {
676 case 0x0:
677 pr_cont("Hardware Assertion");
678 break;
679
645 case 0x1: 680 case 0x1:
646 pr_cont("Free List"); 681 pr_cont("Free List");
647 break; 682 break;
@@ -857,7 +892,8 @@ static int __init mce_amd_init(void)
857 break; 892 break;
858 893
859 case 0x15: 894 case 0x15:
860 xec_mask = 0x1f; 895 xec_mask = c->x86_model == 0x60 ? 0x3f : 0x1f;
896
861 fam_ops->mc0_mce = f15h_mc0_mce; 897 fam_ops->mc0_mce = f15h_mc0_mce;
862 fam_ops->mc1_mce = f15h_mc1_mce; 898 fam_ops->mc1_mce = f15h_mc1_mce;
863 fam_ops->mc2_mce = f15h_mc2_mce; 899 fam_ops->mc2_mce = f15h_mc2_mce;
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index 4891b450830b..e644b52c287c 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
@@ -14,6 +14,8 @@
14#include <linux/pci.h> 14#include <linux/pci.h>
15#include <linux/pci_ids.h> 15#include <linux/pci_ids.h>
16#include <linux/edac.h> 16#include <linux/edac.h>
17
18#include <asm-generic/io-64-nonatomic-lo-hi.h>
17#include "edac_core.h" 19#include "edac_core.h"
18 20
19#define X38_REVISION "1.1" 21#define X38_REVISION "1.1"
@@ -161,11 +163,6 @@ static void x38_clear_error_info(struct mem_ctl_info *mci)
161 X38_ERRSTS_BITS); 163 X38_ERRSTS_BITS);
162} 164}
163 165
164static u64 x38_readq(const void __iomem *addr)
165{
166 return readl(addr) | (((u64)readl(addr + 4)) << 32);
167}
168
169static void x38_get_and_clear_error_info(struct mem_ctl_info *mci, 166static void x38_get_and_clear_error_info(struct mem_ctl_info *mci,
170 struct x38_error_info *info) 167 struct x38_error_info *info)
171{ 168{
@@ -183,9 +180,9 @@ static void x38_get_and_clear_error_info(struct mem_ctl_info *mci,
183 if (!(info->errsts & X38_ERRSTS_BITS)) 180 if (!(info->errsts & X38_ERRSTS_BITS))
184 return; 181 return;
185 182
186 info->eccerrlog[0] = x38_readq(window + X38_C0ECCERRLOG); 183 info->eccerrlog[0] = lo_hi_readq(window + X38_C0ECCERRLOG);
187 if (x38_channel_num == 2) 184 if (x38_channel_num == 2)
188 info->eccerrlog[1] = x38_readq(window + X38_C1ECCERRLOG); 185 info->eccerrlog[1] = lo_hi_readq(window + X38_C1ECCERRLOG);
189 186
190 pci_read_config_word(pdev, X38_ERRSTS, &info->errsts2); 187 pci_read_config_word(pdev, X38_ERRSTS, &info->errsts2);
191 188
@@ -196,10 +193,10 @@ static void x38_get_and_clear_error_info(struct mem_ctl_info *mci,
196 * should be UE info. 193 * should be UE info.
197 */ 194 */
198 if ((info->errsts ^ info->errsts2) & X38_ERRSTS_BITS) { 195 if ((info->errsts ^ info->errsts2) & X38_ERRSTS_BITS) {
199 info->eccerrlog[0] = x38_readq(window + X38_C0ECCERRLOG); 196 info->eccerrlog[0] = lo_hi_readq(window + X38_C0ECCERRLOG);
200 if (x38_channel_num == 2) 197 if (x38_channel_num == 2)
201 info->eccerrlog[1] = 198 info->eccerrlog[1] =
202 x38_readq(window + X38_C1ECCERRLOG); 199 lo_hi_readq(window + X38_C1ECCERRLOG);
203 } 200 }
204 201
205 x38_clear_error_info(mci); 202 x38_clear_error_info(mci);
diff --git a/include/asm-generic/io-64-nonatomic-hi-lo.h b/include/asm-generic/io-64-nonatomic-hi-lo.h
index a6806a94250d..2e29d13fc154 100644
--- a/include/asm-generic/io-64-nonatomic-hi-lo.h
+++ b/include/asm-generic/io-64-nonatomic-hi-lo.h
@@ -4,8 +4,7 @@
4#include <linux/io.h> 4#include <linux/io.h>
5#include <asm-generic/int-ll64.h> 5#include <asm-generic/int-ll64.h>
6 6
7#ifndef readq 7static inline __u64 hi_lo_readq(const volatile void __iomem *addr)
8static inline __u64 readq(const volatile void __iomem *addr)
9{ 8{
10 const volatile u32 __iomem *p = addr; 9 const volatile u32 __iomem *p = addr;
11 u32 low, high; 10 u32 low, high;
@@ -15,14 +14,19 @@ static inline __u64 readq(const volatile void __iomem *addr)
15 14
16 return low + ((u64)high << 32); 15 return low + ((u64)high << 32);
17} 16}
18#endif
19 17
20#ifndef writeq 18static inline void hi_lo_writeq(__u64 val, volatile void __iomem *addr)
21static inline void writeq(__u64 val, volatile void __iomem *addr)
22{ 19{
23 writel(val >> 32, addr + 4); 20 writel(val >> 32, addr + 4);
24 writel(val, addr); 21 writel(val, addr);
25} 22}
23
24#ifndef readq
25#define readq hi_lo_readq
26#endif
27
28#ifndef writeq
29#define writeq hi_lo_writeq
26#endif 30#endif
27 31
28#endif /* _ASM_IO_64_NONATOMIC_HI_LO_H_ */ 32#endif /* _ASM_IO_64_NONATOMIC_HI_LO_H_ */
diff --git a/include/asm-generic/io-64-nonatomic-lo-hi.h b/include/asm-generic/io-64-nonatomic-lo-hi.h
index ca546b1ff8b5..0efacff0a1ce 100644
--- a/include/asm-generic/io-64-nonatomic-lo-hi.h
+++ b/include/asm-generic/io-64-nonatomic-lo-hi.h
@@ -4,8 +4,7 @@
4#include <linux/io.h> 4#include <linux/io.h>
5#include <asm-generic/int-ll64.h> 5#include <asm-generic/int-ll64.h>
6 6
7#ifndef readq 7static inline __u64 lo_hi_readq(const volatile void __iomem *addr)
8static inline __u64 readq(const volatile void __iomem *addr)
9{ 8{
10 const volatile u32 __iomem *p = addr; 9 const volatile u32 __iomem *p = addr;
11 u32 low, high; 10 u32 low, high;
@@ -15,14 +14,19 @@ static inline __u64 readq(const volatile void __iomem *addr)
15 14
16 return low + ((u64)high << 32); 15 return low + ((u64)high << 32);
17} 16}
18#endif
19 17
20#ifndef writeq 18static inline void lo_hi_writeq(__u64 val, volatile void __iomem *addr)
21static inline void writeq(__u64 val, volatile void __iomem *addr)
22{ 19{
23 writel(val, addr); 20 writel(val, addr);
24 writel(val >> 32, addr + 4); 21 writel(val >> 32, addr + 4);
25} 22}
23
24#ifndef readq
25#define readq lo_hi_readq
26#endif
27
28#ifndef writeq
29#define writeq lo_hi_writeq
26#endif 30#endif
27 31
28#endif /* _ASM_IO_64_NONATOMIC_LO_HI_H_ */ 32#endif /* _ASM_IO_64_NONATOMIC_LO_HI_H_ */