diff options
Diffstat (limited to 'drivers/edac/r82600_edac.c')
-rw-r--r-- | drivers/edac/r82600_edac.c | 142 |
1 files changed, 77 insertions, 65 deletions
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index 2c29faf..fecdb2c 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -23,6 +23,8 @@ #include <linux/slab.h> #include "edac_mc.h" +#define R82600_REVISION " Ver: 2.0.0 " __DATE__ + #define r82600_printk(level, fmt, arg...) \ edac_printk(level, "r82600", fmt, ##arg) @@ -134,17 +136,20 @@ static unsigned int disable_hardware_scrub = 0; static void r82600_get_error_info (struct mem_ctl_info *mci, struct r82600_error_info *info) { - pci_read_config_dword(mci->pdev, R82600_EAP, &info->eapr); + struct pci_dev *pdev; + + pdev = to_pci_dev(mci->dev); + pci_read_config_dword(pdev, R82600_EAP, &info->eapr); if (info->eapr & BIT(0)) /* Clear error to allow next error to be reported [p.62] */ - pci_write_bits32(mci->pdev, R82600_EAP, + pci_write_bits32(pdev, R82600_EAP, ((u32) BIT(0) & (u32) BIT(1)), ((u32) BIT(0) & (u32) BIT(1))); if (info->eapr & BIT(1)) /* Clear error to allow next error to be reported [p.62] */ - pci_write_bits32(mci->pdev, R82600_EAP, + pci_write_bits32(pdev, R82600_EAP, ((u32) BIT(0) & (u32) BIT(1)), ((u32) BIT(0) & (u32) BIT(1))); } @@ -200,25 +205,72 @@ static void r82600_check(struct mem_ctl_info *mci) r82600_process_error_info(mci, &info, 1); } -static int r82600_probe1(struct pci_dev *pdev, int dev_idx) +static inline int ecc_enabled(u8 dramcr) +{ + return dramcr & BIT(5); +} + +static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, + u8 dramcr) { - int rc = -ENODEV; + struct csrow_info *csrow; int index; - struct mem_ctl_info *mci = NULL; + u8 drbar; /* SDRAM Row Boundry Address Register */ + u32 row_high_limit, row_high_limit_last; + u32 reg_sdram, ecc_on, row_base; + + ecc_on = ecc_enabled(dramcr); + reg_sdram = dramcr & BIT(4); + row_high_limit_last = 0; + + for (index = 0; index < mci->nr_csrows; index++) { + csrow = &mci->csrows[index]; + + /* find the DRAM Chip Select Base address and mask */ + pci_read_config_byte(pdev, R82600_DRBA + index, &drbar); + + debugf1("%s() Row=%d DRBA = %#0x\n", __func__, index, drbar); + + row_high_limit = ((u32) drbar << 24); +/* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ + + debugf1("%s() Row=%d, Boundry Address=%#0x, Last = %#0x\n", + __func__, index, row_high_limit, row_high_limit_last); + + /* Empty row [p.57] */ + if (row_high_limit == row_high_limit_last) + continue; + + row_base = row_high_limit_last; + + csrow->first_page = row_base >> PAGE_SHIFT; + csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; + csrow->nr_pages = csrow->last_page - csrow->first_page + 1; + /* Error address is top 19 bits - so granularity is * + * 14 bits */ + csrow->grain = 1 << 14; + csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR; + /* FIXME - check that this is unknowable with this chipset */ + csrow->dtype = DEV_UNKNOWN; + + /* Mode is global on 82600 */ + csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE; + row_high_limit_last = row_high_limit; + } +} + +static int r82600_probe1(struct pci_dev *pdev, int dev_idx) +{ + struct mem_ctl_info *mci; u8 dramcr; - u32 ecc_on; - u32 reg_sdram; u32 eapr; u32 scrub_disabled; u32 sdram_refresh_rate; - u32 row_high_limit_last = 0; struct r82600_error_info discard; debugf0("%s()\n", __func__); pci_read_config_byte(pdev, R82600_DRAMC, &dramcr); pci_read_config_dword(pdev, R82600_EAP, &eapr); - ecc_on = dramcr & BIT(5); - reg_sdram = dramcr & BIT(4); scrub_disabled = eapr & BIT(31); sdram_refresh_rate = dramcr & (BIT(0) | BIT(1)); debugf2("%s(): sdram refresh rate = %#0x\n", __func__, @@ -226,13 +278,11 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr); mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS); - if (mci == NULL) { - rc = -ENOMEM; - goto fail; - } + if (mci == NULL) + return -ENOMEM; debugf0("%s(): mci = %p\n", __func__, mci); - mci->pdev = pdev; + mci->dev = &pdev->dev; mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; /* FIXME try to work out if the chip leads have been used for COM2 @@ -245,7 +295,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) * is possible. */ mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; - if (ecc_on) { + if (ecc_enabled(dramcr)) { if (scrub_disabled) debugf3("%s(): mci = %p - Scrubbing disabled! EAP: " "%#0x\n", __func__, mci, eapr); @@ -253,53 +303,17 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) mci->edac_cap = EDAC_FLAG_NONE; mci->mod_name = EDAC_MOD_STR; - mci->mod_ver = "$Revision: 1.1.2.6 $"; + mci->mod_ver = R82600_REVISION; mci->ctl_name = "R82600"; mci->edac_check = r82600_check; mci->ctl_page_to_phys = NULL; - - for (index = 0; index < mci->nr_csrows; index++) { - struct csrow_info *csrow = &mci->csrows[index]; - u8 drbar; /* sDram Row Boundry Address Register */ - u32 row_high_limit; - u32 row_base; - - /* find the DRAM Chip Select Base address and mask */ - pci_read_config_byte(mci->pdev, R82600_DRBA + index, &drbar); - - debugf1("MC%d: %s() Row=%d DRBA = %#0x\n", mci->mc_idx, - __func__, index, drbar); - - row_high_limit = ((u32) drbar << 24); -/* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ - - debugf1("MC%d: %s() Row=%d, Boundry Address=%#0x, Last = " - "%#0x \n", mci->mc_idx, __func__, index, - row_high_limit, row_high_limit_last); - - /* Empty row [p.57] */ - if (row_high_limit == row_high_limit_last) - continue; - - row_base = row_high_limit_last; - csrow->first_page = row_base >> PAGE_SHIFT; - csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; - csrow->nr_pages = csrow->last_page - csrow->first_page + 1; - /* Error address is top 19 bits - so granularity is * - * 14 bits */ - csrow->grain = 1 << 14; - csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR; - /* FIXME - check that this is unknowable with this chipset */ - csrow->dtype = DEV_UNKNOWN; - - /* Mode is global on 82600 */ - csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE; - row_high_limit_last = row_high_limit; - } - + r82600_init_csrows(mci, pdev, dramcr); r82600_get_error_info(mci, &discard); /* clear counters */ - if (edac_mc_add_mc(mci)) { + /* Here we assume that we will never see multiple instances of this + * type of memory controller. The ID is therefore hardcoded to 0. + */ + if (edac_mc_add_mc(mci,0)) { debugf3("%s(): failed edac_mc_add_mc()\n", __func__); goto fail; } @@ -309,17 +323,15 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) if (disable_hardware_scrub) { debugf3("%s(): Disabling Hardware Scrub (scrub on error)\n", __func__); - pci_write_bits32(mci->pdev, R82600_EAP, BIT(31), BIT(31)); + pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31)); } debugf3("%s(): success\n", __func__); return 0; fail: - if (mci) - edac_mc_free(mci); - - return rc; + edac_mc_free(mci); + return -ENODEV; } /* returns count (>= 0), or negative on error */ @@ -338,7 +350,7 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev) debugf0("%s()\n", __func__); - if ((mci = edac_mc_del_mc(pdev)) == NULL) + if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) return; edac_mc_free(mci); |