aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/e7xxx_edac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac/e7xxx_edac.c')
-rw-r--r--drivers/edac/e7xxx_edac.c86
1 files changed, 58 insertions, 28 deletions
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 68dea87b72e6..9a9c1a546797 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -10,6 +10,9 @@
10 * Based on work by Dan Hollis <goemon at anime dot net> and others. 10 * Based on work by Dan Hollis <goemon at anime dot net> and others.
11 * http://www.anime.net/~goemon/linux-ecc/ 11 * http://www.anime.net/~goemon/linux-ecc/
12 * 12 *
13 * Datasheet:
14 * http://www.intel.com/content/www/us/en/chipsets/e7501-chipset-memory-controller-hub-datasheet.html
15 *
13 * Contributors: 16 * Contributors:
14 * Eric Biederman (Linux Networx) 17 * Eric Biederman (Linux Networx)
15 * Tom Zimmerman (Linux Networx) 18 * Tom Zimmerman (Linux Networx)
@@ -71,7 +74,7 @@
71#endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */ 74#endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */
72 75
73#define E7XXX_NR_CSROWS 8 /* number of csrows */ 76#define E7XXX_NR_CSROWS 8 /* number of csrows */
74#define E7XXX_NR_DIMMS 8 /* FIXME - is this correct? */ 77#define E7XXX_NR_DIMMS 8 /* 2 channels, 4 dimms/channel */
75 78
76/* E7XXX register addresses - device 0 function 0 */ 79/* E7XXX register addresses - device 0 function 0 */
77#define E7XXX_DRB 0x60 /* DRAM row boundary register (8b) */ 80#define E7XXX_DRB 0x60 /* DRAM row boundary register (8b) */
@@ -216,13 +219,15 @@ static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
216 row = edac_mc_find_csrow_by_page(mci, page); 219 row = edac_mc_find_csrow_by_page(mci, page);
217 /* convert syndrome to channel */ 220 /* convert syndrome to channel */
218 channel = e7xxx_find_channel(syndrome); 221 channel = e7xxx_find_channel(syndrome);
219 edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, "e7xxx CE"); 222 edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, page, 0, syndrome,
223 row, channel, -1, "e7xxx CE", "", NULL);
220} 224}
221 225
222static void process_ce_no_info(struct mem_ctl_info *mci) 226static void process_ce_no_info(struct mem_ctl_info *mci)
223{ 227{
224 debugf3("%s()\n", __func__); 228 debugf3("%s()\n", __func__);
225 edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow"); 229 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1,
230 "e7xxx CE log register overflow", "", NULL);
226} 231}
227 232
228static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info) 233static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
@@ -236,13 +241,17 @@ static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
236 /* FIXME - should use PAGE_SHIFT */ 241 /* FIXME - should use PAGE_SHIFT */
237 block_page = error_2b >> 6; /* convert to 4k address */ 242 block_page = error_2b >> 6; /* convert to 4k address */
238 row = edac_mc_find_csrow_by_page(mci, block_page); 243 row = edac_mc_find_csrow_by_page(mci, block_page);
239 edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE"); 244
245 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, block_page, 0, 0,
246 row, -1, -1, "e7xxx UE", "", NULL);
240} 247}
241 248
242static void process_ue_no_info(struct mem_ctl_info *mci) 249static void process_ue_no_info(struct mem_ctl_info *mci)
243{ 250{
244 debugf3("%s()\n", __func__); 251 debugf3("%s()\n", __func__);
245 edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow"); 252
253 edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1,
254 "e7xxx UE log register overflow", "", NULL);
246} 255}
247 256
248static void e7xxx_get_error_info(struct mem_ctl_info *mci, 257static void e7xxx_get_error_info(struct mem_ctl_info *mci,
@@ -347,11 +356,12 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
347 int dev_idx, u32 drc) 356 int dev_idx, u32 drc)
348{ 357{
349 unsigned long last_cumul_size; 358 unsigned long last_cumul_size;
350 int index; 359 int index, j;
351 u8 value; 360 u8 value;
352 u32 dra, cumul_size; 361 u32 dra, cumul_size, nr_pages;
353 int drc_chan, drc_drbg, drc_ddim, mem_dev; 362 int drc_chan, drc_drbg, drc_ddim, mem_dev;
354 struct csrow_info *csrow; 363 struct csrow_info *csrow;
364 struct dimm_info *dimm;
355 365
356 pci_read_config_dword(pdev, E7XXX_DRA, &dra); 366 pci_read_config_dword(pdev, E7XXX_DRA, &dra);
357 drc_chan = dual_channel_active(drc, dev_idx); 367 drc_chan = dual_channel_active(drc, dev_idx);
@@ -379,26 +389,32 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
379 389
380 csrow->first_page = last_cumul_size; 390 csrow->first_page = last_cumul_size;
381 csrow->last_page = cumul_size - 1; 391 csrow->last_page = cumul_size - 1;
382 csrow->nr_pages = cumul_size - last_cumul_size; 392 nr_pages = cumul_size - last_cumul_size;
383 last_cumul_size = cumul_size; 393 last_cumul_size = cumul_size;
384 csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ 394
385 csrow->mtype = MEM_RDDR; /* only one type supported */ 395 for (j = 0; j < drc_chan + 1; j++) {
386 csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; 396 dimm = csrow->channels[j].dimm;
387 397
388 /* 398 dimm->nr_pages = nr_pages / (drc_chan + 1);
389 * if single channel or x8 devices then SECDED 399 dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */
390 * if dual channel and x4 then S4ECD4ED 400 dimm->mtype = MEM_RDDR; /* only one type supported */
391 */ 401 dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
392 if (drc_ddim) { 402
393 if (drc_chan && mem_dev) { 403 /*
394 csrow->edac_mode = EDAC_S4ECD4ED; 404 * if single channel or x8 devices then SECDED
395 mci->edac_cap |= EDAC_FLAG_S4ECD4ED; 405 * if dual channel and x4 then S4ECD4ED
396 } else { 406 */
397 csrow->edac_mode = EDAC_SECDED; 407 if (drc_ddim) {
398 mci->edac_cap |= EDAC_FLAG_SECDED; 408 if (drc_chan && mem_dev) {
399 } 409 dimm->edac_mode = EDAC_S4ECD4ED;
400 } else 410 mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
401 csrow->edac_mode = EDAC_NONE; 411 } else {
412 dimm->edac_mode = EDAC_SECDED;
413 mci->edac_cap |= EDAC_FLAG_SECDED;
414 }
415 } else
416 dimm->edac_mode = EDAC_NONE;
417 }
402 } 418 }
403} 419}
404 420
@@ -406,6 +422,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
406{ 422{
407 u16 pci_data; 423 u16 pci_data;
408 struct mem_ctl_info *mci = NULL; 424 struct mem_ctl_info *mci = NULL;
425 struct edac_mc_layer layers[2];
409 struct e7xxx_pvt *pvt = NULL; 426 struct e7xxx_pvt *pvt = NULL;
410 u32 drc; 427 u32 drc;
411 int drc_chan; 428 int drc_chan;
@@ -416,8 +433,21 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
416 pci_read_config_dword(pdev, E7XXX_DRC, &drc); 433 pci_read_config_dword(pdev, E7XXX_DRC, &drc);
417 434
418 drc_chan = dual_channel_active(drc, dev_idx); 435 drc_chan = dual_channel_active(drc, dev_idx);
419 mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1, 0); 436 /*
420 437 * According with the datasheet, this device has a maximum of
438 * 4 DIMMS per channel, either single-rank or dual-rank. So, the
439 * total amount of dimms is 8 (E7XXX_NR_DIMMS).
440 * That means that the DIMM is mapped as CSROWs, and the channel
441 * will map the rank. So, an error to either channel should be
442 * attributed to the same dimm.
443 */
444 layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
445 layers[0].size = E7XXX_NR_CSROWS;
446 layers[0].is_virt_csrow = true;
447 layers[1].type = EDAC_MC_LAYER_CHANNEL;
448 layers[1].size = drc_chan + 1;
449 layers[1].is_virt_csrow = false;
450 mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
421 if (mci == NULL) 451 if (mci == NULL)
422 return -ENOMEM; 452 return -ENOMEM;
423 453