X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fedac%2Fr82600_edac.c;h=e25f712f2dc3b8479e224d6bae80d9765304166b;hb=ee0ae927937ac8a30350cca1a7a75efafb13976e;hp=2c29fafe67c7ef5877c950b6d9468caf6dc87cf2;hpb=5b67e8dd5ae889fea7d01b905a570fa9a37b8785;p=linux-2.6-omap-h63xx.git diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index 2c29fafe67c..e25f712f2dc 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -11,17 +11,19 @@ * * Written with reference to 82600 High Integration Dual PCI System * Controller Data Book: - * http://www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf + * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf * references to this document given in [] */ -#include #include #include #include #include #include -#include "edac_mc.h" +#include "edac_core.h" + +#define R82600_REVISION " Ver: 2.0.2 " __DATE__ +#define EDAC_MOD_STR "r82600_edac" #define r82600_printk(level, fmt, arg...) \ edac_printk(level, "r82600", fmt, ##arg) @@ -129,28 +131,34 @@ struct r82600_error_info { u32 eapr; }; -static unsigned int disable_hardware_scrub = 0; +static unsigned int disable_hardware_scrub; + +static struct edac_pci_ctl_info *r82600_pci; -static void r82600_get_error_info (struct mem_ctl_info *mci, - struct r82600_error_info *info) +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, - ((u32) BIT(0) & (u32) BIT(1)), - ((u32) BIT(0) & (u32) BIT(1))); + 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, - ((u32) BIT(0) & (u32) BIT(1)), - ((u32) BIT(0) & (u32) BIT(1))); + pci_write_bits32(pdev, R82600_EAP, + ((u32) BIT(0) & (u32) BIT(1)), + ((u32) BIT(0) & (u32) BIT(1))); } -static int r82600_process_error_info (struct mem_ctl_info *mci, - struct r82600_error_info *info, int handle_errors) +static int r82600_process_error_info(struct mem_ctl_info *mci, + struct r82600_error_info *info, + int handle_errors) { int error_found; u32 eapaddr, page; @@ -167,25 +175,24 @@ static int r82600_process_error_info (struct mem_ctl_info *mci, * granularity (upper 19 bits only) */ page = eapaddr >> PAGE_SHIFT; - if (info->eapr & BIT(0)) { /* CE? */ + if (info->eapr & BIT(0)) { /* CE? */ error_found = 1; if (handle_errors) - edac_mc_handle_ce(mci, page, 0, /* not avail */ + edac_mc_handle_ce(mci, page, 0, /* not avail */ syndrome, edac_mc_find_csrow_by_page(mci, page), - 0, /* channel */ - mci->ctl_name); + 0, mci->ctl_name); } - if (info->eapr & BIT(1)) { /* UE? */ + if (info->eapr & BIT(1)) { /* UE? */ error_found = 1; if (handle_errors) /* 82600 doesn't give enough info */ edac_mc_handle_ue(mci, page, 0, - edac_mc_find_csrow_by_page(mci, page), - mci->ctl_name); + edac_mc_find_csrow_by_page(mci, page), + mci->ctl_name); } return error_found; @@ -200,39 +207,84 @@ 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) { - int rc = -ENODEV; + return dramcr & BIT(5); +} + +static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, + u8 dramcr) +{ + 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__, sdram_refresh_rate); debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr); - mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS); + mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0); - 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 +297,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,52 +305,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->dev_name = pci_name(pdev); mci->edac_check = r82600_check; mci->ctl_page_to_phys = NULL; + r82600_init_csrows(mci, pdev, dramcr); + r82600_get_error_info(mci, &discard); /* clear counters */ - 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_get_error_info(mci, &discard); /* clear counters */ - + /* 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)) { debugf3("%s(): failed edac_mc_add_mc()\n", __func__); goto fail; @@ -309,22 +326,31 @@ 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)); + } + + /* allocating generic PCI control info */ + r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); + if (!r82600_pci) { + printk(KERN_WARNING + "%s(): Unable to create PCI control\n", + __func__); + printk(KERN_WARNING + "%s(): PCI error report via EDAC not setup\n", + __func__); } 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 */ static int __devinit r82600_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) + const struct pci_device_id *ent) { debugf0("%s()\n", __func__); @@ -338,7 +364,10 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev) debugf0("%s()\n", __func__); - if ((mci = edac_mc_del_mc(pdev)) == NULL) + if (r82600_pci) + edac_pci_release_generic_ctl(r82600_pci); + + if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) return; edac_mc_free(mci); @@ -346,11 +375,11 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev) static const struct pci_device_id r82600_pci_tbl[] __devinitdata = { { - PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID) - }, + PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID) + }, { - 0, - } /* 0 terminated list. */ + 0, + } /* 0 terminated list. */ }; MODULE_DEVICE_TABLE(pci, r82600_pci_tbl); @@ -377,7 +406,7 @@ module_exit(r82600_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Small - WPAD Ltd. " - "on behalf of EADS Astrium"); + "on behalf of EADS Astrium"); MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); module_param(disable_hardware_scrub, bool, 0644);