diff options
Diffstat (limited to 'drivers/edac/e7xxx_edac.c')
-rw-r--r-- | drivers/edac/e7xxx_edac.c | 158 |
1 files changed, 82 insertions, 76 deletions
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 1e282c843e77..9878379b4993 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c | |||
@@ -335,99 +335,61 @@ static void e7xxx_check(struct mem_ctl_info *mci) | |||
335 | e7xxx_process_error_info(mci, &info, 1); | 335 | e7xxx_process_error_info(mci, &info, 1); |
336 | } | 336 | } |
337 | 337 | ||
338 | static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | 338 | /* Return 1 if dual channel mode is active. Else return 0. */ |
339 | static inline int dual_channel_active(u32 drc, int dev_idx) | ||
339 | { | 340 | { |
340 | int rc = -ENODEV; | 341 | return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1; |
341 | int index; | 342 | } |
342 | u16 pci_data; | ||
343 | struct mem_ctl_info *mci = NULL; | ||
344 | struct e7xxx_pvt *pvt = NULL; | ||
345 | u32 drc; | ||
346 | int drc_chan = 1; /* Number of channels 0=1chan,1=2chan */ | ||
347 | int drc_drbg = 1; /* DRB granularity 0=32mb,1=64mb */ | ||
348 | int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ | ||
349 | u32 dra; | ||
350 | unsigned long last_cumul_size; | ||
351 | struct e7xxx_error_info discard; | ||
352 | |||
353 | debugf0("%s(): mci\n", __func__); | ||
354 | 343 | ||
355 | /* need to find out the number of channels */ | ||
356 | pci_read_config_dword(pdev, E7XXX_DRC, &drc); | ||
357 | 344 | ||
345 | /* Return DRB granularity (0=32mb, 1=64mb). */ | ||
346 | static inline int drb_granularity(u32 drc, int dev_idx) | ||
347 | { | ||
358 | /* only e7501 can be single channel */ | 348 | /* only e7501 can be single channel */ |
359 | if (dev_idx == E7501) { | 349 | return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1; |
360 | drc_chan = ((drc >> 22) & 0x1); | 350 | } |
361 | drc_drbg = (drc >> 18) & 0x3; | ||
362 | } | ||
363 | |||
364 | drc_ddim = (drc >> 20) & 0x3; | ||
365 | mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1); | ||
366 | |||
367 | if (mci == NULL) { | ||
368 | rc = -ENOMEM; | ||
369 | goto fail; | ||
370 | } | ||
371 | |||
372 | debugf3("%s(): init mci\n", __func__); | ||
373 | mci->mtype_cap = MEM_FLAG_RDDR; | ||
374 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | | ||
375 | EDAC_FLAG_S4ECD4ED; | ||
376 | /* FIXME - what if different memory types are in different csrows? */ | ||
377 | mci->mod_name = EDAC_MOD_STR; | ||
378 | mci->mod_ver = E7XXX_REVISION; | ||
379 | mci->dev = &pdev->dev; | ||
380 | |||
381 | debugf3("%s(): init pvt\n", __func__); | ||
382 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | ||
383 | pvt->dev_info = &e7xxx_devs[dev_idx]; | ||
384 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
385 | pvt->dev_info->err_dev, | ||
386 | pvt->bridge_ck); | ||
387 | 351 | ||
388 | if (!pvt->bridge_ck) { | ||
389 | e7xxx_printk(KERN_ERR, "error reporting device not found:" | ||
390 | "vendor %x device 0x%x (broken BIOS?)\n", | ||
391 | PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev); | ||
392 | goto fail; | ||
393 | } | ||
394 | 352 | ||
395 | debugf3("%s(): more mci init\n", __func__); | 353 | static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, |
396 | mci->ctl_name = pvt->dev_info->ctl_name; | 354 | int dev_idx, u32 drc) |
397 | mci->edac_check = e7xxx_check; | 355 | { |
398 | mci->ctl_page_to_phys = ctl_page_to_phys; | 356 | unsigned long last_cumul_size; |
357 | int index; | ||
358 | u8 value; | ||
359 | u32 dra, cumul_size; | ||
360 | int drc_chan, drc_drbg, drc_ddim, mem_dev; | ||
361 | struct csrow_info *csrow; | ||
399 | 362 | ||
400 | /* find out the device types */ | ||
401 | pci_read_config_dword(pdev, E7XXX_DRA, &dra); | 363 | pci_read_config_dword(pdev, E7XXX_DRA, &dra); |
364 | drc_chan = dual_channel_active(drc, dev_idx); | ||
365 | drc_drbg = drb_granularity(drc, dev_idx); | ||
366 | drc_ddim = (drc >> 20) & 0x3; | ||
367 | last_cumul_size = 0; | ||
402 | 368 | ||
403 | /* | 369 | /* The dram row boundary (DRB) reg values are boundary address |
404 | * The dram row boundary (DRB) reg values are boundary address | ||
405 | * for each DRAM row with a granularity of 32 or 64MB (single/dual | 370 | * for each DRAM row with a granularity of 32 or 64MB (single/dual |
406 | * channel operation). DRB regs are cumulative; therefore DRB7 will | 371 | * channel operation). DRB regs are cumulative; therefore DRB7 will |
407 | * contain the total memory contained in all eight rows. | 372 | * contain the total memory contained in all eight rows. |
408 | */ | 373 | */ |
409 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { | 374 | for (index = 0; index < mci->nr_csrows; index++) { |
410 | u8 value; | ||
411 | u32 cumul_size; | ||
412 | /* mem_dev 0=x8, 1=x4 */ | 375 | /* mem_dev 0=x8, 1=x4 */ |
413 | int mem_dev = (dra >> (index * 4 + 3)) & 0x1; | 376 | mem_dev = (dra >> (index * 4 + 3)) & 0x1; |
414 | struct csrow_info *csrow = &mci->csrows[index]; | 377 | csrow = &mci->csrows[index]; |
415 | 378 | ||
416 | pci_read_config_byte(pdev, E7XXX_DRB + index, &value); | 379 | pci_read_config_byte(pdev, E7XXX_DRB + index, &value); |
417 | /* convert a 64 or 32 MiB DRB to a page size. */ | 380 | /* convert a 64 or 32 MiB DRB to a page size. */ |
418 | cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); | 381 | cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); |
419 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, | 382 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, |
420 | cumul_size); | 383 | cumul_size); |
421 | |||
422 | if (cumul_size == last_cumul_size) | 384 | if (cumul_size == last_cumul_size) |
423 | continue; /* not populated */ | 385 | continue; /* not populated */ |
424 | 386 | ||
425 | csrow->first_page = last_cumul_size; | 387 | csrow->first_page = last_cumul_size; |
426 | csrow->last_page = cumul_size - 1; | 388 | csrow->last_page = cumul_size - 1; |
427 | csrow->nr_pages = cumul_size - last_cumul_size; | 389 | csrow->nr_pages = cumul_size - last_cumul_size; |
428 | last_cumul_size = cumul_size; | 390 | last_cumul_size = cumul_size; |
429 | csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ | 391 | csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ |
430 | csrow->mtype = MEM_RDDR; /* only one type supported */ | 392 | csrow->mtype = MEM_RDDR; /* only one type supported */ |
431 | csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; | 393 | csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; |
432 | 394 | ||
433 | /* | 395 | /* |
@@ -445,9 +407,54 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
445 | } else | 407 | } else |
446 | csrow->edac_mode = EDAC_NONE; | 408 | csrow->edac_mode = EDAC_NONE; |
447 | } | 409 | } |
410 | } | ||
448 | 411 | ||
449 | mci->edac_cap |= EDAC_FLAG_NONE; | 412 | static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) |
413 | { | ||
414 | u16 pci_data; | ||
415 | struct mem_ctl_info *mci = NULL; | ||
416 | struct e7xxx_pvt *pvt = NULL; | ||
417 | u32 drc; | ||
418 | int drc_chan; | ||
419 | struct e7xxx_error_info discard; | ||
420 | |||
421 | debugf0("%s(): mci\n", __func__); | ||
422 | pci_read_config_dword(pdev, E7XXX_DRC, &drc); | ||
423 | |||
424 | drc_chan = dual_channel_active(drc, dev_idx); | ||
425 | mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1); | ||
426 | |||
427 | if (mci == NULL) | ||
428 | return -ENOMEM; | ||
450 | 429 | ||
430 | debugf3("%s(): init mci\n", __func__); | ||
431 | mci->mtype_cap = MEM_FLAG_RDDR; | ||
432 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | | ||
433 | EDAC_FLAG_S4ECD4ED; | ||
434 | /* FIXME - what if different memory types are in different csrows? */ | ||
435 | mci->mod_name = EDAC_MOD_STR; | ||
436 | mci->mod_ver = E7XXX_REVISION; | ||
437 | mci->dev = &pdev->dev; | ||
438 | debugf3("%s(): init pvt\n", __func__); | ||
439 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | ||
440 | pvt->dev_info = &e7xxx_devs[dev_idx]; | ||
441 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
442 | pvt->dev_info->err_dev, | ||
443 | pvt->bridge_ck); | ||
444 | |||
445 | if (!pvt->bridge_ck) { | ||
446 | e7xxx_printk(KERN_ERR, "error reporting device not found:" | ||
447 | "vendor %x device 0x%x (broken BIOS?)\n", | ||
448 | PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev); | ||
449 | goto fail0; | ||
450 | } | ||
451 | |||
452 | debugf3("%s(): more mci init\n", __func__); | ||
453 | mci->ctl_name = pvt->dev_info->ctl_name; | ||
454 | mci->edac_check = e7xxx_check; | ||
455 | mci->ctl_page_to_phys = ctl_page_to_phys; | ||
456 | e7xxx_init_csrows(mci, pdev, dev_idx, drc); | ||
457 | mci->edac_cap |= EDAC_FLAG_NONE; | ||
451 | debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); | 458 | debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); |
452 | /* load the top of low memory, remap base, and remap limit vars */ | 459 | /* load the top of low memory, remap base, and remap limit vars */ |
453 | pci_read_config_word(pdev, E7XXX_TOLM, &pci_data); | 460 | pci_read_config_word(pdev, E7XXX_TOLM, &pci_data); |
@@ -468,21 +475,20 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
468 | */ | 475 | */ |
469 | if (edac_mc_add_mc(mci,0)) { | 476 | if (edac_mc_add_mc(mci,0)) { |
470 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); | 477 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
471 | goto fail; | 478 | goto fail1; |
472 | } | 479 | } |
473 | 480 | ||
474 | /* get this far and it's successful */ | 481 | /* get this far and it's successful */ |
475 | debugf3("%s(): success\n", __func__); | 482 | debugf3("%s(): success\n", __func__); |
476 | return 0; | 483 | return 0; |
477 | 484 | ||
478 | fail: | 485 | fail1: |
479 | if (mci != NULL) { | 486 | pci_dev_put(pvt->bridge_ck); |
480 | if(pvt != NULL && pvt->bridge_ck) | 487 | |
481 | pci_dev_put(pvt->bridge_ck); | 488 | fail0: |
482 | edac_mc_free(mci); | 489 | edac_mc_free(mci); |
483 | } | ||
484 | 490 | ||
485 | return rc; | 491 | return -ENODEV; |
486 | } | 492 | } |
487 | 493 | ||
488 | /* returns count (>= 0), or negative on error */ | 494 | /* returns count (>= 0), or negative on error */ |