aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Baron <jbaron@akamai.com>2014-07-04 07:48:32 -0400
committerBorislav Petkov <bp@suse.de>2014-07-04 08:00:26 -0400
commit7ee40b897d18ab03111eda9a6a0550e98166eada (patch)
tree989a4c6bd18781ac5ed611d2bf62a47d6d7d8d6c
parenta21e98ce1e0cafac30c1b11e41b9e690d8d93442 (diff)
ie31200_edac: Introduce the driver
Add a driver for the E3-1200 series of Intel DRAM controllers, based on the following E3-1200 specs: http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200v3-vol-2-datasheet.html I've tested this on bad memory hardware, and observed correlating bad reads and uncorrected memory errors as reported by the driver. Tested against: CPU E3-1270 v3 @ 3.50GHz : 8086:0c08 (haswell) CPU E3-1270 V2 @ 3.50GHz : 8086:0158 (ivy bridge) CPU E31270 @ 3.40GHz : 8086:0108 (sandy bridge) Signed-off-by: Jason Baron <jbaron@akamai.com> Link: http://lkml.kernel.org/r/95c83e80dd40b5377e8bb206285c5d95ac623872.1403818526.git.jbaron@akamai.com [ Boris: realign defines ] Signed-off-by: Borislav Petkov <bp@suse.de>
-rw-r--r--drivers/edac/Kconfig7
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/ie31200_edac.c541
3 files changed, 549 insertions, 0 deletions
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/ie31200_edac.c b/drivers/edac/ie31200_edac.c
new file mode 100644
index 000000000000..6d3d2c3cb6d6
--- /dev/null
+++ b/drivers/edac/ie31200_edac.c
@@ -0,0 +1,541 @@
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 rc;
332 int i, j;
333 struct mem_ctl_info *mci = NULL;
334 struct edac_mc_layer layers[2];
335 struct dimm_data dimm_info[IE31200_CHANNELS][IE31200_DIMMS_PER_CHANNEL];
336 void __iomem *window;
337 struct ie31200_priv *priv;
338 u32 addr_decode;
339
340 edac_dbg(0, "MC:\n");
341
342 if (!ecc_capable(pdev)) {
343 ie31200_printk(KERN_INFO, "No ECC support\n");
344 return -ENODEV;
345 }
346
347 window = ie31200_map_mchbar(pdev);
348 if (!window)
349 return -ENODEV;
350
351 /* populate DIMM info */
352 for (i = 0; i < IE31200_CHANNELS; i++) {
353 addr_decode = readl(window + IE31200_MAD_DIMM_0_OFFSET +
354 (i * 4));
355 edac_dbg(0, "addr_decode: 0x%x\n", addr_decode);
356 for (j = 0; j < IE31200_DIMMS_PER_CHANNEL; j++) {
357 dimm_info[i][j].size = (addr_decode >> (j * 8)) &
358 IE31200_MAD_DIMM_SIZE;
359 dimm_info[i][j].dual_rank = (addr_decode &
360 (IE31200_MAD_DIMM_A_RANK << j)) ? 1 : 0;
361 dimm_info[i][j].x16_width = (addr_decode &
362 (IE31200_MAD_DIMM_A_WIDTH << j)) ? 1 : 0;
363 edac_dbg(0, "size: 0x%x, rank: %d, width: %d\n",
364 dimm_info[i][j].size,
365 dimm_info[i][j].dual_rank,
366 dimm_info[i][j].x16_width);
367 }
368 }
369
370 nr_channels = how_many_channels(pdev);
371
372 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
373 layers[0].size = IE31200_DIMMS;
374 layers[0].is_virt_csrow = true;
375 layers[1].type = EDAC_MC_LAYER_CHANNEL;
376 layers[1].size = nr_channels;
377 layers[1].is_virt_csrow = false;
378 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
379 sizeof(struct ie31200_priv));
380
381 rc = -ENOMEM;
382 if (!mci)
383 goto fail_unmap;
384
385 edac_dbg(3, "MC: init mci\n");
386
387 mci->pdev = &pdev->dev;
388 mci->mtype_cap = MEM_FLAG_DDR3;
389
390 mci->edac_ctl_cap = EDAC_FLAG_SECDED;
391 mci->edac_cap = EDAC_FLAG_SECDED;
392
393 mci->mod_name = EDAC_MOD_STR;
394 mci->mod_ver = IE31200_REVISION;
395 mci->ctl_name = ie31200_devs[dev_idx].ctl_name;
396 mci->dev_name = pci_name(pdev);
397 mci->edac_check = ie31200_check;
398 mci->ctl_page_to_phys = NULL;
399 priv = mci->pvt_info;
400 priv->window = window;
401
402 /*
403 * The dram rank boundary (DRB) reg values are boundary addresses
404 * for each DRAM rank with a granularity of 64MB. DRB regs are
405 * cumulative; the last one will contain the total memory
406 * contained in all ranks.
407 */
408 for (i = 0; i < IE31200_DIMMS_PER_CHANNEL; i++) {
409 for (j = 0; j < IE31200_CHANNELS; j++) {
410 struct dimm_info *dimm;
411 unsigned long nr_pages;
412
413 nr_pages = IE31200_PAGES(dimm_info[j][i].size);
414 if (nr_pages == 0)
415 continue;
416
417 if (dimm_info[j][i].dual_rank) {
418 nr_pages = nr_pages / 2;
419 dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
420 mci->n_layers, (i * 2) + 1,
421 j, 0);
422 dimm->nr_pages = nr_pages;
423 edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
424 dimm->grain = 8; /* just a guess */
425 dimm->mtype = MEM_DDR3;
426 dimm->dtype = DEV_UNKNOWN;
427 dimm->edac_mode = EDAC_UNKNOWN;
428 }
429 dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
430 mci->n_layers, i * 2, j, 0);
431 dimm->nr_pages = nr_pages;
432 edac_dbg(0, "set nr pages: 0x%lx\n", nr_pages);
433 dimm->grain = 8; /* same guess */
434 dimm->mtype = MEM_DDR3;
435 dimm->dtype = DEV_UNKNOWN;
436 dimm->edac_mode = EDAC_UNKNOWN;
437 }
438 }
439
440 ie31200_clear_error_info(mci);
441
442 rc = -ENODEV;
443 if (edac_mc_add_mc(mci)) {
444 edac_dbg(3, "MC: failed edac_mc_add_mc()\n");
445 goto fail_free;
446 }
447
448 /* get this far and it's successful */
449 edac_dbg(3, "MC: success\n");
450 return 0;
451
452fail_free:
453 if (mci)
454 edac_mc_free(mci);
455fail_unmap:
456 iounmap(window);
457
458 return rc;
459}
460
461static int ie31200_init_one(struct pci_dev *pdev,
462 const struct pci_device_id *ent)
463{
464 edac_dbg(0, "MC:\n");
465
466 if (pci_enable_device(pdev) < 0)
467 return -EIO;
468
469 return ie31200_probe1(pdev, ent->driver_data);
470}
471
472static void ie31200_remove_one(struct pci_dev *pdev)
473{
474 struct mem_ctl_info *mci;
475 struct ie31200_priv *priv;
476
477 edac_dbg(0, "\n");
478 mci = edac_mc_del_mc(&pdev->dev);
479 if (!mci)
480 return;
481 priv = mci->pvt_info;
482 iounmap(priv->window);
483 edac_mc_free(mci);
484}
485
486static const struct pci_device_id ie31200_pci_tbl[] = {
487 {
488 PCI_VEND_DEV(INTEL, IE31200_HB_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
489 IE31200},
490 {
491 PCI_VEND_DEV(INTEL, IE31200_HB_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
492 IE31200},
493 {
494 PCI_VEND_DEV(INTEL, IE31200_HB_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
495 IE31200},
496 {
497 PCI_VEND_DEV(INTEL, IE31200_HB_4), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
498 IE31200},
499 {
500 PCI_VEND_DEV(INTEL, IE31200_HB_5), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
501 IE31200},
502 {
503 PCI_VEND_DEV(INTEL, IE31200_HB_6), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
504 IE31200},
505 {
506 PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
507 IE31200},
508 {
509 0,
510 } /* 0 terminated list. */
511};
512MODULE_DEVICE_TABLE(pci, ie31200_pci_tbl);
513
514static struct pci_driver ie31200_driver = {
515 .name = EDAC_MOD_STR,
516 .probe = ie31200_init_one,
517 .remove = ie31200_remove_one,
518 .id_table = ie31200_pci_tbl,
519};
520
521static int __init ie31200_init(void)
522{
523 edac_dbg(3, "MC:\n");
524 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
525 opstate_init();
526
527 return pci_register_driver(&ie31200_driver);
528}
529
530static void __exit ie31200_exit(void)
531{
532 edac_dbg(3, "MC:\n");
533 pci_unregister_driver(&ie31200_driver);
534}
535
536module_init(ie31200_init);
537module_exit(ie31200_exit);
538
539MODULE_LICENSE("GPL");
540MODULE_AUTHOR("Jason Baron <jbaron@akamai.com>");
541MODULE_DESCRIPTION("MC support for Intel Processor E31200 memory hub controllers");