i7core_edac: Show read/write virtual/physical channel association
[pandora-kernel.git] / drivers / edac / i7core_edac.c
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
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_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
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
75 #define MC_CHANNEL_RANK_PRESENT 0x7c
76   #define RANK_PRESENT_MASK             0xffff
77
78 #define MC_CHANNEL_ADDR_MATCH   0xf0
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
89
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
107 #define MC_RANK_PRESENT         0x7c
108
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
132 /*
133  * i7core structs
134  */
135
136 #define NUM_CHANS 3
137 #define NUM_MCR_FUNCS  4
138 #define NUM_CHAN_FUNCS 3
139
140 struct i7core_info {
141         u32     mc_control;
142         u32     mc_status;
143         u32     max_dod;
144         u32     ch_map;
145 };
146
147
148 struct 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
159 struct i7core_channel {
160         u32 ranks;
161         u32 dimms;
162 };
163
164 struct pci_id_descr {
165         int             dev;
166         int             func;
167         int             dev_id;
168         struct pci_dev  *pdev;
169 };
170
171 struct i7core_pvt {
172         struct pci_dev          *pci_mcr[NUM_MCR_FUNCS];
173         struct pci_dev          *pci_ch[NUM_CHANS][NUM_CHAN_FUNCS];
174         struct i7core_info      info;
175         struct i7core_inject    inject;
176         struct i7core_channel   channel[NUM_CHANS];
177 };
178
179 /* Device name and register DID (Device ID) */
180 struct i7core_dev_info {
181         const char *ctl_name;   /* name for this device */
182         u16 fsb_mapping_errors; /* DID for the branchmap,control */
183 };
184
185 #define PCI_DESCR(device, function, device_id)  \
186         .dev = (device),                        \
187         .func = (function),                     \
188         .dev_id = (device_id)
189
190 struct 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)   },
214 };
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  */
221 static 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
226
227 /* Table of devices attributes supported by this driver */
228 static 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
235 static struct edac_pci_ctl_info *i7core_pci;
236
237 /****************************************************************************
238                         Anciliary status routines
239  ****************************************************************************/
240
241         /* MC_CONTROL bits */
242 #define CH_ACTIVE(pvt, ch)      ((pvt)->info.mc_control & 1 << (8 + ch))
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)
247 #define CH_DISABLED(pvt, ch)    ((pvt)->info.mc_status & 1 << ch)
248
249         /* MC_MAX_DOD read functions */
250 static inline int maxnumdimms(struct i7core_pvt *pvt)
251 {
252         return (pvt->info.max_dod & 0x3) + 1;
253 }
254
255 static 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
262 static 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
269 static 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
279 static 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
287
288 /****************************************************************************
289                         Memory check routines
290  ****************************************************************************/
291 static int get_dimm_config(struct mem_ctl_info *mci)
292 {
293         struct i7core_pvt *pvt = mci->pvt_info;
294         int i;
295
296         if (!pvt->pci_mcr[0])
297                 return -ENODEV;
298
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);
312
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
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
338                 /* Devices 4-6 function 0 */
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
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),
356                         pvt->channel[i].ranks, pvt->channel[i].dimms,
357                         (data & REGISTERED_DIMM)? 'R' : 'U' );
358         }
359
360         return 0;
361 }
362
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  */
374 static int disable_inject(struct mem_ctl_info *mci)
375 {
376         struct i7core_pvt *pvt = mci->pvt_info;
377
378         pvt->inject.enable = 0;
379
380         if (!pvt->pci_ch[pvt->inject.channel][0])
381                 return -ENODEV;
382
383         pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
384                                 MC_CHANNEL_ERROR_MASK, 0);
385
386         return 0;
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  */
396 static 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
414 static 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  */
429 static 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
447 static 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  */
464 static 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
482 static 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  */
499 static 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
563 static 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  */
617 static 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
626         if (!pvt->pci_ch[pvt->inject.channel][0])
627                 return 0;
628
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 {
644                 if (pvt->channel[pvt->inject.channel].dimms > 2)
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 {
654                 if (pvt->channel[pvt->inject.channel].dimms > 2)
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
705 static 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  */
715 static 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
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  */
763 static void i7core_put_devices(void)
764 {
765         int i;
766
767         for (i = 0; i < N_DEVS; i++)
768                 pci_dev_put(pci_devs[i].pdev);
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  */
777 static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev)
778 {
779         struct i7core_pvt *pvt = mci->pvt_info;
780         int rc, i,func;
781         struct pci_dev *pdev = NULL;
782
783         pvt = mci->pvt_info;
784         memset(pvt, 0, sizeof(*pvt));
785
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                 }
823
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;
834                 }
835         }
836
837         i7core_printk(KERN_INFO, "Driver loaded.\n");
838
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  */
849 static 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;
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
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
875         mci->dev = &pdev->dev;  /* record ptr to the generic device */
876         dev_set_drvdata(mci->dev, mci);
877
878         pvt = mci->pvt_info;
879
880 //      pvt->system_address = pdev;     /* Record this device in our private */
881 //      pvt->maxch = num_channels;
882 //      pvt->maxdimmperch = num_dimms_per_channel;
883
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;
893         mci->mc_driver_sysfs_attributes = i7core_inj_attrs;
894
895         /* 'get' the pci devices we want to reserve for our use */
896         if (i7core_get_devices(mci, pdev))
897                 goto fail0;
898
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
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
928         /* Get dimm basic config */
929         get_dimm_config(mci);
930
931         return 0;
932
933 fail1:
934         i7core_put_devices();
935
936 fail0:
937         edac_mc_free(mci);
938         return -ENODEV;
939 }
940
941 /*
942  *      i7core_remove   destructor for one instance of device
943  *
944  */
945 static 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 */
959         i7core_put_devices();
960
961         edac_mc_free(mci);
962 }
963
964 MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);
965
966 /*
967  *      i7core_driver   pci_driver structure for this module
968  *
969  */
970 static 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  */
981 static 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  */
999 static void __exit i7core_exit(void)
1000 {
1001         debugf2("MC: " __FILE__ ": %s()\n", __func__);
1002         pci_unregister_driver(&i7core_driver);
1003 }
1004
1005 module_init(i7core_init);
1006 module_exit(i7core_exit);
1007
1008 MODULE_LICENSE("GPL");
1009 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
1010 MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
1011 MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
1012                    I7CORE_REVISION);
1013
1014 module_param(edac_op_state, int, 0444);
1015 MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");