i7core_edac: Properly fill struct csrow_info
[deliverable/linux.git] / drivers / edac / i7core_edac.c
CommitLineData
a0c36a1f
MCC
1/* Intel 7 core Memory Controller kernel module (Nehalem)
2 *
3 * This file may be distributed under the terms of the
4 * GNU General Public License version 2 only.
5 *
6 * Copyright (c) 2009 by:
7 * Mauro Carvalho Chehab <mchehab@redhat.com>
8 *
9 * Red Hat Inc. http://www.redhat.com
10 *
11 * Forked and adapted from the i5400_edac driver
12 *
13 * Based on the following public Intel datasheets:
14 * Intel Core i7 Processor Extreme Edition and Intel Core i7 Processor
15 * Datasheet, Volume 2:
16 * http://download.intel.com/design/processor/datashts/320835.pdf
17 * Intel Xeon Processor 5500 Series Datasheet Volume 2
18 * http://www.intel.com/Assets/PDF/datasheet/321322.pdf
19 * also available at:
20 * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
21 */
22
a0c36a1f
MCC
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/pci.h>
26#include <linux/pci_ids.h>
27#include <linux/slab.h>
28#include <linux/edac.h>
29#include <linux/mmzone.h>
30
31#include "edac_core.h"
32
7b029d03
MCC
33/* To use the new pci_[read/write]_config_qword instead of two dword */
34#define USE_QWORD 1
a0c36a1f
MCC
35
36/*
37 * Alter this version for the module when modifications are made
38 */
39#define I7CORE_REVISION " Ver: 1.0.0 " __DATE__
40#define EDAC_MOD_STR "i7core_edac"
41
42/* HACK: temporary, just to enable all logs, for now */
43#undef debugf0
44#define debugf0(fmt, arg...) edac_printk(KERN_INFO, "i7core", fmt, ##arg)
45
46/*
47 * Debug macros
48 */
49#define i7core_printk(level, fmt, arg...) \
50 edac_printk(level, "i7core", fmt, ##arg)
51
52#define i7core_mc_printk(mci, level, fmt, arg...) \
53 edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg)
54
55/*
56 * i7core Memory Controller Registers
57 */
58
59 /* OFFSETS for Device 3 Function 0 */
60
61#define MC_CONTROL 0x48
62#define MC_STATUS 0x4c
63#define MC_MAX_DOD 0x64
64
442305b1
MCC
65/*
66 * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet:
67 * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
68 */
69
70#define MC_TEST_ERR_RCV1 0x60
71 #define DIMM2_COR_ERR(r) ((r) & 0x7fff)
72
73#define MC_TEST_ERR_RCV0 0x64
74 #define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff)
75 #define DIMM0_COR_ERR(r) ((r) & 0x7fff)
76
a0c36a1f
MCC
77 /* OFFSETS for Devices 4,5 and 6 Function 0 */
78
0b2b7b7e
MCC
79#define MC_CHANNEL_DIMM_INIT_PARAMS 0x58
80 #define THREE_DIMMS_PRESENT (1 << 24)
81 #define SINGLE_QUAD_RANK_PRESENT (1 << 23)
82 #define QUAD_RANK_PRESENT (1 << 22)
83 #define REGISTERED_DIMM (1 << 15)
84
f122a892
MCC
85#define MC_CHANNEL_MAPPER 0x60
86 #define RDLCH(r, ch) ((((r) >> (3 + (ch * 6))) & 0x07) - 1)
87 #define WRLCH(r, ch) ((((r) >> (ch * 6)) & 0x07) - 1)
88
0b2b7b7e
MCC
89#define MC_CHANNEL_RANK_PRESENT 0x7c
90 #define RANK_PRESENT_MASK 0xffff
91
a0c36a1f 92#define MC_CHANNEL_ADDR_MATCH 0xf0
194a40fe
MCC
93#define MC_CHANNEL_ERROR_MASK 0xf8
94#define MC_CHANNEL_ERROR_INJECT 0xfc
95 #define INJECT_ADDR_PARITY 0x10
96 #define INJECT_ECC 0x08
97 #define MASK_CACHELINE 0x06
98 #define MASK_FULL_CACHELINE 0x06
99 #define MASK_MSB32_CACHELINE 0x04
100 #define MASK_LSB32_CACHELINE 0x02
101 #define NO_MASK_CACHELINE 0x00
102 #define REPEAT_EN 0x01
a0c36a1f 103
0b2b7b7e
MCC
104 /* OFFSETS for Devices 4,5 and 6 Function 1 */
105#define MC_DOD_CH_DIMM0 0x48
106#define MC_DOD_CH_DIMM1 0x4c
107#define MC_DOD_CH_DIMM2 0x50
108 #define RANKOFFSET_MASK ((1 << 12) | (1 << 11) | (1 << 10))
109 #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10)
110 #define DIMM_PRESENT_MASK (1 << 9)
111 #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9)
112 #define NUMBANK_MASK ((1 << 8) | (1 << 7))
113 #define NUMBANK(x) (((x) & NUMBANK_MASK) >> 7)
114 #define NUMRANK_MASK ((1 << 6) | (1 << 5))
115 #define NUMRANK(x) (((x) & NUMRANK_MASK) >> 5)
116 #define NUMROW_MASK ((1 << 4) | (1 << 3))
117 #define NUMROW(x) (((x) & NUMROW_MASK) >> 3)
118 #define NUMCOL_MASK 3
119 #define NUMCOL(x) ((x) & NUMCOL_MASK)
120
f122a892
MCC
121#define MC_RANK_PRESENT 0x7c
122
0b2b7b7e
MCC
123#define MC_SAG_CH_0 0x80
124#define MC_SAG_CH_1 0x84
125#define MC_SAG_CH_2 0x88
126#define MC_SAG_CH_3 0x8c
127#define MC_SAG_CH_4 0x90
128#define MC_SAG_CH_5 0x94
129#define MC_SAG_CH_6 0x98
130#define MC_SAG_CH_7 0x9c
131
132#define MC_RIR_LIMIT_CH_0 0x40
133#define MC_RIR_LIMIT_CH_1 0x44
134#define MC_RIR_LIMIT_CH_2 0x48
135#define MC_RIR_LIMIT_CH_3 0x4C
136#define MC_RIR_LIMIT_CH_4 0x50
137#define MC_RIR_LIMIT_CH_5 0x54
138#define MC_RIR_LIMIT_CH_6 0x58
139#define MC_RIR_LIMIT_CH_7 0x5C
140#define MC_RIR_LIMIT_MASK ((1 << 10) - 1)
141
142#define MC_RIR_WAY_CH 0x80
143 #define MC_RIR_WAY_OFFSET_MASK (((1 << 14) - 1) & ~0x7)
144 #define MC_RIR_WAY_RANK_MASK 0x7
145
a0c36a1f
MCC
146/*
147 * i7core structs
148 */
149
150#define NUM_CHANS 3
442305b1
MCC
151#define MAX_DIMMS 3 /* Max DIMMS per channel */
152#define MAX_MCR_FUNC 4
153#define MAX_CHAN_FUNC 3
a0c36a1f
MCC
154
155struct i7core_info {
156 u32 mc_control;
157 u32 mc_status;
158 u32 max_dod;
f122a892 159 u32 ch_map;
a0c36a1f
MCC
160};
161
194a40fe
MCC
162
163struct i7core_inject {
164 int enable;
165
166 u32 section;
167 u32 type;
168 u32 eccmask;
169
170 /* Error address mask */
171 int channel, dimm, rank, bank, page, col;
172};
173
0b2b7b7e 174struct i7core_channel {
442305b1
MCC
175 u32 ranks;
176 u32 dimms;
0b2b7b7e
MCC
177};
178
8f331907
MCC
179struct pci_id_descr {
180 int dev;
181 int func;
182 int dev_id;
183 struct pci_dev *pdev;
184};
185
a0c36a1f 186struct i7core_pvt {
442305b1
MCC
187 struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1];
188 struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
a0c36a1f 189 struct i7core_info info;
194a40fe 190 struct i7core_inject inject;
0b2b7b7e 191 struct i7core_channel channel[NUM_CHANS];
ef708b53 192 int channels; /* Number of active channels */
442305b1
MCC
193
194 int ce_count_available;
195 unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */
196 int last_ce_count[MAX_DIMMS];
197
a0c36a1f
MCC
198};
199
200/* Device name and register DID (Device ID) */
201struct i7core_dev_info {
202 const char *ctl_name; /* name for this device */
203 u16 fsb_mapping_errors; /* DID for the branchmap,control */
204};
205
8f331907
MCC
206#define PCI_DESCR(device, function, device_id) \
207 .dev = (device), \
208 .func = (function), \
209 .dev_id = (device_id)
210
211struct pci_id_descr pci_devs[] = {
212 /* Memory controller */
213 { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) },
214 { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) },
215 { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */
216 { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
217
218 /* Channel 0 */
219 { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) },
220 { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) },
221 { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK) },
222 { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC) },
223
224 /* Channel 1 */
225 { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL) },
226 { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR) },
227 { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK) },
228 { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC) },
229
230 /* Channel 2 */
231 { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL) },
232 { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) },
233 { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) },
234 { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) },
a0c36a1f 235};
8f331907
MCC
236#define N_DEVS ARRAY_SIZE(pci_devs)
237
238/*
239 * pci_device_id table for which devices we are looking for
240 * This should match the first device at pci_devs table
241 */
242static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
243 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)},
244 {0,} /* 0 terminated list. */
245};
246
a0c36a1f
MCC
247
248/* Table of devices attributes supported by this driver */
249static const struct i7core_dev_info i7core_devs[] = {
250 {
251 .ctl_name = "i7 Core",
252 .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR,
253 },
254};
255
256static struct edac_pci_ctl_info *i7core_pci;
257
258/****************************************************************************
259 Anciliary status routines
260 ****************************************************************************/
261
262 /* MC_CONTROL bits */
ef708b53
MCC
263#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & (1 << (8 + ch)))
264#define ECCx8(pvt) ((pvt)->info.mc_control & (1 << 1))
a0c36a1f
MCC
265
266 /* MC_STATUS bits */
ef708b53
MCC
267#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 3))
268#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch))
a0c36a1f
MCC
269
270 /* MC_MAX_DOD read functions */
271static inline int maxnumdimms(struct i7core_pvt *pvt)
272{
273 return (pvt->info.max_dod & 0x3) + 1;
274}
275
276static inline int maxnumrank(struct i7core_pvt *pvt)
277{
278 static int ranks[4] = { 1, 2, 4, -EINVAL };
279
280 return ranks[(pvt->info.max_dod >> 2) & 0x3];
281}
282
283static inline int maxnumbank(struct i7core_pvt *pvt)
284{
285 static int banks[4] = { 4, 8, 16, -EINVAL };
286
287 return banks[(pvt->info.max_dod >> 4) & 0x3];
288}
289
290static inline int maxnumrow(struct i7core_pvt *pvt)
291{
292 static int rows[8] = {
293 1 << 12, 1 << 13, 1 << 14, 1 << 15,
294 1 << 16, -EINVAL, -EINVAL, -EINVAL,
295 };
296
297 return rows[((pvt->info.max_dod >> 6) & 0x7)];
298}
299
300static inline int maxnumcol(struct i7core_pvt *pvt)
301{
302 static int cols[8] = {
303 1 << 10, 1 << 11, 1 << 12, -EINVAL,
304 };
305 return cols[((pvt->info.max_dod >> 9) & 0x3) << 12];
306}
307
194a40fe 308
a0c36a1f
MCC
309/****************************************************************************
310 Memory check routines
311 ****************************************************************************/
ef708b53
MCC
312static int i7core_get_active_channels(int *channels)
313{
314 struct pci_dev *pdev = NULL;
315 int i;
316 u32 status, control;
317
318 *channels = 0;
319
320 for (i = 0; i < N_DEVS; i++) {
321 if (!pci_devs[i].pdev)
322 continue;
323
324 if (PCI_SLOT(pci_devs[i].pdev->devfn) == 3 &&
325 PCI_FUNC(pci_devs[i].pdev->devfn) == 0) {
326 pdev = pci_devs[i].pdev;
327 break;
328 }
329 }
330
331 if (!pdev)
332 return -ENODEV;
333
334 /* Device 3 function 0 reads */
335 pci_read_config_dword(pdev, MC_STATUS, &status);
336 pci_read_config_dword(pdev, MC_CONTROL, &control);
337
338 for (i = 0; i < NUM_CHANS; i++) {
339 /* Check if the channel is active */
340 if (!(control & (1 << (8 + i))))
341 continue;
342
343 /* Check if the channel is disabled */
344 if (status & (1 << i)) {
345 continue;
346 }
347
348 (*channels)++;
349 }
350
1c6fed80
MCC
351 debugf0("Number of active channels: %d\n", *channels);
352
ef708b53
MCC
353 return 0;
354}
355
a0c36a1f
MCC
356static int get_dimm_config(struct mem_ctl_info *mci)
357{
358 struct i7core_pvt *pvt = mci->pvt_info;
1c6fed80
MCC
359 struct csrow_info *csr;
360 int i, csrow = 0;
361 enum edac_type mode;
a0c36a1f 362
8f331907
MCC
363 if (!pvt->pci_mcr[0])
364 return -ENODEV;
365
f122a892
MCC
366 /* Device 3 function 0 reads */
367 pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL,
368 &pvt->info.mc_control);
369 pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS,
370 &pvt->info.mc_status);
371 pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD,
1c6fed80 372 &pvt->info.max_dod);
f122a892
MCC
373 pci_read_config_dword(pvt->pci_mcr[0], MC_CHANNEL_MAPPER,
374 &pvt->info.ch_map);
375
376 debugf0("MC control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
377 pvt->info.mc_control, pvt->info.mc_status,
378 pvt->info.max_dod, pvt->info.ch_map);
a0c36a1f 379
1c6fed80 380 if (ECC_ENABLED(pvt)) {
a0c36a1f 381 debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4);
1c6fed80
MCC
382 if (ECCx8(pvt))
383 mode = EDAC_S8ECD8ED;
384 else
385 mode = EDAC_S4ECD4ED;
386 } else {
a0c36a1f 387 debugf0("ECC disabled\n");
1c6fed80
MCC
388 mode = EDAC_NONE;
389 }
a0c36a1f
MCC
390
391 /* FIXME: need to handle the error codes */
392 debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n",
393 maxnumdimms(pvt), maxnumrank(pvt), maxnumbank(pvt));
394 debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n",
395 maxnumrow(pvt), maxnumcol(pvt));
396
0b2b7b7e
MCC
397 debugf0("Memory channel configuration:\n");
398
399 for (i = 0; i < NUM_CHANS; i++) {
400 u32 data;
401
402 if (!CH_ACTIVE(pvt, i)) {
403 debugf0("Channel %i is not active\n", i);
404 continue;
405 }
406 if (CH_DISABLED(pvt, i)) {
407 debugf0("Channel %i is disabled\n", i);
408 continue;
409 }
410
f122a892 411 /* Devices 4-6 function 0 */
0b2b7b7e
MCC
412 pci_read_config_dword(pvt->pci_ch[i][0],
413 MC_CHANNEL_DIMM_INIT_PARAMS, &data);
414
415 pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2;
416
417 if (data & THREE_DIMMS_PRESENT)
418 pvt->channel[i].dimms = 3;
419 else if (data & SINGLE_QUAD_RANK_PRESENT)
420 pvt->channel[i].dimms = 1;
421 else
422 pvt->channel[i].dimms = 2;
423
1c6fed80
MCC
424 debugf0("Ch%d phy rd%d, wr%d (0x%08x): "
425 "%d ranks, %d %cDIMMs, offset = %d\n",
426 i,
427 RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
428 data,
0b2b7b7e 429 pvt->channel[i].ranks, pvt->channel[i].dimms,
1c6fed80
MCC
430 (data & REGISTERED_DIMM)? 'R' : 'U',
431 RANKOFFSET(data));
432
433 csr = &mci->csrows[csrow];
434 csr->first_page = 0;
435 csr->last_page = 0;
436 csr->page_mask = 0;
437 csr->nr_pages = 0;
438 csr->grain = 0;
439 csr->csrow_idx = csrow;
440 csr->dtype = DEV_X8; /* FIXME: check this */
441
442 if (data & REGISTERED_DIMM)
443 csr->mtype = MEM_RDDR3;
444 else
445 csr->mtype = MEM_DDR3;
446 csr->edac_mode = mode;
447
448 csrow++;
0b2b7b7e
MCC
449 }
450
a0c36a1f
MCC
451 return 0;
452}
453
194a40fe
MCC
454/****************************************************************************
455 Error insertion routines
456 ****************************************************************************/
457
458/* The i7core has independent error injection features per channel.
459 However, to have a simpler code, we don't allow enabling error injection
460 on more than one channel.
461 Also, since a change at an inject parameter will be applied only at enable,
462 we're disabling error injection on all write calls to the sysfs nodes that
463 controls the error code injection.
464 */
8f331907 465static int disable_inject(struct mem_ctl_info *mci)
194a40fe
MCC
466{
467 struct i7core_pvt *pvt = mci->pvt_info;
468
469 pvt->inject.enable = 0;
470
8f331907
MCC
471 if (!pvt->pci_ch[pvt->inject.channel][0])
472 return -ENODEV;
473
194a40fe
MCC
474 pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
475 MC_CHANNEL_ERROR_MASK, 0);
8f331907
MCC
476
477 return 0;
194a40fe
MCC
478}
479
480/*
481 * i7core inject inject.section
482 *
483 * accept and store error injection inject.section value
484 * bit 0 - refers to the lower 32-byte half cacheline
485 * bit 1 - refers to the upper 32-byte half cacheline
486 */
487static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
488 const char *data, size_t count)
489{
490 struct i7core_pvt *pvt = mci->pvt_info;
491 unsigned long value;
492 int rc;
493
494 if (pvt->inject.enable)
495 disable_inject(mci);
496
497 rc = strict_strtoul(data, 10, &value);
498 if ((rc < 0) || (value > 3))
499 return 0;
500
501 pvt->inject.section = (u32) value;
502 return count;
503}
504
505static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
506 char *data)
507{
508 struct i7core_pvt *pvt = mci->pvt_info;
509 return sprintf(data, "0x%08x\n", pvt->inject.section);
510}
511
512/*
513 * i7core inject.type
514 *
515 * accept and store error injection inject.section value
516 * bit 0 - repeat enable - Enable error repetition
517 * bit 1 - inject ECC error
518 * bit 2 - inject parity error
519 */
520static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
521 const char *data, size_t count)
522{
523 struct i7core_pvt *pvt = mci->pvt_info;
524 unsigned long value;
525 int rc;
526
527 if (pvt->inject.enable)
528 disable_inject(mci);
529
530 rc = strict_strtoul(data, 10, &value);
531 if ((rc < 0) || (value > 7))
532 return 0;
533
534 pvt->inject.type = (u32) value;
535 return count;
536}
537
538static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
539 char *data)
540{
541 struct i7core_pvt *pvt = mci->pvt_info;
542 return sprintf(data, "0x%08x\n", pvt->inject.type);
543}
544
545/*
546 * i7core_inject_inject.eccmask_store
547 *
548 * The type of error (UE/CE) will depend on the inject.eccmask value:
549 * Any bits set to a 1 will flip the corresponding ECC bit
550 * Correctable errors can be injected by flipping 1 bit or the bits within
551 * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
552 * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
553 * uncorrectable error to be injected.
554 */
555static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
556 const char *data, size_t count)
557{
558 struct i7core_pvt *pvt = mci->pvt_info;
559 unsigned long value;
560 int rc;
561
562 if (pvt->inject.enable)
563 disable_inject(mci);
564
565 rc = strict_strtoul(data, 10, &value);
566 if (rc < 0)
567 return 0;
568
569 pvt->inject.eccmask = (u32) value;
570 return count;
571}
572
573static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
574 char *data)
575{
576 struct i7core_pvt *pvt = mci->pvt_info;
577 return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
578}
579
580/*
581 * i7core_addrmatch
582 *
583 * The type of error (UE/CE) will depend on the inject.eccmask value:
584 * Any bits set to a 1 will flip the corresponding ECC bit
585 * Correctable errors can be injected by flipping 1 bit or the bits within
586 * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
587 * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
588 * uncorrectable error to be injected.
589 */
590static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci,
591 const char *data, size_t count)
592{
593 struct i7core_pvt *pvt = mci->pvt_info;
594 char *cmd, *val;
595 long value;
596 int rc;
597
598 if (pvt->inject.enable)
599 disable_inject(mci);
600
601 do {
602 cmd = strsep((char **) &data, ":");
603 if (!cmd)
604 break;
605 val = strsep((char **) &data, " \n\t");
606 if (!val)
607 return cmd - data;
608
609 if (!strcasecmp(val,"any"))
610 value = -1;
611 else {
612 rc = strict_strtol(val, 10, &value);
613 if ((rc < 0) || (value < 0))
614 return cmd - data;
615 }
616
617 if (!strcasecmp(cmd,"channel")) {
618 if (value < 3)
619 pvt->inject.channel = value;
620 else
621 return cmd - data;
622 } else if (!strcasecmp(cmd,"dimm")) {
623 if (value < 4)
624 pvt->inject.dimm = value;
625 else
626 return cmd - data;
627 } else if (!strcasecmp(cmd,"rank")) {
628 if (value < 4)
629 pvt->inject.rank = value;
630 else
631 return cmd - data;
632 } else if (!strcasecmp(cmd,"bank")) {
633 if (value < 4)
634 pvt->inject.bank = value;
635 else
636 return cmd - data;
637 } else if (!strcasecmp(cmd,"page")) {
638 if (value <= 0xffff)
639 pvt->inject.page = value;
640 else
641 return cmd - data;
642 } else if (!strcasecmp(cmd,"col") ||
643 !strcasecmp(cmd,"column")) {
644 if (value <= 0x3fff)
645 pvt->inject.col = value;
646 else
647 return cmd - data;
648 }
649 } while (1);
650
651 return count;
652}
653
654static ssize_t i7core_inject_addrmatch_show(struct mem_ctl_info *mci,
655 char *data)
656{
657 struct i7core_pvt *pvt = mci->pvt_info;
658 char channel[4], dimm[4], bank[4], rank[4], page[7], col[7];
659
660 if (pvt->inject.channel < 0)
661 sprintf(channel, "any");
662 else
663 sprintf(channel, "%d", pvt->inject.channel);
664 if (pvt->inject.dimm < 0)
665 sprintf(dimm, "any");
666 else
667 sprintf(dimm, "%d", pvt->inject.dimm);
668 if (pvt->inject.bank < 0)
669 sprintf(bank, "any");
670 else
671 sprintf(bank, "%d", pvt->inject.bank);
672 if (pvt->inject.rank < 0)
673 sprintf(rank, "any");
674 else
675 sprintf(rank, "%d", pvt->inject.rank);
676 if (pvt->inject.page < 0)
677 sprintf(page, "any");
678 else
679 sprintf(page, "0x%04x", pvt->inject.page);
680 if (pvt->inject.col < 0)
681 sprintf(col, "any");
682 else
683 sprintf(col, "0x%04x", pvt->inject.col);
684
685 return sprintf(data, "channel: %s\ndimm: %s\nbank: %s\n"
686 "rank: %s\npage: %s\ncolumn: %s\n",
687 channel, dimm, bank, rank, page, col);
688}
689
690/*
691 * This routine prepares the Memory Controller for error injection.
692 * The error will be injected when some process tries to write to the
693 * memory that matches the given criteria.
694 * The criteria can be set in terms of a mask where dimm, rank, bank, page
695 * and col can be specified.
696 * A -1 value for any of the mask items will make the MCU to ignore
697 * that matching criteria for error injection.
698 *
699 * It should be noticed that the error will only happen after a write operation
700 * on a memory that matches the condition. if REPEAT_EN is not enabled at
701 * inject mask, then it will produce just one error. Otherwise, it will repeat
702 * until the injectmask would be cleaned.
703 *
704 * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD
705 * is reliable enough to check if the MC is using the
706 * three channels. However, this is not clear at the datasheet.
707 */
708static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
709 const char *data, size_t count)
710{
711 struct i7core_pvt *pvt = mci->pvt_info;
712 u32 injectmask;
713 u64 mask = 0;
714 int rc;
715 long enable;
716
8f331907
MCC
717 if (!pvt->pci_ch[pvt->inject.channel][0])
718 return 0;
719
194a40fe
MCC
720 rc = strict_strtoul(data, 10, &enable);
721 if ((rc < 0))
722 return 0;
723
724 if (enable) {
725 pvt->inject.enable = 1;
726 } else {
727 disable_inject(mci);
728 return count;
729 }
730
731 /* Sets pvt->inject.dimm mask */
732 if (pvt->inject.dimm < 0)
7b029d03 733 mask |= 1L << 41;
194a40fe 734 else {
0b2b7b7e 735 if (pvt->channel[pvt->inject.channel].dimms > 2)
7b029d03 736 mask |= (pvt->inject.dimm & 0x3L) << 35;
194a40fe 737 else
7b029d03 738 mask |= (pvt->inject.dimm & 0x1L) << 36;
194a40fe
MCC
739 }
740
741 /* Sets pvt->inject.rank mask */
742 if (pvt->inject.rank < 0)
7b029d03 743 mask |= 1L << 40;
194a40fe 744 else {
0b2b7b7e 745 if (pvt->channel[pvt->inject.channel].dimms > 2)
7b029d03 746 mask |= (pvt->inject.rank & 0x1L) << 34;
194a40fe 747 else
7b029d03 748 mask |= (pvt->inject.rank & 0x3L) << 34;
194a40fe
MCC
749 }
750
751 /* Sets pvt->inject.bank mask */
752 if (pvt->inject.bank < 0)
7b029d03 753 mask |= 1L << 39;
194a40fe 754 else
7b029d03 755 mask |= (pvt->inject.bank & 0x15L) << 30;
194a40fe
MCC
756
757 /* Sets pvt->inject.page mask */
758 if (pvt->inject.page < 0)
7b029d03 759 mask |= 1L << 38;
194a40fe 760 else
7b029d03 761 mask |= (pvt->inject.page & 0xffffL) << 14;
194a40fe
MCC
762
763 /* Sets pvt->inject.column mask */
764 if (pvt->inject.col < 0)
7b029d03 765 mask |= 1L << 37;
194a40fe 766 else
7b029d03 767 mask |= (pvt->inject.col & 0x3fffL);
194a40fe 768
7b029d03 769#if USE_QWORD
194a40fe
MCC
770 pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0],
771 MC_CHANNEL_ADDR_MATCH, mask);
7b029d03
MCC
772#else
773 pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
774 MC_CHANNEL_ADDR_MATCH, mask);
775 pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
776 MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L);
777#endif
778
779#if 1
780#if USE_QWORD
781 u64 rdmask;
782 pci_read_config_qword(pvt->pci_ch[pvt->inject.channel][0],
783 MC_CHANNEL_ADDR_MATCH, &rdmask);
784 debugf0("Inject addr match write 0x%016llx, read: 0x%016llx\n",
785 mask, rdmask);
786#else
787 u32 rdmask1, rdmask2;
788
789 pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
790 MC_CHANNEL_ADDR_MATCH, &rdmask1);
791 pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
792 MC_CHANNEL_ADDR_MATCH + 4, &rdmask2);
793
794 debugf0("Inject addr match write 0x%016llx, read: 0x%08x%08x\n",
795 mask, rdmask1, rdmask2);
796#endif
797#endif
194a40fe
MCC
798
799 pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
800 MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask);
801
802 /*
803 * bit 0: REPEAT_EN
804 * bits 1-2: MASK_HALF_CACHELINE
805 * bit 3: INJECT_ECC
806 * bit 4: INJECT_ADDR_PARITY
807 */
808
7b029d03
MCC
809 injectmask = (pvt->inject.type & 1) |
810 (pvt->inject.section & 0x3) << 1 |
194a40fe
MCC
811 (pvt->inject.type & 0x6) << (3 - 1);
812
813 pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
814 MC_CHANNEL_ERROR_MASK, injectmask);
815
194a40fe
MCC
816 debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n",
817 mask, pvt->inject.eccmask, injectmask);
818
7b029d03
MCC
819
820
194a40fe
MCC
821 return count;
822}
823
824static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
825 char *data)
826{
827 struct i7core_pvt *pvt = mci->pvt_info;
7b029d03
MCC
828 u32 injectmask;
829
830 pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
831 MC_CHANNEL_ERROR_MASK, &injectmask);
832
833 debugf0("Inject error read: 0x%018x\n", injectmask);
834
835 if (injectmask & 0x0c)
836 pvt->inject.enable = 1;
837
194a40fe
MCC
838 return sprintf(data, "%d\n", pvt->inject.enable);
839}
840
442305b1
MCC
841static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data)
842{
843 struct i7core_pvt *pvt = mci->pvt_info;
844
845 if (!pvt->ce_count_available)
846 return sprintf(data, "unavailable\n");
847
848 return sprintf(data, "dimm0: %lu\ndimm1: %lu\ndimm2: %lu\n",
849 pvt->ce_count[0],
850 pvt->ce_count[1],
851 pvt->ce_count[2]);
852}
853
194a40fe
MCC
854/*
855 * Sysfs struct
856 */
857static struct mcidev_sysfs_attribute i7core_inj_attrs[] = {
858
859 {
860 .attr = {
861 .name = "inject_section",
862 .mode = (S_IRUGO | S_IWUSR)
863 },
864 .show = i7core_inject_section_show,
865 .store = i7core_inject_section_store,
866 }, {
867 .attr = {
868 .name = "inject_type",
869 .mode = (S_IRUGO | S_IWUSR)
870 },
871 .show = i7core_inject_type_show,
872 .store = i7core_inject_type_store,
873 }, {
874 .attr = {
875 .name = "inject_eccmask",
876 .mode = (S_IRUGO | S_IWUSR)
877 },
878 .show = i7core_inject_eccmask_show,
879 .store = i7core_inject_eccmask_store,
880 }, {
881 .attr = {
882 .name = "inject_addrmatch",
883 .mode = (S_IRUGO | S_IWUSR)
884 },
885 .show = i7core_inject_addrmatch_show,
886 .store = i7core_inject_addrmatch_store,
887 }, {
888 .attr = {
889 .name = "inject_enable",
890 .mode = (S_IRUGO | S_IWUSR)
891 },
892 .show = i7core_inject_enable_show,
893 .store = i7core_inject_enable_store,
442305b1
MCC
894 }, {
895 .attr = {
896 .name = "corrected_error_counts",
897 .mode = (S_IRUGO | S_IWUSR)
898 },
899 .show = i7core_ce_regs_show,
900 .store = NULL,
194a40fe
MCC
901 },
902};
903
a0c36a1f
MCC
904/****************************************************************************
905 Device initialization routines: put/get, init/exit
906 ****************************************************************************/
907
908/*
909 * i7core_put_devices 'put' all the devices that we have
910 * reserved via 'get'
911 */
8f331907 912static void i7core_put_devices(void)
a0c36a1f 913{
8f331907 914 int i;
a0c36a1f 915
8f331907
MCC
916 for (i = 0; i < N_DEVS; i++)
917 pci_dev_put(pci_devs[i].pdev);
a0c36a1f
MCC
918}
919
920/*
921 * i7core_get_devices Find and perform 'get' operation on the MCH's
922 * device/functions we want to reference for this driver
923 *
924 * Need to 'get' device 16 func 1 and func 2
925 */
ef708b53 926static int i7core_get_devices(void)
a0c36a1f 927{
ef708b53 928 int rc, i;
8f331907 929 struct pci_dev *pdev = NULL;
a0c36a1f 930
8f331907
MCC
931 for (i = 0; i < N_DEVS; i++) {
932 pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
933 pci_devs[i].dev_id, NULL);
ef708b53
MCC
934 if (likely(pdev))
935 pci_devs[i].pdev = pdev;
936 else {
8f331907
MCC
937 i7core_printk(KERN_ERR,
938 "Device not found: PCI ID %04x:%04x "
939 "(dev %d, func %d)\n",
940 PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id,
941 pci_devs[i].dev,pci_devs[i].func);
ef708b53
MCC
942
943 /* Dev 3 function 2 only exists on chips with RDIMMs */
8f331907 944 if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2))
ef708b53
MCC
945 continue;
946
947 /* End of list, leave */
948 rc = -ENODEV;
949 goto error;
8f331907 950 }
8f331907 951
ef708b53
MCC
952 /* Sanity check */
953 if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[i].dev ||
954 PCI_FUNC(pdev->devfn) != pci_devs[i].func)) {
8f331907 955 i7core_printk(KERN_ERR,
ef708b53
MCC
956 "Device PCI ID %04x:%04x "
957 "has fn %d.%d instead of fn %d.%d\n",
8f331907 958 PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id,
ef708b53 959 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
8f331907 960 pci_devs[i].dev, pci_devs[i].func);
ef708b53
MCC
961 rc = -EINVAL;
962 goto error;
8f331907 963 }
ef708b53
MCC
964
965 /* Be sure that the device is enabled */
966 rc = pci_enable_device(pdev);
967 if (unlikely(rc < 0)) {
8f331907 968 i7core_printk(KERN_ERR,
ef708b53
MCC
969 "Couldn't enable PCI ID %04x:%04x "
970 "fn %d.%d\n",
8f331907 971 PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id,
ef708b53
MCC
972 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
973 goto error;
8f331907 974 }
a0c36a1f 975
8f331907 976 i7core_printk(KERN_INFO,
ef708b53 977 "Registered device %0x:%0x fn %d.%d\n",
8f331907
MCC
978 PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id,
979 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
ef708b53
MCC
980 }
981
982 return 0;
983
984error:
985 i7core_put_devices();
986 return -EINVAL;
987}
988
989static int mci_bind_devs(struct mem_ctl_info *mci)
990{
991 struct i7core_pvt *pvt = mci->pvt_info;
992 struct pci_dev *pdev;
993 int i, func, slot;
994
995 for (i = 0; i < N_DEVS; i++) {
996 pdev = pci_devs[i].pdev;
997 if (!pdev)
998 continue;
8f331907
MCC
999
1000 func = PCI_FUNC(pdev->devfn);
ef708b53
MCC
1001 slot = PCI_SLOT(pdev->devfn);
1002 if (slot == 3) {
1003 if (unlikely(func > MAX_MCR_FUNC))
1004 goto error;
8f331907 1005 pvt->pci_mcr[func] = pdev;
ef708b53
MCC
1006 } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) {
1007 if (unlikely(func > MAX_CHAN_FUNC))
1008 goto error;
1009 pvt->pci_ch[slot - 4][func] = pdev;
1010 } else
1011 goto error;
1012
1013 debugf0("Associated fn %d.%d, dev = %p\n",
1014 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev);
a0c36a1f 1015 }
a0c36a1f 1016 return 0;
ef708b53
MCC
1017
1018error:
1019 i7core_printk(KERN_ERR, "Device %d, function %d "
1020 "is out of the expected range\n",
1021 slot, func);
1022 return -EINVAL;
a0c36a1f
MCC
1023}
1024
442305b1
MCC
1025/****************************************************************************
1026 Error check routines
1027 ****************************************************************************/
1028
1029/* This function is based on the device 3 function 4 registers as described on:
1030 * Intel Xeon Processor 5500 Series Datasheet Volume 2
1031 * http://www.intel.com/Assets/PDF/datasheet/321322.pdf
1032 * also available at:
1033 * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
1034 */
1035static void check_mc_test_err(struct mem_ctl_info *mci)
1036{
1037 struct i7core_pvt *pvt = mci->pvt_info;
1038 u32 rcv1, rcv0;
1039 int new0, new1, new2;
1040
1041 if (!pvt->pci_mcr[4]) {
1042 debugf0("%s MCR registers not found\n",__func__);
1043 return;
1044 }
1045
1046 /* Corrected error reads */
1047 pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1);
1048 pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0);
1049
1050 /* Store the new values */
1051 new2 = DIMM2_COR_ERR(rcv1);
1052 new1 = DIMM1_COR_ERR(rcv0);
1053 new0 = DIMM0_COR_ERR(rcv0);
1054
1055 debugf2("%s CE rcv1=0x%08x rcv0=0x%08x, %d %d %d\n",
1056 (pvt->ce_count_available ? "UPDATE" : "READ"),
1057 rcv1, rcv0, new0, new1, new2);
1058
1059 /* Updates CE counters if it is not the first time here */
1060 if (pvt->ce_count_available) {
1061 /* Updates CE counters */
1062 int add0, add1, add2;
1063
1064 add2 = new2 - pvt->last_ce_count[2];
1065 add1 = new1 - pvt->last_ce_count[1];
1066 add0 = new0 - pvt->last_ce_count[0];
1067
1068 if (add2 < 0)
1069 add2 += 0x7fff;
1070 pvt->ce_count[2] += add2;
1071
1072 if (add1 < 0)
1073 add1 += 0x7fff;
1074 pvt->ce_count[1] += add1;
1075
1076 if (add0 < 0)
1077 add0 += 0x7fff;
1078 pvt->ce_count[0] += add0;
1079 } else
1080 pvt->ce_count_available = 1;
1081
1082 /* Store the new values */
1083 pvt->last_ce_count[2] = new2;
1084 pvt->last_ce_count[1] = new1;
1085 pvt->last_ce_count[0] = new0;
1086}
1087
87d1d272
MCC
1088/*
1089 * i7core_check_error Retrieve and process errors reported by the
1090 * hardware. Called by the Core module.
1091 */
1092static void i7core_check_error(struct mem_ctl_info *mci)
1093{
442305b1 1094 check_mc_test_err(mci);
87d1d272
MCC
1095}
1096
a0c36a1f
MCC
1097/*
1098 * i7core_probe Probe for ONE instance of device to see if it is
1099 * present.
1100 * return:
1101 * 0 for FOUND a device
1102 * < 0 for error code
1103 */
1104static int __devinit i7core_probe(struct pci_dev *pdev,
1105 const struct pci_device_id *id)
1106{
1107 struct mem_ctl_info *mci;
1108 struct i7core_pvt *pvt;
ef708b53 1109 int num_channels = 0;
a0c36a1f 1110 int num_csrows;
a0c36a1f
MCC
1111 int dev_idx = id->driver_data;
1112
ef708b53 1113 if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs)))
a0c36a1f
MCC
1114 return -EINVAL;
1115
ef708b53
MCC
1116 /* get the pci devices we want to reserve for our use */
1117 if (unlikely(i7core_get_devices() < 0))
1118 return -ENODEV;
1119
1120 /* Check the number of active and not disabled channels */
1121 if (unlikely (i7core_get_active_channels(&num_channels)) < 0)
1122 goto fail0;
a0c36a1f 1123
ef708b53
MCC
1124 /* FIXME: we currently don't know the number of csrows */
1125 num_csrows = num_channels;
a0c36a1f
MCC
1126
1127 /* allocate a new MC control structure */
1128 mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
ef708b53 1129 if (unlikely (!mci))
a0c36a1f
MCC
1130 return -ENOMEM;
1131
1132 debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
1133
194a40fe 1134 mci->dev = &pdev->dev; /* record ptr to the generic device */
a0c36a1f
MCC
1135
1136 pvt = mci->pvt_info;
ef708b53 1137 memset(pvt, 0, sizeof(*pvt));
a0c36a1f 1138
a0c36a1f 1139 mci->mc_idx = 0;
ef708b53 1140 mci->mtype_cap = MEM_FLAG_DDR3; /* FIXME: how to handle RDDR3? */
a0c36a1f
MCC
1141 mci->edac_ctl_cap = EDAC_FLAG_NONE;
1142 mci->edac_cap = EDAC_FLAG_NONE;
1143 mci->mod_name = "i7core_edac.c";
1144 mci->mod_ver = I7CORE_REVISION;
1145 mci->ctl_name = i7core_devs[dev_idx].ctl_name;
1146 mci->dev_name = pci_name(pdev);
1147 mci->ctl_page_to_phys = NULL;
194a40fe 1148 mci->mc_driver_sysfs_attributes = i7core_inj_attrs;
87d1d272
MCC
1149 /* Set the function pointer to an actual operation function */
1150 mci->edac_check = i7core_check_error;
8f331907 1151
ef708b53
MCC
1152 /* Store pci devices at mci for faster access */
1153 if (unlikely (mci_bind_devs(mci)) < 0)
1154 goto fail1;
1155
1156 /* Get dimm basic config */
1157 get_dimm_config(mci);
1158
a0c36a1f 1159 /* add this new MC control structure to EDAC's list of MCs */
ef708b53 1160 if (unlikely(edac_mc_add_mc(mci)) < 0) {
a0c36a1f
MCC
1161 debugf0("MC: " __FILE__
1162 ": %s(): failed edac_mc_add_mc()\n", __func__);
1163 /* FIXME: perhaps some code should go here that disables error
1164 * reporting if we just enabled it
1165 */
1166 goto fail1;
1167 }
1168
1169 /* allocating generic PCI control info */
1170 i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
ef708b53 1171 if (unlikely (!i7core_pci)) {
a0c36a1f
MCC
1172 printk(KERN_WARNING
1173 "%s(): Unable to create PCI control\n",
1174 __func__);
1175 printk(KERN_WARNING
1176 "%s(): PCI error report via EDAC not setup\n",
1177 __func__);
1178 }
1179
194a40fe 1180 /* Default error mask is any memory */
ef708b53 1181 pvt->inject.channel = 0;
194a40fe
MCC
1182 pvt->inject.dimm = -1;
1183 pvt->inject.rank = -1;
1184 pvt->inject.bank = -1;
1185 pvt->inject.page = -1;
1186 pvt->inject.col = -1;
1187
ef708b53 1188 i7core_printk(KERN_INFO, "Driver loaded.\n");
8f331907 1189
a0c36a1f
MCC
1190 return 0;
1191
1192fail1:
8f331907 1193 i7core_put_devices();
a0c36a1f
MCC
1194
1195fail0:
1196 edac_mc_free(mci);
1197 return -ENODEV;
1198}
1199
1200/*
1201 * i7core_remove destructor for one instance of device
1202 *
1203 */
1204static void __devexit i7core_remove(struct pci_dev *pdev)
1205{
1206 struct mem_ctl_info *mci;
1207
1208 debugf0(__FILE__ ": %s()\n", __func__);
1209
1210 if (i7core_pci)
1211 edac_pci_release_generic_ctl(i7core_pci);
1212
1213 mci = edac_mc_del_mc(&pdev->dev);
87d1d272 1214
a0c36a1f
MCC
1215 if (!mci)
1216 return;
1217
1218 /* retrieve references to resources, and free those resources */
8f331907 1219 i7core_put_devices();
a0c36a1f
MCC
1220
1221 edac_mc_free(mci);
1222}
1223
a0c36a1f
MCC
1224MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);
1225
1226/*
1227 * i7core_driver pci_driver structure for this module
1228 *
1229 */
1230static struct pci_driver i7core_driver = {
1231 .name = "i7core_edac",
1232 .probe = i7core_probe,
1233 .remove = __devexit_p(i7core_remove),
1234 .id_table = i7core_pci_tbl,
1235};
1236
1237/*
1238 * i7core_init Module entry function
1239 * Try to initialize this module for its devices
1240 */
1241static int __init i7core_init(void)
1242{
1243 int pci_rc;
1244
1245 debugf2("MC: " __FILE__ ": %s()\n", __func__);
1246
1247 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
1248 opstate_init();
1249
1250 pci_rc = pci_register_driver(&i7core_driver);
1251
1252 return (pci_rc < 0) ? pci_rc : 0;
1253}
1254
1255/*
1256 * i7core_exit() Module exit function
1257 * Unregister the driver
1258 */
1259static void __exit i7core_exit(void)
1260{
1261 debugf2("MC: " __FILE__ ": %s()\n", __func__);
1262 pci_unregister_driver(&i7core_driver);
1263}
1264
1265module_init(i7core_init);
1266module_exit(i7core_exit);
1267
1268MODULE_LICENSE("GPL");
1269MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
1270MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
1271MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
1272 I7CORE_REVISION);
1273
1274module_param(edac_op_state, int, 0444);
1275MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
This page took 0.080291 seconds and 5 git commands to generate.