]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/edac/i7core_edac.c
i7core_edac: Add error insertion code for Nehalem
[mirror_ubuntu-jammy-kernel.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
33
34/*
35 * Alter this version for the module when modifications are made
36 */
37#define I7CORE_REVISION " Ver: 1.0.0 " __DATE__
38#define EDAC_MOD_STR "i7core_edac"
39
40/* HACK: temporary, just to enable all logs, for now */
41#undef debugf0
42#define debugf0(fmt, arg...) edac_printk(KERN_INFO, "i7core", fmt, ##arg)
43
44/*
45 * Debug macros
46 */
47#define i7core_printk(level, fmt, arg...) \
48 edac_printk(level, "i7core", fmt, ##arg)
49
50#define i7core_mc_printk(mci, level, fmt, arg...) \
51 edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg)
52
53/*
54 * i7core Memory Controller Registers
55 */
56
57 /* OFFSETS for Device 3 Function 0 */
58
59#define MC_CONTROL 0x48
60#define MC_STATUS 0x4c
61#define MC_MAX_DOD 0x64
62
63 /* OFFSETS for Devices 4,5 and 6 Function 0 */
64
65#define MC_CHANNEL_ADDR_MATCH 0xf0
194a40fe
MCC
66#define MC_CHANNEL_ERROR_MASK 0xf8
67#define MC_CHANNEL_ERROR_INJECT 0xfc
68 #define INJECT_ADDR_PARITY 0x10
69 #define INJECT_ECC 0x08
70 #define MASK_CACHELINE 0x06
71 #define MASK_FULL_CACHELINE 0x06
72 #define MASK_MSB32_CACHELINE 0x04
73 #define MASK_LSB32_CACHELINE 0x02
74 #define NO_MASK_CACHELINE 0x00
75 #define REPEAT_EN 0x01
a0c36a1f
MCC
76
77/*
78 * i7core structs
79 */
80
81#define NUM_CHANS 3
82#define NUM_FUNCS 1
83
84struct i7core_info {
85 u32 mc_control;
86 u32 mc_status;
87 u32 max_dod;
88};
89
194a40fe
MCC
90
91struct i7core_inject {
92 int enable;
93
94 u32 section;
95 u32 type;
96 u32 eccmask;
97
98 /* Error address mask */
99 int channel, dimm, rank, bank, page, col;
100};
101
a0c36a1f
MCC
102struct i7core_pvt {
103 struct pci_dev *pci_mcr; /* Dev 3:0 */
104 struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS];
105 struct i7core_info info;
194a40fe 106 struct i7core_inject inject;
a0c36a1f
MCC
107};
108
109/* Device name and register DID (Device ID) */
110struct i7core_dev_info {
111 const char *ctl_name; /* name for this device */
112 u16 fsb_mapping_errors; /* DID for the branchmap,control */
113};
114
115static int chan_pci_ids[NUM_CHANS] = {
116 PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL, /* Dev 4 */
117 PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL, /* Dev 5 */
118 PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL, /* Dev 6 */
119};
120
121/* Table of devices attributes supported by this driver */
122static const struct i7core_dev_info i7core_devs[] = {
123 {
124 .ctl_name = "i7 Core",
125 .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR,
126 },
127};
128
129static struct edac_pci_ctl_info *i7core_pci;
130
131/****************************************************************************
132 Anciliary status routines
133 ****************************************************************************/
134
135 /* MC_CONTROL bits */
136#define CH2_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 10)
137#define CH1_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 9)
138#define CH0_ACTIVE(pvt) ((pvt)->info.mc_control & 1 << 8)
139#define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1)
140
141 /* MC_STATUS bits */
142#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3)
143#define CH2_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 2)
144#define CH1_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 1)
145#define CH0_DISABLED(pvt) ((pvt)->info.mc_status & 1 << 0)
146
147 /* MC_MAX_DOD read functions */
148static inline int maxnumdimms(struct i7core_pvt *pvt)
149{
150 return (pvt->info.max_dod & 0x3) + 1;
151}
152
153static inline int maxnumrank(struct i7core_pvt *pvt)
154{
155 static int ranks[4] = { 1, 2, 4, -EINVAL };
156
157 return ranks[(pvt->info.max_dod >> 2) & 0x3];
158}
159
160static inline int maxnumbank(struct i7core_pvt *pvt)
161{
162 static int banks[4] = { 4, 8, 16, -EINVAL };
163
164 return banks[(pvt->info.max_dod >> 4) & 0x3];
165}
166
167static inline int maxnumrow(struct i7core_pvt *pvt)
168{
169 static int rows[8] = {
170 1 << 12, 1 << 13, 1 << 14, 1 << 15,
171 1 << 16, -EINVAL, -EINVAL, -EINVAL,
172 };
173
174 return rows[((pvt->info.max_dod >> 6) & 0x7)];
175}
176
177static inline int maxnumcol(struct i7core_pvt *pvt)
178{
179 static int cols[8] = {
180 1 << 10, 1 << 11, 1 << 12, -EINVAL,
181 };
182 return cols[((pvt->info.max_dod >> 9) & 0x3) << 12];
183}
184
194a40fe 185
a0c36a1f
MCC
186/****************************************************************************
187 Memory check routines
188 ****************************************************************************/
189static int get_dimm_config(struct mem_ctl_info *mci)
190{
191 struct i7core_pvt *pvt = mci->pvt_info;
192
193 pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control);
194 pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status);
195 pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod);
196
197 debugf0("Channels active [%c][%c][%c] - enabled [%c][%c][%c]\n",
198 CH0_ACTIVE(pvt)?'0':'-',
199 CH1_ACTIVE(pvt)?'1':'-',
200 CH2_ACTIVE(pvt)?'2':'-',
201 CH0_DISABLED(pvt)?'-':'0',
202 CH1_DISABLED(pvt)?'-':'1',
203 CH2_DISABLED(pvt)?'-':'2');
204
205 if (ECC_ENABLED(pvt))
206 debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4);
207 else
208 debugf0("ECC disabled\n");
209
210 /* FIXME: need to handle the error codes */
211 debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n",
212 maxnumdimms(pvt), maxnumrank(pvt), maxnumbank(pvt));
213 debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n",
214 maxnumrow(pvt), maxnumcol(pvt));
215
216 return 0;
217}
218
194a40fe
MCC
219/****************************************************************************
220 Error insertion routines
221 ****************************************************************************/
222
223/* The i7core has independent error injection features per channel.
224 However, to have a simpler code, we don't allow enabling error injection
225 on more than one channel.
226 Also, since a change at an inject parameter will be applied only at enable,
227 we're disabling error injection on all write calls to the sysfs nodes that
228 controls the error code injection.
229 */
230static void disable_inject(struct mem_ctl_info *mci)
231{
232 struct i7core_pvt *pvt = mci->pvt_info;
233
234 pvt->inject.enable = 0;
235
236 pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
237 MC_CHANNEL_ERROR_MASK, 0);
238}
239
240/*
241 * i7core inject inject.section
242 *
243 * accept and store error injection inject.section value
244 * bit 0 - refers to the lower 32-byte half cacheline
245 * bit 1 - refers to the upper 32-byte half cacheline
246 */
247static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
248 const char *data, size_t count)
249{
250 struct i7core_pvt *pvt = mci->pvt_info;
251 unsigned long value;
252 int rc;
253
254 if (pvt->inject.enable)
255 disable_inject(mci);
256
257 rc = strict_strtoul(data, 10, &value);
258 if ((rc < 0) || (value > 3))
259 return 0;
260
261 pvt->inject.section = (u32) value;
262 return count;
263}
264
265static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
266 char *data)
267{
268 struct i7core_pvt *pvt = mci->pvt_info;
269 return sprintf(data, "0x%08x\n", pvt->inject.section);
270}
271
272/*
273 * i7core inject.type
274 *
275 * accept and store error injection inject.section value
276 * bit 0 - repeat enable - Enable error repetition
277 * bit 1 - inject ECC error
278 * bit 2 - inject parity error
279 */
280static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
281 const char *data, size_t count)
282{
283 struct i7core_pvt *pvt = mci->pvt_info;
284 unsigned long value;
285 int rc;
286
287 if (pvt->inject.enable)
288 disable_inject(mci);
289
290 rc = strict_strtoul(data, 10, &value);
291 if ((rc < 0) || (value > 7))
292 return 0;
293
294 pvt->inject.type = (u32) value;
295 return count;
296}
297
298static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
299 char *data)
300{
301 struct i7core_pvt *pvt = mci->pvt_info;
302 return sprintf(data, "0x%08x\n", pvt->inject.type);
303}
304
305/*
306 * i7core_inject_inject.eccmask_store
307 *
308 * The type of error (UE/CE) will depend on the inject.eccmask value:
309 * Any bits set to a 1 will flip the corresponding ECC bit
310 * Correctable errors can be injected by flipping 1 bit or the bits within
311 * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
312 * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
313 * uncorrectable error to be injected.
314 */
315static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
316 const char *data, size_t count)
317{
318 struct i7core_pvt *pvt = mci->pvt_info;
319 unsigned long value;
320 int rc;
321
322 if (pvt->inject.enable)
323 disable_inject(mci);
324
325 rc = strict_strtoul(data, 10, &value);
326 if (rc < 0)
327 return 0;
328
329 pvt->inject.eccmask = (u32) value;
330 return count;
331}
332
333static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
334 char *data)
335{
336 struct i7core_pvt *pvt = mci->pvt_info;
337 return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
338}
339
340/*
341 * i7core_addrmatch
342 *
343 * The type of error (UE/CE) will depend on the inject.eccmask value:
344 * Any bits set to a 1 will flip the corresponding ECC bit
345 * Correctable errors can be injected by flipping 1 bit or the bits within
346 * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
347 * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
348 * uncorrectable error to be injected.
349 */
350static ssize_t i7core_inject_addrmatch_store(struct mem_ctl_info *mci,
351 const char *data, size_t count)
352{
353 struct i7core_pvt *pvt = mci->pvt_info;
354 char *cmd, *val;
355 long value;
356 int rc;
357
358 if (pvt->inject.enable)
359 disable_inject(mci);
360
361 do {
362 cmd = strsep((char **) &data, ":");
363 if (!cmd)
364 break;
365 val = strsep((char **) &data, " \n\t");
366 if (!val)
367 return cmd - data;
368
369 if (!strcasecmp(val,"any"))
370 value = -1;
371 else {
372 rc = strict_strtol(val, 10, &value);
373 if ((rc < 0) || (value < 0))
374 return cmd - data;
375 }
376
377 if (!strcasecmp(cmd,"channel")) {
378 if (value < 3)
379 pvt->inject.channel = value;
380 else
381 return cmd - data;
382 } else if (!strcasecmp(cmd,"dimm")) {
383 if (value < 4)
384 pvt->inject.dimm = value;
385 else
386 return cmd - data;
387 } else if (!strcasecmp(cmd,"rank")) {
388 if (value < 4)
389 pvt->inject.rank = value;
390 else
391 return cmd - data;
392 } else if (!strcasecmp(cmd,"bank")) {
393 if (value < 4)
394 pvt->inject.bank = value;
395 else
396 return cmd - data;
397 } else if (!strcasecmp(cmd,"page")) {
398 if (value <= 0xffff)
399 pvt->inject.page = value;
400 else
401 return cmd - data;
402 } else if (!strcasecmp(cmd,"col") ||
403 !strcasecmp(cmd,"column")) {
404 if (value <= 0x3fff)
405 pvt->inject.col = value;
406 else
407 return cmd - data;
408 }
409 } while (1);
410
411 return count;
412}
413
414static ssize_t i7core_inject_addrmatch_show(struct mem_ctl_info *mci,
415 char *data)
416{
417 struct i7core_pvt *pvt = mci->pvt_info;
418 char channel[4], dimm[4], bank[4], rank[4], page[7], col[7];
419
420 if (pvt->inject.channel < 0)
421 sprintf(channel, "any");
422 else
423 sprintf(channel, "%d", pvt->inject.channel);
424 if (pvt->inject.dimm < 0)
425 sprintf(dimm, "any");
426 else
427 sprintf(dimm, "%d", pvt->inject.dimm);
428 if (pvt->inject.bank < 0)
429 sprintf(bank, "any");
430 else
431 sprintf(bank, "%d", pvt->inject.bank);
432 if (pvt->inject.rank < 0)
433 sprintf(rank, "any");
434 else
435 sprintf(rank, "%d", pvt->inject.rank);
436 if (pvt->inject.page < 0)
437 sprintf(page, "any");
438 else
439 sprintf(page, "0x%04x", pvt->inject.page);
440 if (pvt->inject.col < 0)
441 sprintf(col, "any");
442 else
443 sprintf(col, "0x%04x", pvt->inject.col);
444
445 return sprintf(data, "channel: %s\ndimm: %s\nbank: %s\n"
446 "rank: %s\npage: %s\ncolumn: %s\n",
447 channel, dimm, bank, rank, page, col);
448}
449
450/*
451 * This routine prepares the Memory Controller for error injection.
452 * The error will be injected when some process tries to write to the
453 * memory that matches the given criteria.
454 * The criteria can be set in terms of a mask where dimm, rank, bank, page
455 * and col can be specified.
456 * A -1 value for any of the mask items will make the MCU to ignore
457 * that matching criteria for error injection.
458 *
459 * It should be noticed that the error will only happen after a write operation
460 * on a memory that matches the condition. if REPEAT_EN is not enabled at
461 * inject mask, then it will produce just one error. Otherwise, it will repeat
462 * until the injectmask would be cleaned.
463 *
464 * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD
465 * is reliable enough to check if the MC is using the
466 * three channels. However, this is not clear at the datasheet.
467 */
468static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
469 const char *data, size_t count)
470{
471 struct i7core_pvt *pvt = mci->pvt_info;
472 u32 injectmask;
473 u64 mask = 0;
474 int rc;
475 long enable;
476
477 rc = strict_strtoul(data, 10, &enable);
478 if ((rc < 0))
479 return 0;
480
481 if (enable) {
482 pvt->inject.enable = 1;
483 } else {
484 disable_inject(mci);
485 return count;
486 }
487
488 /* Sets pvt->inject.dimm mask */
489 if (pvt->inject.dimm < 0)
490 mask |= 1l << 41;
491 else {
492 if (maxnumdimms(pvt) > 2)
493 mask |= (pvt->inject.dimm & 0x3l) << 35;
494 else
495 mask |= (pvt->inject.dimm & 0x1l) << 36;
496 }
497
498 /* Sets pvt->inject.rank mask */
499 if (pvt->inject.rank < 0)
500 mask |= 1l << 40;
501 else {
502 if (maxnumdimms(pvt) > 2)
503 mask |= (pvt->inject.rank & 0x1l) << 34;
504 else
505 mask |= (pvt->inject.rank & 0x3l) << 34;
506 }
507
508 /* Sets pvt->inject.bank mask */
509 if (pvt->inject.bank < 0)
510 mask |= 1l << 39;
511 else
512 mask |= (pvt->inject.bank & 0x15l) << 30;
513
514 /* Sets pvt->inject.page mask */
515 if (pvt->inject.page < 0)
516 mask |= 1l << 38;
517 else
518 mask |= (pvt->inject.page & 0xffffl) << 14;
519
520 /* Sets pvt->inject.column mask */
521 if (pvt->inject.col < 0)
522 mask |= 1l << 37;
523 else
524 mask |= (pvt->inject.col & 0x3fffl);
525
526 pci_write_config_qword(pvt->pci_ch[pvt->inject.channel][0],
527 MC_CHANNEL_ADDR_MATCH, mask);
528
529 pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
530 MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask);
531
532 /*
533 * bit 0: REPEAT_EN
534 * bits 1-2: MASK_HALF_CACHELINE
535 * bit 3: INJECT_ECC
536 * bit 4: INJECT_ADDR_PARITY
537 */
538
539 injectmask = (pvt->inject.type & 1) &&
540 (pvt->inject.section & 0x3) << 1 &&
541 (pvt->inject.type & 0x6) << (3 - 1);
542
543 pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
544 MC_CHANNEL_ERROR_MASK, injectmask);
545
546
547 debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n",
548 mask, pvt->inject.eccmask, injectmask);
549
550 return count;
551}
552
553static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
554 char *data)
555{
556 struct i7core_pvt *pvt = mci->pvt_info;
557 return sprintf(data, "%d\n", pvt->inject.enable);
558}
559
560/*
561 * Sysfs struct
562 */
563static struct mcidev_sysfs_attribute i7core_inj_attrs[] = {
564
565 {
566 .attr = {
567 .name = "inject_section",
568 .mode = (S_IRUGO | S_IWUSR)
569 },
570 .show = i7core_inject_section_show,
571 .store = i7core_inject_section_store,
572 }, {
573 .attr = {
574 .name = "inject_type",
575 .mode = (S_IRUGO | S_IWUSR)
576 },
577 .show = i7core_inject_type_show,
578 .store = i7core_inject_type_store,
579 }, {
580 .attr = {
581 .name = "inject_eccmask",
582 .mode = (S_IRUGO | S_IWUSR)
583 },
584 .show = i7core_inject_eccmask_show,
585 .store = i7core_inject_eccmask_store,
586 }, {
587 .attr = {
588 .name = "inject_addrmatch",
589 .mode = (S_IRUGO | S_IWUSR)
590 },
591 .show = i7core_inject_addrmatch_show,
592 .store = i7core_inject_addrmatch_store,
593 }, {
594 .attr = {
595 .name = "inject_enable",
596 .mode = (S_IRUGO | S_IWUSR)
597 },
598 .show = i7core_inject_enable_show,
599 .store = i7core_inject_enable_store,
600 },
601};
602
a0c36a1f
MCC
603/****************************************************************************
604 Device initialization routines: put/get, init/exit
605 ****************************************************************************/
606
607/*
608 * i7core_put_devices 'put' all the devices that we have
609 * reserved via 'get'
610 */
611static void i7core_put_devices(struct mem_ctl_info *mci)
612{
613 struct i7core_pvt *pvt = mci->pvt_info;
614 int i, n;
615
616 pci_dev_put(pvt->pci_mcr);
617
618 /* Release all PCI device functions at MTR channel controllers */
619 for (i = 0; i < NUM_CHANS; i++)
620 for (n = 0; n < NUM_FUNCS; n++)
621 pci_dev_put(pvt->pci_ch[i][n]);
622}
623
624/*
625 * i7core_get_devices Find and perform 'get' operation on the MCH's
626 * device/functions we want to reference for this driver
627 *
628 * Need to 'get' device 16 func 1 and func 2
629 */
630static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx)
631{
632 struct i7core_pvt *pvt;
633 struct pci_dev *pdev;
634 int i, n, func;
635
636 pvt = mci->pvt_info;
637 memset(pvt, 0, sizeof(*pvt));
638
639 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR,
640 NULL);
641 if (!pdev) {
642 i7core_printk(KERN_ERR,
643 "Couldn't get PCI ID %04x:%04x function 0\n",
644 PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR);
645 return -ENODEV;
646 }
647 pvt->pci_mcr=pdev;
648
649 /* Get dimm basic config */
650 get_dimm_config(mci);
651
652 /* Retrieve all needed functions at MTR channel controllers */
653 for (i = 0; i < NUM_CHANS; i++) {
654 pdev = NULL;
655 for (n = 0; n < NUM_FUNCS; n++) {
656 pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
657 chan_pci_ids[i], pdev);
658 if (!pdev) {
659 /* End of list, leave */
660 i7core_printk(KERN_ERR,
661 "Device not found: PCI ID %04x:%04x "
662 "found only %d functions "
663 "(broken BIOS?)\n",
664 PCI_VENDOR_ID_INTEL,
665 chan_pci_ids[i], n);
666 i7core_put_devices(mci);
667 return -ENODEV;
668 }
669 func = PCI_FUNC(pdev->devfn);
670 pvt->pci_ch[i][func] = pdev;
671 }
672 }
673 i7core_printk(KERN_INFO, "Driver loaded.\n");
674
675 return 0;
676}
677
678/*
679 * i7core_probe Probe for ONE instance of device to see if it is
680 * present.
681 * return:
682 * 0 for FOUND a device
683 * < 0 for error code
684 */
685static int __devinit i7core_probe(struct pci_dev *pdev,
686 const struct pci_device_id *id)
687{
688 struct mem_ctl_info *mci;
689 struct i7core_pvt *pvt;
690 int rc;
691 int num_channels;
692 int num_csrows;
693 int num_dimms_per_channel;
694 int dev_idx = id->driver_data;
695
696 if (dev_idx >= ARRAY_SIZE(i7core_devs))
697 return -EINVAL;
698
699 /* wake up device */
700 rc = pci_enable_device(pdev);
701 if (rc == -EIO)
702 return rc;
703
704 debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
705 __func__,
706 pdev->bus->number,
707 PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
708
709 /* We only are looking for func 0 of the set */
710 if (PCI_FUNC(pdev->devfn) != 0)
711 return -ENODEV;
712
713 num_channels = NUM_CHANS;
714
715 /* FIXME: FAKE data, since we currently don't now how to get this */
716 num_dimms_per_channel = 4;
717 num_csrows = num_dimms_per_channel;
718
719 /* allocate a new MC control structure */
720 mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
721 if (mci == NULL)
722 return -ENOMEM;
723
724 debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
725
194a40fe 726 mci->dev = &pdev->dev; /* record ptr to the generic device */
a0c36a1f
MCC
727 dev_set_drvdata(mci->dev, mci);
728
729 pvt = mci->pvt_info;
194a40fe 730
a0c36a1f
MCC
731// pvt->system_address = pdev; /* Record this device in our private */
732// pvt->maxch = num_channels;
733// pvt->maxdimmperch = num_dimms_per_channel;
734
735 /* 'get' the pci devices we want to reserve for our use */
736 if (i7core_get_devices(mci, dev_idx))
737 goto fail0;
738
739 mci->mc_idx = 0;
740 mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */
741 mci->edac_ctl_cap = EDAC_FLAG_NONE;
742 mci->edac_cap = EDAC_FLAG_NONE;
743 mci->mod_name = "i7core_edac.c";
744 mci->mod_ver = I7CORE_REVISION;
745 mci->ctl_name = i7core_devs[dev_idx].ctl_name;
746 mci->dev_name = pci_name(pdev);
747 mci->ctl_page_to_phys = NULL;
194a40fe 748 mci->mc_driver_sysfs_attributes = i7core_inj_attrs;
a0c36a1f
MCC
749
750 /* add this new MC control structure to EDAC's list of MCs */
751 if (edac_mc_add_mc(mci)) {
752 debugf0("MC: " __FILE__
753 ": %s(): failed edac_mc_add_mc()\n", __func__);
754 /* FIXME: perhaps some code should go here that disables error
755 * reporting if we just enabled it
756 */
757 goto fail1;
758 }
759
760 /* allocating generic PCI control info */
761 i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
762 if (!i7core_pci) {
763 printk(KERN_WARNING
764 "%s(): Unable to create PCI control\n",
765 __func__);
766 printk(KERN_WARNING
767 "%s(): PCI error report via EDAC not setup\n",
768 __func__);
769 }
770
194a40fe
MCC
771 /* Default error mask is any memory */
772 pvt->inject.channel = -1;
773 pvt->inject.dimm = -1;
774 pvt->inject.rank = -1;
775 pvt->inject.bank = -1;
776 pvt->inject.page = -1;
777 pvt->inject.col = -1;
778
a0c36a1f
MCC
779 return 0;
780
781fail1:
782 i7core_put_devices(mci);
783
784fail0:
785 edac_mc_free(mci);
786 return -ENODEV;
787}
788
789/*
790 * i7core_remove destructor for one instance of device
791 *
792 */
793static void __devexit i7core_remove(struct pci_dev *pdev)
794{
795 struct mem_ctl_info *mci;
796
797 debugf0(__FILE__ ": %s()\n", __func__);
798
799 if (i7core_pci)
800 edac_pci_release_generic_ctl(i7core_pci);
801
802 mci = edac_mc_del_mc(&pdev->dev);
803 if (!mci)
804 return;
805
806 /* retrieve references to resources, and free those resources */
807 i7core_put_devices(mci);
808
809 edac_mc_free(mci);
810}
811
812/*
813 * pci_device_id table for which devices we are looking for
814 *
815 * The "E500P" device is the first device supported.
816 */
817static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
818 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)},
819 {0,} /* 0 terminated list. */
820};
821
822MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);
823
824/*
825 * i7core_driver pci_driver structure for this module
826 *
827 */
828static struct pci_driver i7core_driver = {
829 .name = "i7core_edac",
830 .probe = i7core_probe,
831 .remove = __devexit_p(i7core_remove),
832 .id_table = i7core_pci_tbl,
833};
834
835/*
836 * i7core_init Module entry function
837 * Try to initialize this module for its devices
838 */
839static int __init i7core_init(void)
840{
841 int pci_rc;
842
843 debugf2("MC: " __FILE__ ": %s()\n", __func__);
844
845 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
846 opstate_init();
847
848 pci_rc = pci_register_driver(&i7core_driver);
849
850 return (pci_rc < 0) ? pci_rc : 0;
851}
852
853/*
854 * i7core_exit() Module exit function
855 * Unregister the driver
856 */
857static void __exit i7core_exit(void)
858{
859 debugf2("MC: " __FILE__ ": %s()\n", __func__);
860 pci_unregister_driver(&i7core_driver);
861}
862
863module_init(i7core_init);
864module_exit(i7core_exit);
865
866MODULE_LICENSE("GPL");
867MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
868MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
869MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
870 I7CORE_REVISION);
871
872module_param(edac_op_state, int, 0444);
873MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");