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