1 /* Intel 7 core Memory Controller kernel module (Nehalem)
3 * This file may be distributed under the terms of the
4 * GNU General Public License version 2 only.
6 * Copyright (c) 2009 by:
7 * Mauro Carvalho Chehab <mchehab@redhat.com>
9 * Red Hat Inc. http://www.redhat.com
11 * Forked and adapted from the i5400_edac driver
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
20 * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
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>
31 #include "edac_core.h"
33 /* To use the new pci_[read/write]_config_qword instead of two dword */
37 * Alter this version for the module when modifications are made
39 #define I7CORE_REVISION " Ver: 1.0.0 " __DATE__
40 #define EDAC_MOD_STR "i7core_edac"
42 /* HACK: temporary, just to enable all logs, for now */
44 #define debugf0(fmt, arg...) edac_printk(KERN_INFO, "i7core", fmt, ##arg)
49 #define i7core_printk(level, fmt, arg...) \
50 edac_printk(level, "i7core", fmt, ##arg)
52 #define i7core_mc_printk(mci, level, fmt, arg...) \
53 edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg)
56 * i7core Memory Controller Registers
59 /* OFFSETS for Device 3 Function 0 */
61 #define MC_CONTROL 0x48
62 #define MC_STATUS 0x4c
63 #define MC_MAX_DOD 0x64
65 /* OFFSETS for Devices 4,5 and 6 Function 0 */
67 #define MC_CHANNEL_DIMM_INIT_PARAMS 0x58
68 #define THREE_DIMMS_PRESENT (1 << 24)
69 #define SINGLE_QUAD_RANK_PRESENT (1 << 23)
70 #define QUAD_RANK_PRESENT (1 << 22)
71 #define REGISTERED_DIMM (1 << 15)
73 #define MC_CHANNEL_MAPPER 0x60
74 #define RDLCH(r, ch) ((((r) >> (3 + (ch * 6))) & 0x07) - 1)
75 #define WRLCH(r, ch) ((((r) >> (ch * 6)) & 0x07) - 1)
77 #define MC_CHANNEL_RANK_PRESENT 0x7c
78 #define RANK_PRESENT_MASK 0xffff
80 #define MC_CHANNEL_ADDR_MATCH 0xf0
81 #define MC_CHANNEL_ERROR_MASK 0xf8
82 #define MC_CHANNEL_ERROR_INJECT 0xfc
83 #define INJECT_ADDR_PARITY 0x10
84 #define INJECT_ECC 0x08
85 #define MASK_CACHELINE 0x06
86 #define MASK_FULL_CACHELINE 0x06
87 #define MASK_MSB32_CACHELINE 0x04
88 #define MASK_LSB32_CACHELINE 0x02
89 #define NO_MASK_CACHELINE 0x00
90 #define REPEAT_EN 0x01
92 /* OFFSETS for Devices 4,5 and 6 Function 1 */
93 #define MC_DOD_CH_DIMM0 0x48
94 #define MC_DOD_CH_DIMM1 0x4c
95 #define MC_DOD_CH_DIMM2 0x50
96 #define RANKOFFSET_MASK ((1 << 12) | (1 << 11) | (1 << 10))
97 #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10)
98 #define DIMM_PRESENT_MASK (1 << 9)
99 #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9)
100 #define NUMBANK_MASK ((1 << 8) | (1 << 7))
101 #define NUMBANK(x) (((x) & NUMBANK_MASK) >> 7)
102 #define NUMRANK_MASK ((1 << 6) | (1 << 5))
103 #define NUMRANK(x) (((x) & NUMRANK_MASK) >> 5)
104 #define NUMROW_MASK ((1 << 4) | (1 << 3))
105 #define NUMROW(x) (((x) & NUMROW_MASK) >> 3)
106 #define NUMCOL_MASK 3
107 #define NUMCOL(x) ((x) & NUMCOL_MASK)
109 #define MC_RANK_PRESENT 0x7c
111 #define MC_SAG_CH_0 0x80
112 #define MC_SAG_CH_1 0x84
113 #define MC_SAG_CH_2 0x88
114 #define MC_SAG_CH_3 0x8c
115 #define MC_SAG_CH_4 0x90
116 #define MC_SAG_CH_5 0x94
117 #define MC_SAG_CH_6 0x98
118 #define MC_SAG_CH_7 0x9c
120 #define MC_RIR_LIMIT_CH_0 0x40
121 #define MC_RIR_LIMIT_CH_1 0x44
122 #define MC_RIR_LIMIT_CH_2 0x48
123 #define MC_RIR_LIMIT_CH_3 0x4C
124 #define MC_RIR_LIMIT_CH_4 0x50
125 #define MC_RIR_LIMIT_CH_5 0x54
126 #define MC_RIR_LIMIT_CH_6 0x58
127 #define MC_RIR_LIMIT_CH_7 0x5C
128 #define MC_RIR_LIMIT_MASK ((1 << 10) - 1)
130 #define MC_RIR_WAY_CH 0x80
131 #define MC_RIR_WAY_OFFSET_MASK (((1 << 14) - 1) & ~0x7)
132 #define MC_RIR_WAY_RANK_MASK 0x7
139 #define NUM_MCR_FUNCS 4
140 #define NUM_CHAN_FUNCS 3
150 struct i7core_inject
{
157 /* Error address mask */
158 int channel
, dimm
, rank
, bank
, page
, col
;
161 struct i7core_channel
{
166 struct pci_id_descr
{
170 struct pci_dev
*pdev
;
174 struct pci_dev
*pci_mcr
[NUM_MCR_FUNCS
];
175 struct pci_dev
*pci_ch
[NUM_CHANS
][NUM_CHAN_FUNCS
];
176 struct i7core_info info
;
177 struct i7core_inject inject
;
178 struct i7core_channel channel
[NUM_CHANS
];
181 /* Device name and register DID (Device ID) */
182 struct i7core_dev_info
{
183 const char *ctl_name
; /* name for this device */
184 u16 fsb_mapping_errors
; /* DID for the branchmap,control */
187 #define PCI_DESCR(device, function, device_id) \
189 .func = (function), \
190 .dev_id = (device_id)
192 struct pci_id_descr pci_devs
[] = {
193 /* Memory controller */
194 { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR
) },
195 { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD
) },
196 { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS
) }, /* if RDIMM is supported */
197 { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST
) },
200 { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL
) },
201 { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR
) },
202 { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK
) },
203 { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC
) },
206 { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL
) },
207 { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR
) },
208 { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK
) },
209 { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC
) },
212 { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL
) },
213 { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR
) },
214 { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK
) },
215 { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC
) },
217 #define N_DEVS ARRAY_SIZE(pci_devs)
220 * pci_device_id table for which devices we are looking for
221 * This should match the first device at pci_devs table
223 static const struct pci_device_id i7core_pci_tbl
[] __devinitdata
= {
224 {PCI_DEVICE(PCI_VENDOR_ID_INTEL
, PCI_DEVICE_ID_INTEL_I7_MCR
)},
225 {0,} /* 0 terminated list. */
229 /* Table of devices attributes supported by this driver */
230 static const struct i7core_dev_info i7core_devs
[] = {
232 .ctl_name
= "i7 Core",
233 .fsb_mapping_errors
= PCI_DEVICE_ID_INTEL_I7_MCR
,
237 static struct edac_pci_ctl_info
*i7core_pci
;
239 /****************************************************************************
240 Anciliary status routines
241 ****************************************************************************/
243 /* MC_CONTROL bits */
244 #define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & 1 << (8 + ch))
245 #define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1)
248 #define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3)
249 #define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & 1 << ch)
251 /* MC_MAX_DOD read functions */
252 static inline int maxnumdimms(struct i7core_pvt
*pvt
)
254 return (pvt
->info
.max_dod
& 0x3) + 1;
257 static inline int maxnumrank(struct i7core_pvt
*pvt
)
259 static int ranks
[4] = { 1, 2, 4, -EINVAL
};
261 return ranks
[(pvt
->info
.max_dod
>> 2) & 0x3];
264 static inline int maxnumbank(struct i7core_pvt
*pvt
)
266 static int banks
[4] = { 4, 8, 16, -EINVAL
};
268 return banks
[(pvt
->info
.max_dod
>> 4) & 0x3];
271 static inline int maxnumrow(struct i7core_pvt
*pvt
)
273 static int rows
[8] = {
274 1 << 12, 1 << 13, 1 << 14, 1 << 15,
275 1 << 16, -EINVAL
, -EINVAL
, -EINVAL
,
278 return rows
[((pvt
->info
.max_dod
>> 6) & 0x7)];
281 static inline int maxnumcol(struct i7core_pvt
*pvt
)
283 static int cols
[8] = {
284 1 << 10, 1 << 11, 1 << 12, -EINVAL
,
286 return cols
[((pvt
->info
.max_dod
>> 9) & 0x3) << 12];
290 /****************************************************************************
291 Memory check routines
292 ****************************************************************************/
293 static int get_dimm_config(struct mem_ctl_info
*mci
)
295 struct i7core_pvt
*pvt
= mci
->pvt_info
;
298 if (!pvt
->pci_mcr
[0])
301 /* Device 3 function 0 reads */
302 pci_read_config_dword(pvt
->pci_mcr
[0], MC_CONTROL
,
303 &pvt
->info
.mc_control
);
304 pci_read_config_dword(pvt
->pci_mcr
[0], MC_STATUS
,
305 &pvt
->info
.mc_status
);
306 pci_read_config_dword(pvt
->pci_mcr
[0], MC_MAX_DOD
,
308 pci_read_config_dword(pvt
->pci_mcr
[0], MC_CHANNEL_MAPPER
,
311 debugf0("MC control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
312 pvt
->info
.mc_control
, pvt
->info
.mc_status
,
313 pvt
->info
.max_dod
, pvt
->info
.ch_map
);
315 if (ECC_ENABLED(pvt
))
316 debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt
)?8:4);
318 debugf0("ECC disabled\n");
320 /* FIXME: need to handle the error codes */
321 debugf0("DOD Maximum limits: DIMMS: %d, %d-ranked, %d-banked\n",
322 maxnumdimms(pvt
), maxnumrank(pvt
), maxnumbank(pvt
));
323 debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n",
324 maxnumrow(pvt
), maxnumcol(pvt
));
326 debugf0("Memory channel configuration:\n");
328 for (i
= 0; i
< NUM_CHANS
; i
++) {
331 if (!CH_ACTIVE(pvt
, i
)) {
332 debugf0("Channel %i is not active\n", i
);
335 if (CH_DISABLED(pvt
, i
)) {
336 debugf0("Channel %i is disabled\n", i
);
340 /* Devices 4-6 function 0 */
341 pci_read_config_dword(pvt
->pci_ch
[i
][0],
342 MC_CHANNEL_DIMM_INIT_PARAMS
, &data
);
344 pvt
->channel
[i
].ranks
= (data
& QUAD_RANK_PRESENT
)? 4 : 2;
346 if (data
& THREE_DIMMS_PRESENT
)
347 pvt
->channel
[i
].dimms
= 3;
348 else if (data
& SINGLE_QUAD_RANK_PRESENT
)
349 pvt
->channel
[i
].dimms
= 1;
351 pvt
->channel
[i
].dimms
= 2;
353 debugf0("Ch%d (0x%08x): rd ch %d, wr ch %d, "
354 "%d ranks, %d %cDIMMs\n",
356 RDLCH(pvt
->info
.ch_map
, i
),
357 WRLCH(pvt
->info
.ch_map
, i
),
358 pvt
->channel
[i
].ranks
, pvt
->channel
[i
].dimms
,
359 (data
& REGISTERED_DIMM
)? 'R' : 'U' );
365 /****************************************************************************
366 Error insertion routines
367 ****************************************************************************/
369 /* The i7core has independent error injection features per channel.
370 However, to have a simpler code, we don't allow enabling error injection
371 on more than one channel.
372 Also, since a change at an inject parameter will be applied only at enable,
373 we're disabling error injection on all write calls to the sysfs nodes that
374 controls the error code injection.
376 static int disable_inject(struct mem_ctl_info
*mci
)
378 struct i7core_pvt
*pvt
= mci
->pvt_info
;
380 pvt
->inject
.enable
= 0;
382 if (!pvt
->pci_ch
[pvt
->inject
.channel
][0])
385 pci_write_config_dword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
386 MC_CHANNEL_ERROR_MASK
, 0);
392 * i7core inject inject.section
394 * accept and store error injection inject.section value
395 * bit 0 - refers to the lower 32-byte half cacheline
396 * bit 1 - refers to the upper 32-byte half cacheline
398 static ssize_t
i7core_inject_section_store(struct mem_ctl_info
*mci
,
399 const char *data
, size_t count
)
401 struct i7core_pvt
*pvt
= mci
->pvt_info
;
405 if (pvt
->inject
.enable
)
408 rc
= strict_strtoul(data
, 10, &value
);
409 if ((rc
< 0) || (value
> 3))
412 pvt
->inject
.section
= (u32
) value
;
416 static ssize_t
i7core_inject_section_show(struct mem_ctl_info
*mci
,
419 struct i7core_pvt
*pvt
= mci
->pvt_info
;
420 return sprintf(data
, "0x%08x\n", pvt
->inject
.section
);
426 * accept and store error injection inject.section value
427 * bit 0 - repeat enable - Enable error repetition
428 * bit 1 - inject ECC error
429 * bit 2 - inject parity error
431 static ssize_t
i7core_inject_type_store(struct mem_ctl_info
*mci
,
432 const char *data
, size_t count
)
434 struct i7core_pvt
*pvt
= mci
->pvt_info
;
438 if (pvt
->inject
.enable
)
441 rc
= strict_strtoul(data
, 10, &value
);
442 if ((rc
< 0) || (value
> 7))
445 pvt
->inject
.type
= (u32
) value
;
449 static ssize_t
i7core_inject_type_show(struct mem_ctl_info
*mci
,
452 struct i7core_pvt
*pvt
= mci
->pvt_info
;
453 return sprintf(data
, "0x%08x\n", pvt
->inject
.type
);
457 * i7core_inject_inject.eccmask_store
459 * The type of error (UE/CE) will depend on the inject.eccmask value:
460 * Any bits set to a 1 will flip the corresponding ECC bit
461 * Correctable errors can be injected by flipping 1 bit or the bits within
462 * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
463 * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
464 * uncorrectable error to be injected.
466 static ssize_t
i7core_inject_eccmask_store(struct mem_ctl_info
*mci
,
467 const char *data
, size_t count
)
469 struct i7core_pvt
*pvt
= mci
->pvt_info
;
473 if (pvt
->inject
.enable
)
476 rc
= strict_strtoul(data
, 10, &value
);
480 pvt
->inject
.eccmask
= (u32
) value
;
484 static ssize_t
i7core_inject_eccmask_show(struct mem_ctl_info
*mci
,
487 struct i7core_pvt
*pvt
= mci
->pvt_info
;
488 return sprintf(data
, "0x%08x\n", pvt
->inject
.eccmask
);
494 * The type of error (UE/CE) will depend on the inject.eccmask value:
495 * Any bits set to a 1 will flip the corresponding ECC bit
496 * Correctable errors can be injected by flipping 1 bit or the bits within
497 * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
498 * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
499 * uncorrectable error to be injected.
501 static ssize_t
i7core_inject_addrmatch_store(struct mem_ctl_info
*mci
,
502 const char *data
, size_t count
)
504 struct i7core_pvt
*pvt
= mci
->pvt_info
;
509 if (pvt
->inject
.enable
)
513 cmd
= strsep((char **) &data
, ":");
516 val
= strsep((char **) &data
, " \n\t");
520 if (!strcasecmp(val
,"any"))
523 rc
= strict_strtol(val
, 10, &value
);
524 if ((rc
< 0) || (value
< 0))
528 if (!strcasecmp(cmd
,"channel")) {
530 pvt
->inject
.channel
= value
;
533 } else if (!strcasecmp(cmd
,"dimm")) {
535 pvt
->inject
.dimm
= value
;
538 } else if (!strcasecmp(cmd
,"rank")) {
540 pvt
->inject
.rank
= value
;
543 } else if (!strcasecmp(cmd
,"bank")) {
545 pvt
->inject
.bank
= value
;
548 } else if (!strcasecmp(cmd
,"page")) {
550 pvt
->inject
.page
= value
;
553 } else if (!strcasecmp(cmd
,"col") ||
554 !strcasecmp(cmd
,"column")) {
556 pvt
->inject
.col
= value
;
565 static ssize_t
i7core_inject_addrmatch_show(struct mem_ctl_info
*mci
,
568 struct i7core_pvt
*pvt
= mci
->pvt_info
;
569 char channel
[4], dimm
[4], bank
[4], rank
[4], page
[7], col
[7];
571 if (pvt
->inject
.channel
< 0)
572 sprintf(channel
, "any");
574 sprintf(channel
, "%d", pvt
->inject
.channel
);
575 if (pvt
->inject
.dimm
< 0)
576 sprintf(dimm
, "any");
578 sprintf(dimm
, "%d", pvt
->inject
.dimm
);
579 if (pvt
->inject
.bank
< 0)
580 sprintf(bank
, "any");
582 sprintf(bank
, "%d", pvt
->inject
.bank
);
583 if (pvt
->inject
.rank
< 0)
584 sprintf(rank
, "any");
586 sprintf(rank
, "%d", pvt
->inject
.rank
);
587 if (pvt
->inject
.page
< 0)
588 sprintf(page
, "any");
590 sprintf(page
, "0x%04x", pvt
->inject
.page
);
591 if (pvt
->inject
.col
< 0)
594 sprintf(col
, "0x%04x", pvt
->inject
.col
);
596 return sprintf(data
, "channel: %s\ndimm: %s\nbank: %s\n"
597 "rank: %s\npage: %s\ncolumn: %s\n",
598 channel
, dimm
, bank
, rank
, page
, col
);
602 * This routine prepares the Memory Controller for error injection.
603 * The error will be injected when some process tries to write to the
604 * memory that matches the given criteria.
605 * The criteria can be set in terms of a mask where dimm, rank, bank, page
606 * and col can be specified.
607 * A -1 value for any of the mask items will make the MCU to ignore
608 * that matching criteria for error injection.
610 * It should be noticed that the error will only happen after a write operation
611 * on a memory that matches the condition. if REPEAT_EN is not enabled at
612 * inject mask, then it will produce just one error. Otherwise, it will repeat
613 * until the injectmask would be cleaned.
615 * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD
616 * is reliable enough to check if the MC is using the
617 * three channels. However, this is not clear at the datasheet.
619 static ssize_t
i7core_inject_enable_store(struct mem_ctl_info
*mci
,
620 const char *data
, size_t count
)
622 struct i7core_pvt
*pvt
= mci
->pvt_info
;
628 if (!pvt
->pci_ch
[pvt
->inject
.channel
][0])
631 rc
= strict_strtoul(data
, 10, &enable
);
636 pvt
->inject
.enable
= 1;
642 /* Sets pvt->inject.dimm mask */
643 if (pvt
->inject
.dimm
< 0)
646 if (pvt
->channel
[pvt
->inject
.channel
].dimms
> 2)
647 mask
|= (pvt
->inject
.dimm
& 0x3L
) << 35;
649 mask
|= (pvt
->inject
.dimm
& 0x1L
) << 36;
652 /* Sets pvt->inject.rank mask */
653 if (pvt
->inject
.rank
< 0)
656 if (pvt
->channel
[pvt
->inject
.channel
].dimms
> 2)
657 mask
|= (pvt
->inject
.rank
& 0x1L
) << 34;
659 mask
|= (pvt
->inject
.rank
& 0x3L
) << 34;
662 /* Sets pvt->inject.bank mask */
663 if (pvt
->inject
.bank
< 0)
666 mask
|= (pvt
->inject
.bank
& 0x15L
) << 30;
668 /* Sets pvt->inject.page mask */
669 if (pvt
->inject
.page
< 0)
672 mask
|= (pvt
->inject
.page
& 0xffffL
) << 14;
674 /* Sets pvt->inject.column mask */
675 if (pvt
->inject
.col
< 0)
678 mask
|= (pvt
->inject
.col
& 0x3fffL
);
681 pci_write_config_qword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
682 MC_CHANNEL_ADDR_MATCH
, mask
);
684 pci_write_config_dword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
685 MC_CHANNEL_ADDR_MATCH
, mask
);
686 pci_write_config_dword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
687 MC_CHANNEL_ADDR_MATCH
+ 4, mask
>> 32L);
693 pci_read_config_qword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
694 MC_CHANNEL_ADDR_MATCH
, &rdmask
);
695 debugf0("Inject addr match write 0x%016llx, read: 0x%016llx\n",
698 u32 rdmask1
, rdmask2
;
700 pci_read_config_dword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
701 MC_CHANNEL_ADDR_MATCH
, &rdmask1
);
702 pci_read_config_dword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
703 MC_CHANNEL_ADDR_MATCH
+ 4, &rdmask2
);
705 debugf0("Inject addr match write 0x%016llx, read: 0x%08x%08x\n",
706 mask
, rdmask1
, rdmask2
);
710 pci_write_config_dword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
711 MC_CHANNEL_ERROR_MASK
, pvt
->inject
.eccmask
);
715 * bits 1-2: MASK_HALF_CACHELINE
717 * bit 4: INJECT_ADDR_PARITY
720 injectmask
= (pvt
->inject
.type
& 1) |
721 (pvt
->inject
.section
& 0x3) << 1 |
722 (pvt
->inject
.type
& 0x6) << (3 - 1);
724 pci_write_config_dword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
725 MC_CHANNEL_ERROR_MASK
, injectmask
);
727 debugf0("Error inject addr match 0x%016llx, ecc 0x%08x, inject 0x%08x\n",
728 mask
, pvt
->inject
.eccmask
, injectmask
);
735 static ssize_t
i7core_inject_enable_show(struct mem_ctl_info
*mci
,
738 struct i7core_pvt
*pvt
= mci
->pvt_info
;
741 pci_read_config_dword(pvt
->pci_ch
[pvt
->inject
.channel
][0],
742 MC_CHANNEL_ERROR_MASK
, &injectmask
);
744 debugf0("Inject error read: 0x%018x\n", injectmask
);
746 if (injectmask
& 0x0c)
747 pvt
->inject
.enable
= 1;
749 return sprintf(data
, "%d\n", pvt
->inject
.enable
);
755 static struct mcidev_sysfs_attribute i7core_inj_attrs
[] = {
759 .name
= "inject_section",
760 .mode
= (S_IRUGO
| S_IWUSR
)
762 .show
= i7core_inject_section_show
,
763 .store
= i7core_inject_section_store
,
766 .name
= "inject_type",
767 .mode
= (S_IRUGO
| S_IWUSR
)
769 .show
= i7core_inject_type_show
,
770 .store
= i7core_inject_type_store
,
773 .name
= "inject_eccmask",
774 .mode
= (S_IRUGO
| S_IWUSR
)
776 .show
= i7core_inject_eccmask_show
,
777 .store
= i7core_inject_eccmask_store
,
780 .name
= "inject_addrmatch",
781 .mode
= (S_IRUGO
| S_IWUSR
)
783 .show
= i7core_inject_addrmatch_show
,
784 .store
= i7core_inject_addrmatch_store
,
787 .name
= "inject_enable",
788 .mode
= (S_IRUGO
| S_IWUSR
)
790 .show
= i7core_inject_enable_show
,
791 .store
= i7core_inject_enable_store
,
795 /****************************************************************************
796 Device initialization routines: put/get, init/exit
797 ****************************************************************************/
800 * i7core_put_devices 'put' all the devices that we have
803 static void i7core_put_devices(void)
807 for (i
= 0; i
< N_DEVS
; i
++)
808 pci_dev_put(pci_devs
[i
].pdev
);
812 * i7core_get_devices Find and perform 'get' operation on the MCH's
813 * device/functions we want to reference for this driver
815 * Need to 'get' device 16 func 1 and func 2
817 static int i7core_get_devices(struct mem_ctl_info
*mci
, struct pci_dev
*mcidev
)
819 struct i7core_pvt
*pvt
= mci
->pvt_info
;
821 struct pci_dev
*pdev
= NULL
;
824 memset(pvt
, 0, sizeof(*pvt
));
826 for (i
= 0; i
< N_DEVS
; i
++) {
827 pdev
= pci_get_device(PCI_VENDOR_ID_INTEL
,
828 pci_devs
[i
].dev_id
, NULL
);
830 /* End of list, leave */
831 i7core_printk(KERN_ERR
,
832 "Device not found: PCI ID %04x:%04x "
833 "(dev %d, func %d)\n",
834 PCI_VENDOR_ID_INTEL
, pci_devs
[i
].dev_id
,
835 pci_devs
[i
].dev
,pci_devs
[i
].func
);
836 if ((pci_devs
[i
].dev
== 3) && (pci_devs
[i
].func
== 2))
837 continue; /* Only on chips with RDIMMs */
839 i7core_put_devices();
841 pci_devs
[i
].pdev
= pdev
;
843 rc
= pci_enable_device(pdev
);
845 i7core_printk(KERN_ERR
,
846 "Couldn't enable PCI ID %04x:%04x "
847 "(dev %d, func %d)\n",
848 PCI_VENDOR_ID_INTEL
, pci_devs
[i
].dev_id
,
849 pci_devs
[i
].dev
, pci_devs
[i
].func
);
850 i7core_put_devices();
854 if (PCI_FUNC(pdev
->devfn
) != pci_devs
[i
].func
) {
855 i7core_printk(KERN_ERR
,
856 "Device PCI ID %04x:%04x "
857 "has function %d instead of %d\n",
858 PCI_VENDOR_ID_INTEL
, pci_devs
[i
].dev_id
,
859 PCI_FUNC(pdev
->devfn
), pci_devs
[i
].func
);
860 i7core_put_devices();
864 i7core_printk(KERN_INFO
,
865 "Registered device %0x:%0x fn=%0x %0x\n",
866 PCI_VENDOR_ID_INTEL
, pci_devs
[i
].dev_id
,
867 PCI_SLOT(pdev
->devfn
), PCI_FUNC(pdev
->devfn
));
869 func
= PCI_FUNC(pdev
->devfn
);
870 if (pci_devs
[i
].dev
< 4) {
871 pvt
->pci_mcr
[func
] = pdev
;
873 pvt
->pci_ch
[pci_devs
[i
].dev
- 4][func
] = pdev
;
877 i7core_printk(KERN_INFO
, "Driver loaded.\n");
883 * i7core_check_error Retrieve and process errors reported by the
884 * hardware. Called by the Core module.
886 static void i7core_check_error(struct mem_ctl_info
*mci
)
888 /* FIXME: need a real code here */
892 * i7core_probe Probe for ONE instance of device to see if it is
895 * 0 for FOUND a device
898 static int __devinit
i7core_probe(struct pci_dev
*pdev
,
899 const struct pci_device_id
*id
)
901 struct mem_ctl_info
*mci
;
902 struct i7core_pvt
*pvt
;
905 int num_dimms_per_channel
;
906 int dev_idx
= id
->driver_data
;
908 if (dev_idx
>= ARRAY_SIZE(i7core_devs
))
911 num_channels
= NUM_CHANS
;
913 /* FIXME: FAKE data, since we currently don't now how to get this */
914 num_dimms_per_channel
= 4;
915 num_csrows
= num_dimms_per_channel
;
917 /* allocate a new MC control structure */
918 mci
= edac_mc_alloc(sizeof(*pvt
), num_csrows
, num_channels
, 0);
922 debugf0("MC: " __FILE__
": %s(): mci = %p\n", __func__
, mci
);
924 /* 'get' the pci devices we want to reserve for our use */
925 if (i7core_get_devices(mci
, pdev
))
928 mci
->dev
= &pdev
->dev
; /* record ptr to the generic device */
932 // pvt->system_address = pdev; /* Record this device in our private */
933 // pvt->maxch = num_channels;
934 // pvt->maxdimmperch = num_dimms_per_channel;
937 mci
->mtype_cap
= MEM_FLAG_FB_DDR2
; /* FIXME: it uses DDR3 */
938 mci
->edac_ctl_cap
= EDAC_FLAG_NONE
;
939 mci
->edac_cap
= EDAC_FLAG_NONE
;
940 mci
->mod_name
= "i7core_edac.c";
941 mci
->mod_ver
= I7CORE_REVISION
;
942 mci
->ctl_name
= i7core_devs
[dev_idx
].ctl_name
;
943 mci
->dev_name
= pci_name(pdev
);
944 mci
->ctl_page_to_phys
= NULL
;
945 mci
->mc_driver_sysfs_attributes
= i7core_inj_attrs
;
947 /* Set the function pointer to an actual operation function */
948 mci
->edac_check
= i7core_check_error
;
950 /* add this new MC control structure to EDAC's list of MCs */
951 if (edac_mc_add_mc(mci
)) {
952 debugf0("MC: " __FILE__
953 ": %s(): failed edac_mc_add_mc()\n", __func__
);
954 /* FIXME: perhaps some code should go here that disables error
955 * reporting if we just enabled it
960 /* allocating generic PCI control info */
961 i7core_pci
= edac_pci_create_generic_ctl(&pdev
->dev
, EDAC_MOD_STR
);
964 "%s(): Unable to create PCI control\n",
967 "%s(): PCI error report via EDAC not setup\n",
971 /* Default error mask is any memory */
972 pvt
->inject
.channel
= -1;
973 pvt
->inject
.dimm
= -1;
974 pvt
->inject
.rank
= -1;
975 pvt
->inject
.bank
= -1;
976 pvt
->inject
.page
= -1;
977 pvt
->inject
.col
= -1;
979 /* Get dimm basic config */
980 get_dimm_config(mci
);
985 i7core_put_devices();
993 * i7core_remove destructor for one instance of device
996 static void __devexit
i7core_remove(struct pci_dev
*pdev
)
998 struct mem_ctl_info
*mci
;
1000 debugf0(__FILE__
": %s()\n", __func__
);
1003 edac_pci_release_generic_ctl(i7core_pci
);
1005 mci
= edac_mc_del_mc(&pdev
->dev
);
1010 /* retrieve references to resources, and free those resources */
1011 i7core_put_devices();
1016 MODULE_DEVICE_TABLE(pci
, i7core_pci_tbl
);
1019 * i7core_driver pci_driver structure for this module
1022 static struct pci_driver i7core_driver
= {
1023 .name
= "i7core_edac",
1024 .probe
= i7core_probe
,
1025 .remove
= __devexit_p(i7core_remove
),
1026 .id_table
= i7core_pci_tbl
,
1030 * i7core_init Module entry function
1031 * Try to initialize this module for its devices
1033 static int __init
i7core_init(void)
1037 debugf2("MC: " __FILE__
": %s()\n", __func__
);
1039 /* Ensure that the OPSTATE is set correctly for POLL or NMI */
1042 pci_rc
= pci_register_driver(&i7core_driver
);
1044 return (pci_rc
< 0) ? pci_rc
: 0;
1048 * i7core_exit() Module exit function
1049 * Unregister the driver
1051 static void __exit
i7core_exit(void)
1053 debugf2("MC: " __FILE__
": %s()\n", __func__
);
1054 pci_unregister_driver(&i7core_driver
);
1057 module_init(i7core_init
);
1058 module_exit(i7core_exit
);
1060 MODULE_LICENSE("GPL");
1061 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
1062 MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
1063 MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
1066 module_param(edac_op_state
, int, 0444);
1067 MODULE_PARM_DESC(edac_op_state
, "EDAC Error Reporting state: 0=Poll,1=NMI");