diff options
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/amd76x_edac.c | 99 | ||||
-rw-r--r-- | drivers/edac/e752x_edac.c | 346 | ||||
-rw-r--r-- | drivers/edac/e7xxx_edac.c | 177 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 590 | ||||
-rw-r--r-- | drivers/edac/edac_mc.h | 23 | ||||
-rw-r--r-- | drivers/edac/i82860_edac.c | 133 | ||||
-rw-r--r-- | drivers/edac/i82875p_edac.c | 221 | ||||
-rw-r--r-- | drivers/edac/r82600_edac.c | 144 |
8 files changed, 935 insertions, 798 deletions
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index 53423ad6d4a..f79f6b587bf 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c @@ -12,7 +12,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -20,6 +19,9 @@ #include <linux/slab.h> #include "edac_mc.h" +#define AMD76X_REVISION " Ver: 2.0.1 " __DATE__ +#define EDAC_MOD_STR "amd76x_edac" + #define amd76x_printk(level, fmt, arg...) \ edac_printk(level, "amd76x", fmt, ##arg) @@ -102,15 +104,18 @@ static const struct amd76x_dev_info amd76x_devs[] = { static void amd76x_get_error_info(struct mem_ctl_info *mci, struct amd76x_error_info *info) { - pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS, + struct pci_dev *pdev; + + pdev = to_pci_dev(mci->dev); + pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &info->ecc_mode_status); if (info->ecc_mode_status & BIT(8)) - pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, + pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS, (u32) BIT(8), (u32) BIT(8)); if (info->ecc_mode_status & BIT(9)) - pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, + pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS, (u32) BIT(9), (u32) BIT(9)); } @@ -176,6 +181,38 @@ static void amd76x_check(struct mem_ctl_info *mci) amd76x_process_error_info(mci, &info, 1); } +static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, + enum edac_type edac_mode) +{ + struct csrow_info *csrow; + u32 mba, mba_base, mba_mask, dms; + int index; + + for (index = 0; index < mci->nr_csrows; index++) { + csrow = &mci->csrows[index]; + + /* find the DRAM Chip Select Base address and mask */ + pci_read_config_dword(pdev, + AMD76X_MEM_BASE_ADDR + (index * 4), + &mba); + + if (!(mba & BIT(0))) + continue; + + mba_base = mba & 0xff800000UL; + mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL; + pci_read_config_dword(pdev, AMD76X_DRAM_MODE_STATUS, &dms); + csrow->first_page = mba_base >> PAGE_SHIFT; + csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; + csrow->page_mask = mba_mask >> PAGE_SHIFT; + csrow->grain = csrow->nr_pages << PAGE_SHIFT; + csrow->mtype = MEM_RDDR; + csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN; + csrow->edac_mode = edac_mode; + } +} + /** * amd76x_probe1 - Perform set up for detected device * @pdev; PCI device detected @@ -187,15 +224,13 @@ static void amd76x_check(struct mem_ctl_info *mci) */ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) { - int rc = -ENODEV; - int index; - struct mem_ctl_info *mci = NULL; - enum edac_type ems_modes[] = { + static const enum edac_type ems_modes[] = { EDAC_NONE, EDAC_EC, EDAC_SECDED, EDAC_SECDED }; + struct mem_ctl_info *mci = NULL; u32 ems; u32 ems_mode; struct amd76x_error_info discard; @@ -206,53 +241,28 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS); if (mci == NULL) { - rc = -ENOMEM; - goto fail; + return -ENOMEM; } debugf0("%s(): mci = %p\n", __func__, mci); - mci->pdev = pdev; + mci->dev = &pdev->dev; mci->mtype_cap = MEM_FLAG_RDDR; mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; mci->edac_cap = ems_mode ? (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE; mci->mod_name = EDAC_MOD_STR; - mci->mod_ver = "$Revision: 1.4.2.5 $"; + mci->mod_ver = AMD76X_REVISION; mci->ctl_name = amd76x_devs[dev_idx].ctl_name; mci->edac_check = amd76x_check; mci->ctl_page_to_phys = NULL; - for (index = 0; index < mci->nr_csrows; index++) { - struct csrow_info *csrow = &mci->csrows[index]; - u32 mba; - u32 mba_base; - u32 mba_mask; - u32 dms; - - /* find the DRAM Chip Select Base address and mask */ - pci_read_config_dword(mci->pdev, - AMD76X_MEM_BASE_ADDR + (index * 4), &mba); - - if (!(mba & BIT(0))) - continue; - - mba_base = mba & 0xff800000UL; - mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL; - pci_read_config_dword(mci->pdev, AMD76X_DRAM_MODE_STATUS, - &dms); - csrow->first_page = mba_base >> PAGE_SHIFT; - csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT; - csrow->last_page = csrow->first_page + csrow->nr_pages - 1; - csrow->page_mask = mba_mask >> PAGE_SHIFT; - csrow->grain = csrow->nr_pages << PAGE_SHIFT; - csrow->mtype = MEM_RDDR; - csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN; - csrow->edac_mode = ems_modes[ems_mode]; - } - + amd76x_init_csrows(mci, pdev, ems_modes[ems_mode]); amd76x_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; } @@ -262,9 +272,8 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) return 0; fail: - if (mci != NULL) - edac_mc_free(mci); - return rc; + edac_mc_free(mci); + return -ENODEV; } /* returns count (>= 0), or negative on error */ @@ -291,7 +300,7 @@ static void __devexit amd76x_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); diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index fce31936e6d..c82bc0ed7f1 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -17,7 +17,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -25,6 +24,9 @@ #include <linux/slab.h> #include "edac_mc.h" +#define E752X_REVISION " Ver: 2.0.1 " __DATE__ +#define EDAC_MOD_STR "e752x_edac" + static int force_function_unhide; #define e752x_printk(level, fmt, arg...) \ @@ -763,22 +765,174 @@ static void e752x_check(struct mem_ctl_info *mci) e752x_process_error_info(mci, &info, 1); } -static int e752x_probe1(struct pci_dev *pdev, int dev_idx) +/* Return 1 if dual channel mode is active. Else return 0. */ +static inline int dual_channel_active(u16 ddrcsr) +{ + return (((ddrcsr >> 12) & 3) == 3); +} + +static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, + u16 ddrcsr) +{ + struct csrow_info *csrow; + unsigned long last_cumul_size; + int index, mem_dev, drc_chan; + int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ + int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ + u8 value; + u32 dra, drc, cumul_size; + + pci_read_config_dword(pdev, E752X_DRA, &dra); + pci_read_config_dword(pdev, E752X_DRC, &drc); + drc_chan = dual_channel_active(ddrcsr); + drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ + drc_ddim = (drc >> 20) & 0x3; + + /* The dram row boundary (DRB) reg values are boundary address for + * each DRAM row with a granularity of 64 or 128MB (single/dual + * channel operation). DRB regs are cumulative; therefore DRB7 will + * contain the total memory contained in all eight rows. + */ + for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { + /* mem_dev 0=x8, 1=x4 */ + mem_dev = (dra >> (index * 4 + 2)) & 0x3; + csrow = &mci->csrows[index]; + + mem_dev = (mem_dev == 2); + pci_read_config_byte(pdev, E752X_DRB + index, &value); + /* convert a 128 or 64 MiB DRB to a page size. */ + cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); + debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, + cumul_size); + if (cumul_size == last_cumul_size) + continue; /* not populated */ + + csrow->first_page = last_cumul_size; + csrow->last_page = cumul_size - 1; + csrow->nr_pages = cumul_size - last_cumul_size; + last_cumul_size = cumul_size; + csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ + csrow->mtype = MEM_RDDR; /* only one type supported */ + csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; + + /* + * if single channel or x8 devices then SECDED + * if dual channel and x4 then S4ECD4ED + */ + if (drc_ddim) { + if (drc_chan && mem_dev) { + csrow->edac_mode = EDAC_S4ECD4ED; + mci->edac_cap |= EDAC_FLAG_S4ECD4ED; + } else { + csrow->edac_mode = EDAC_SECDED; + mci->edac_cap |= EDAC_FLAG_SECDED; + } + } else + csrow->edac_mode = EDAC_NONE; + } +} + +static void e752x_init_mem_map_table(struct pci_dev *pdev, + struct e752x_pvt *pvt) { - int rc = -ENODEV; int index; + u8 value, last, row, stat8; + + last = 0; + row = 0; + + for (index = 0; index < 8; index += 2) { + pci_read_config_byte(pdev, E752X_DRB + index, &value); + /* test if there is a dimm in this slot */ + if (value == last) { + /* no dimm in the slot, so flag it as empty */ + pvt->map[index] = 0xff; + pvt->map[index + 1] = 0xff; + } else { /* there is a dimm in the slot */ + pvt->map[index] = row; + row++; + last = value; + /* test the next value to see if the dimm is double + * sided + */ + pci_read_config_byte(pdev, E752X_DRB + index + 1, + &value); + pvt->map[index + 1] = (value == last) ? + 0xff : /* the dimm is single sided, + so flag as empty */ + row; /* this is a double sided dimm + to save the next row # */ + row++; + last = value; + } + } + + /* set the map type. 1 = normal, 0 = reversed */ + pci_read_config_byte(pdev, E752X_DRM, &stat8); + pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); +} + +/* Return 0 on success or 1 on failure. */ +static int e752x_get_devs(struct pci_dev *pdev, int dev_idx, + struct e752x_pvt *pvt) +{ + struct pci_dev *dev; + + pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, + pvt->dev_info->err_dev, + pvt->bridge_ck); + + if (pvt->bridge_ck == NULL) + pvt->bridge_ck = pci_scan_single_device(pdev->bus, + PCI_DEVFN(0, 1)); + + if (pvt->bridge_ck == NULL) { + e752x_printk(KERN_ERR, "error reporting device not found:" + "vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); + return 1; + } + + dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev, + NULL); + + if (dev == NULL) + goto fail; + + pvt->dev_d0f0 = dev; + pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck); + + return 0; + +fail: + pci_dev_put(pvt->bridge_ck); + return 1; +} + +static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt) +{ + struct pci_dev *dev; + + dev = pvt->dev_d0f1; + /* Turn off error disable & SMI in case the BIOS turned it on */ + pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); + pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); + pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); + pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); + pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); +} + +static int e752x_probe1(struct pci_dev *pdev, int dev_idx) +{ u16 pci_data; u8 stat8; - struct mem_ctl_info *mci = NULL; - struct e752x_pvt *pvt = NULL; + struct mem_ctl_info *mci; + struct e752x_pvt *pvt; u16 ddrcsr; - u32 drc; int drc_chan; /* Number of channels 0=1chan,1=2chan */ - int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ - int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ - u32 dra; - unsigned long last_cumul_size; - struct pci_dev *dev = NULL; struct e752x_error_info discard; debugf0("%s(): mci\n", __func__); @@ -792,25 +946,20 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) if (!force_function_unhide && !(stat8 & (1 << 5))) { printk(KERN_INFO "Contact your BIOS vendor to see if the " "E752x error registers can be safely un-hidden\n"); - goto fail; + return -ENOMEM; } stat8 |= (1 << 5); pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); - /* need to find out the number of channels */ - pci_read_config_dword(pdev, E752X_DRC, &drc); pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr); /* FIXME: should check >>12 or 0xf, true for all? */ /* Dual channel = 1, Single channel = 0 */ - drc_chan = (((ddrcsr >> 12) & 3) == 3); - drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ - drc_ddim = (drc >> 20) & 0x3; + drc_chan = dual_channel_active(ddrcsr); mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1); if (mci == NULL) { - rc = -ENOMEM; - goto fail; + return -ENOMEM; } debugf3("%s(): init mci\n", __func__); @@ -819,159 +968,54 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) EDAC_FLAG_S4ECD4ED; /* FIXME - what if different memory types are in different csrows? */ mci->mod_name = EDAC_MOD_STR; - mci->mod_ver = "$Revision: 1.5.2.11 $"; - mci->pdev = pdev; + mci->mod_ver = E752X_REVISION; + mci->dev = &pdev->dev; debugf3("%s(): init pvt\n", __func__); pvt = (struct e752x_pvt *) mci->pvt_info; pvt->dev_info = &e752x_devs[dev_idx]; - pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, - pvt->dev_info->err_dev, - pvt->bridge_ck); - - if (pvt->bridge_ck == NULL) - pvt->bridge_ck = pci_scan_single_device(pdev->bus, - PCI_DEVFN(0, 1)); + pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); - if (pvt->bridge_ck == NULL) { - e752x_printk(KERN_ERR, "error reporting device not found:" - "vendor %x device 0x%x (broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); - goto fail; + if (e752x_get_devs(pdev, dev_idx, pvt)) { + edac_mc_free(mci); + return -ENODEV; } - pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); debugf3("%s(): more mci init\n", __func__); mci->ctl_name = pvt->dev_info->ctl_name; mci->edac_check = e752x_check; mci->ctl_page_to_phys = ctl_page_to_phys; - /* find out the device types */ - pci_read_config_dword(pdev, E752X_DRA, &dra); - - /* - * The dram row boundary (DRB) reg values are boundary address for - * each DRAM row with a granularity of 64 or 128MB (single/dual - * channel operation). DRB regs are cumulative; therefore DRB7 will - * contain the total memory contained in all eight rows. - */ - for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { - u8 value; - u32 cumul_size; - - /* mem_dev 0=x8, 1=x4 */ - int mem_dev = (dra >> (index * 4 + 2)) & 0x3; - struct csrow_info *csrow = &mci->csrows[index]; - - mem_dev = (mem_dev == 2); - pci_read_config_byte(mci->pdev, E752X_DRB + index, &value); - /* convert a 128 or 64 MiB DRB to a page size. */ - cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); - debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, - cumul_size); - - if (cumul_size == last_cumul_size) - continue; /* not populated */ - - csrow->first_page = last_cumul_size; - csrow->last_page = cumul_size - 1; - csrow->nr_pages = cumul_size - last_cumul_size; - last_cumul_size = cumul_size; - csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ - csrow->mtype = MEM_RDDR; /* only one type supported */ - csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; - - /* - * if single channel or x8 devices then SECDED - * if dual channel and x4 then S4ECD4ED - */ - if (drc_ddim) { - if (drc_chan && mem_dev) { - csrow->edac_mode = EDAC_S4ECD4ED; - mci->edac_cap |= EDAC_FLAG_S4ECD4ED; - } else { - csrow->edac_mode = EDAC_SECDED; - mci->edac_cap |= EDAC_FLAG_SECDED; - } - } else - csrow->edac_mode = EDAC_NONE; - } - - /* Fill in the memory map table */ - { - u8 value; - u8 last = 0; - u8 row = 0; - - for (index = 0; index < 8; index += 2) { - pci_read_config_byte(mci->pdev, E752X_DRB + index, - &value); - - /* test if there is a dimm in this slot */ - if (value == last) { - /* no dimm in the slot, so flag it as empty */ - pvt->map[index] = 0xff; - pvt->map[index + 1] = 0xff; - } else { /* there is a dimm in the slot */ - pvt->map[index] = row; - row++; - last = value; - /* test the next value to see if the dimm is - double sided */ - pci_read_config_byte(mci->pdev, - E752X_DRB + index + 1, - &value); - pvt->map[index + 1] = (value == last) ? - 0xff : /* the dimm is single sided, - * so flag as empty - */ - row; /* this is a double sided dimm - * to save the next row # - */ - row++; - last = value; - } - } - } + e752x_init_csrows(mci, pdev, ddrcsr); + e752x_init_mem_map_table(pdev, pvt); /* set the map type. 1 = normal, 0 = reversed */ - pci_read_config_byte(mci->pdev, E752X_DRM, &stat8); + pci_read_config_byte(pdev, E752X_DRM, &stat8); pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); mci->edac_cap |= EDAC_FLAG_NONE; debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); /* load the top of low memory, remap base, and remap limit vars */ - pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data); + pci_read_config_word(pdev, E752X_TOLM, &pci_data); pvt->tolm = ((u32) pci_data) << 4; - pci_read_config_word(mci->pdev, E752X_REMAPBASE, &pci_data); + pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data); pvt->remapbase = ((u32) pci_data) << 14; - pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data); + pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data); pvt->remaplimit = ((u32) pci_data) << 14; e752x_printk(KERN_INFO, "tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, pvt->remapbase, pvt->remaplimit); - 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; } - dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev, - NULL); - pvt->dev_d0f0 = dev; - /* find the error reporting device and clear errors */ - dev = pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck); - /* Turn off error disable & SMI in case the BIOS turned it on */ - pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); - pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); - pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); - pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); - pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); - pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); - pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); - pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); - + e752x_init_error_reporting_regs(pvt); e752x_get_error_info(mci, &discard); /* clear other MCH errors */ /* get this far and it's successful */ @@ -979,20 +1023,12 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) return 0; fail: - if (mci) { - if (pvt->dev_d0f0) - pci_dev_put(pvt->dev_d0f0); - - if (pvt->dev_d0f1) - pci_dev_put(pvt->dev_d0f1); - - if (pvt->bridge_ck) - pci_dev_put(pvt->bridge_ck); - - edac_mc_free(mci); - } + pci_dev_put(pvt->dev_d0f0); + pci_dev_put(pvt->dev_d0f1); + pci_dev_put(pvt->bridge_ck); + edac_mc_free(mci); - return rc; + return -ENODEV; } /* returns count (>= 0), or negative on error */ @@ -1015,7 +1051,7 @@ static void __devexit e752x_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; pvt = (struct e752x_pvt *) mci->pvt_info; diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index a9518d3e4be..310d91b41c9 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -22,7 +22,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -30,6 +29,9 @@ #include <linux/slab.h> #include "edac_mc.h" +#define E7XXX_REVISION " Ver: 2.0.1 " __DATE__ +#define EDAC_MOD_STR "e7xxx_edac" + #define e7xxx_printk(level, fmt, arg...) \ edac_printk(level, "e7xxx", fmt, ##arg) @@ -333,99 +335,61 @@ static void e7xxx_check(struct mem_ctl_info *mci) e7xxx_process_error_info(mci, &info, 1); } -static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) +/* Return 1 if dual channel mode is active. Else return 0. */ +static inline int dual_channel_active(u32 drc, int dev_idx) { - int rc = -ENODEV; - int index; - u16 pci_data; - struct mem_ctl_info *mci = NULL; - struct e7xxx_pvt *pvt = NULL; - u32 drc; - int drc_chan = 1; /* Number of channels 0=1chan,1=2chan */ - int drc_drbg = 1; /* DRB granularity 0=32mb,1=64mb */ - int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ - u32 dra; - unsigned long last_cumul_size; - struct e7xxx_error_info discard; - - debugf0("%s(): mci\n", __func__); + return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1; +} - /* need to find out the number of channels */ - pci_read_config_dword(pdev, E7XXX_DRC, &drc); +/* Return DRB granularity (0=32mb, 1=64mb). */ +static inline int drb_granularity(u32 drc, int dev_idx) +{ /* only e7501 can be single channel */ - if (dev_idx == E7501) { - drc_chan = ((drc >> 22) & 0x1); - drc_drbg = (drc >> 18) & 0x3; - } - - drc_ddim = (drc >> 20) & 0x3; - mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1); - - if (mci == NULL) { - rc = -ENOMEM; - goto fail; - } - - debugf3("%s(): init mci\n", __func__); - mci->mtype_cap = MEM_FLAG_RDDR; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | - EDAC_FLAG_S4ECD4ED; - /* FIXME - what if different memory types are in different csrows? */ - mci->mod_name = EDAC_MOD_STR; - mci->mod_ver = "$Revision: 1.5.2.9 $"; - mci->pdev = pdev; + return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1; +} - debugf3("%s(): init pvt\n", __func__); - pvt = (struct e7xxx_pvt *) mci->pvt_info; - pvt->dev_info = &e7xxx_devs[dev_idx]; - pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, - pvt->dev_info->err_dev, - pvt->bridge_ck); - if (!pvt->bridge_ck) { - e7xxx_printk(KERN_ERR, "error reporting device not found:" - "vendor %x device 0x%x (broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev); - goto fail; - } - - debugf3("%s(): more mci init\n", __func__); - mci->ctl_name = pvt->dev_info->ctl_name; - mci->edac_check = e7xxx_check; - mci->ctl_page_to_phys = ctl_page_to_phys; +static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, + int dev_idx, u32 drc) +{ + unsigned long last_cumul_size; + int index; + u8 value; + u32 dra, cumul_size; + int drc_chan, drc_drbg, drc_ddim, mem_dev; + struct csrow_info *csrow; - /* find out the device types */ pci_read_config_dword(pdev, E7XXX_DRA, &dra); + drc_chan = dual_channel_active(drc, dev_idx); + drc_drbg = drb_granularity(drc, dev_idx); + drc_ddim = (drc >> 20) & 0x3; + last_cumul_size = 0; - /* - * The dram row boundary (DRB) reg values are boundary address + /* The dram row boundary (DRB) reg values are boundary address * for each DRAM row with a granularity of 32 or 64MB (single/dual * channel operation). DRB regs are cumulative; therefore DRB7 will * contain the total memory contained in all eight rows. */ - for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { - u8 value; - u32 cumul_size; + for (index = 0; index < mci->nr_csrows; index++) { /* mem_dev 0=x8, 1=x4 */ - int mem_dev = (dra >> (index * 4 + 3)) & 0x1; - struct csrow_info *csrow = &mci->csrows[index]; + mem_dev = (dra >> (index * 4 + 3)) & 0x1; + csrow = &mci->csrows[index]; - pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value); + pci_read_config_byte(pdev, E7XXX_DRB + index, &value); /* convert a 64 or 32 MiB DRB to a page size. */ cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, cumul_size); - if (cumul_size == last_cumul_size) - continue; /* not populated */ + continue; /* not populated */ csrow->first_page = last_cumul_size; csrow->last_page = cumul_size - 1; csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; - csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ - csrow->mtype = MEM_RDDR; /* only one type supported */ + csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ + csrow->mtype = MEM_RDDR; /* only one type supported */ csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; /* @@ -443,16 +407,61 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) } else csrow->edac_mode = EDAC_NONE; } +} - mci->edac_cap |= EDAC_FLAG_NONE; +static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) +{ + u16 pci_data; + struct mem_ctl_info *mci = NULL; + struct e7xxx_pvt *pvt = NULL; + u32 drc; + int drc_chan; + struct e7xxx_error_info discard; + + debugf0("%s(): mci\n", __func__); + pci_read_config_dword(pdev, E7XXX_DRC, &drc); + + drc_chan = dual_channel_active(drc, dev_idx); + mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1); + + if (mci == NULL) + return -ENOMEM; + + debugf3("%s(): init mci\n", __func__); + mci->mtype_cap = MEM_FLAG_RDDR; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | + EDAC_FLAG_S4ECD4ED; + /* FIXME - what if different memory types are in different csrows? */ + mci->mod_name = EDAC_MOD_STR; + mci->mod_ver = E7XXX_REVISION; + mci->dev = &pdev->dev; + debugf3("%s(): init pvt\n", __func__); + pvt = (struct e7xxx_pvt *) mci->pvt_info; + pvt->dev_info = &e7xxx_devs[dev_idx]; + pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, + pvt->dev_info->err_dev, + pvt->bridge_ck); + if (!pvt->bridge_ck) { + e7xxx_printk(KERN_ERR, "error reporting device not found:" + "vendor %x device 0x%x (broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev); + goto fail0; + } + + debugf3("%s(): more mci init\n", __func__); + mci->ctl_name = pvt->dev_info->ctl_name; + mci->edac_check = e7xxx_check; + mci->ctl_page_to_phys = ctl_page_to_phys; + e7xxx_init_csrows(mci, pdev, dev_idx, drc); + mci->edac_cap |= EDAC_FLAG_NONE; debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); /* load the top of low memory, remap base, and remap limit vars */ - pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data); + pci_read_config_word(pdev, E7XXX_TOLM, &pci_data); pvt->tolm = ((u32) pci_data) << 4; - pci_read_config_word(mci->pdev, E7XXX_REMAPBASE, &pci_data); + pci_read_config_word(pdev, E7XXX_REMAPBASE, &pci_data); pvt->remapbase = ((u32) pci_data) << 14; - pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data); + pci_read_config_word(pdev, E7XXX_REMAPLIMIT, &pci_data); pvt->remaplimit = ((u32) pci_data) << 14; e7xxx_printk(KERN_INFO, "tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, @@ -461,23 +470,25 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) /* clear any pending errors, or initial state bits */ e7xxx_get_error_info(mci, &discard); - if (edac_mc_add_mc(mci) != 0) { + /* 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; + goto fail1; } /* get this far and it's successful */ debugf3("%s(): success\n", __func__); return 0; -fail: - if (mci != NULL) { - if(pvt != NULL && pvt->bridge_ck) - pci_dev_put(pvt->bridge_ck); - edac_mc_free(mci); - } +fail1: + pci_dev_put(pvt->bridge_ck); + +fail0: + edac_mc_free(mci); - return rc; + return -ENODEV; } /* returns count (>= 0), or negative on error */ @@ -498,7 +509,7 @@ static void __devexit e7xxx_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; pvt = (struct e7xxx_pvt *) mci->pvt_info; diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index ea06e3a4dc3..3a7cfe88b16 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -12,7 +12,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/kernel.h> @@ -54,16 +53,17 @@ static int log_ce = 1; static int panic_on_ue; static int poll_msec = 1000; -static int check_pci_parity = 0; /* default YES check PCI parity */ -static int panic_on_pci_parity; /* default no panic on PCI Parity */ -static atomic_t pci_parity_count = ATOMIC_INIT(0); - /* lock to memory controller's control array */ static DECLARE_MUTEX(mem_ctls_mutex); static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); static struct task_struct *edac_thread; +#ifdef CONFIG_PCI +static int check_pci_parity = 0; /* default YES check PCI parity */ +static int panic_on_pci_parity; /* default no panic on PCI Parity */ +static atomic_t pci_parity_count = ATOMIC_INIT(0); + /* Structure of the whitelist and blacklist arrays */ struct edac_pci_device_list { unsigned int vendor; /* Vendor ID */ @@ -80,6 +80,12 @@ static int pci_blacklist_count; static struct edac_pci_device_list pci_whitelist[MAX_LISTED_PCI_DEVICES]; static int pci_whitelist_count ; +#ifndef DISABLE_EDAC_SYSFS +static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */ +static struct completion edac_pci_kobj_complete; +#endif /* DISABLE_EDAC_SYSFS */ +#endif /* CONFIG_PCI */ + /* START sysfs data and methods */ #ifndef DISABLE_EDAC_SYSFS @@ -127,18 +133,15 @@ static struct sysdev_class edac_class = { set_kset_name("edac"), }; -/* sysfs objects: +/* sysfs object: * /sys/devices/system/edac/mc - * /sys/devices/system/edac/pci */ static struct kobject edac_memctrl_kobj; -static struct kobject edac_pci_kobj; /* We use these to wait for the reference counts on edac_memctrl_kobj and * edac_pci_kobj to reach 0. */ static struct completion edac_memctrl_kobj_complete; -static struct completion edac_pci_kobj_complete; /* * /sys/devices/system/edac/mc; @@ -324,6 +327,8 @@ static void edac_sysfs_memctrl_teardown(void) #endif /* DISABLE_EDAC_SYSFS */ } +#ifdef CONFIG_PCI + #ifndef DISABLE_EDAC_SYSFS /* @@ -624,6 +629,252 @@ static void edac_sysfs_pci_teardown(void) #endif } + +static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) +{ + int where; + u16 status; + + where = secondary ? PCI_SEC_STATUS : PCI_STATUS; + pci_read_config_word(dev, where, &status); + + /* If we get back 0xFFFF then we must suspect that the card has been + * pulled but the Linux PCI layer has not yet finished cleaning up. + * We don't want to report on such devices + */ + + if (status == 0xFFFF) { + u32 sanity; + + pci_read_config_dword(dev, 0, &sanity); + + if (sanity == 0xFFFFFFFF) + return 0; + } + + status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | + PCI_STATUS_PARITY; + + if (status) + /* reset only the bits we are interested in */ + pci_write_config_word(dev, where, status); + + return status; +} + +typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev); + +/* Clear any PCI parity errors logged by this device. */ +static void edac_pci_dev_parity_clear(struct pci_dev *dev) +{ + u8 header_type; + + get_pci_parity_status(dev, 0); + + /* read the device TYPE, looking for bridges */ + pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) + get_pci_parity_status(dev, 1); +} + +/* + * PCI Parity polling + * + */ +static void edac_pci_dev_parity_test(struct pci_dev *dev) +{ + u16 status; + u8 header_type; + + /* read the STATUS register on this device + */ + status = get_pci_parity_status(dev, 0); + + debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id ); + + /* check the status reg for errors */ + if (status) { + if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) + edac_printk(KERN_CRIT, EDAC_PCI, + "Signaled System Error on %s\n", + pci_name(dev)); + + if (status & (PCI_STATUS_PARITY)) { + edac_printk(KERN_CRIT, EDAC_PCI, + "Master Data Parity Error on %s\n", + pci_name(dev)); + + atomic_inc(&pci_parity_count); + } + + if (status & (PCI_STATUS_DETECTED_PARITY)) { + edac_printk(KERN_CRIT, EDAC_PCI, + "Detected Parity Error on %s\n", + pci_name(dev)); + + atomic_inc(&pci_parity_count); + } + } + + /* read the device TYPE, looking for bridges */ + pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); + + debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id ); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + /* On bridges, need to examine secondary status register */ + status = get_pci_parity_status(dev, 1); + + debugf2("PCI SEC_STATUS= 0x%04x %s\n", + status, dev->dev.bus_id ); + + /* check the secondary status reg for errors */ + if (status) { + if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) + edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " + "Signaled System Error on %s\n", + pci_name(dev)); + + if (status & (PCI_STATUS_PARITY)) { + edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " + "Master Data Parity Error on " + "%s\n", pci_name(dev)); + + atomic_inc(&pci_parity_count); + } + + if (status & (PCI_STATUS_DETECTED_PARITY)) { + edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " + "Detected Parity Error on %s\n", + pci_name(dev)); + + atomic_inc(&pci_parity_count); + } + } + } +} + +/* + * check_dev_on_list: Scan for a PCI device on a white/black list + * @list: an EDAC &edac_pci_device_list white/black list pointer + * @free_index: index of next free entry on the list + * @pci_dev: PCI Device pointer + * + * see if list contains the device. + * + * Returns: 0 not found + * 1 found on list + */ +static int check_dev_on_list(struct edac_pci_device_list *list, + int free_index, struct pci_dev *dev) +{ + int i; + int rc = 0; /* Assume not found */ + unsigned short vendor=dev->vendor; + unsigned short device=dev->device; + + /* Scan the list, looking for a vendor/device match */ + for (i = 0; i < free_index; i++, list++ ) { + if ((list->vendor == vendor ) && (list->device == device )) { + rc = 1; + break; + } + } + + return rc; +} + +/* + * pci_dev parity list iterator + * Scan the PCI device list for one iteration, looking for SERRORs + * Master Parity ERRORS or Parity ERRORs on primary or secondary devices + */ +static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) +{ + struct pci_dev *dev = NULL; + + /* request for kernel access to the next PCI device, if any, + * and while we are looking at it have its reference count + * bumped until we are done with it + */ + while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + /* if whitelist exists then it has priority, so only scan + * those devices on the whitelist + */ + if (pci_whitelist_count > 0 ) { + if (check_dev_on_list(pci_whitelist, + pci_whitelist_count, dev)) + fn(dev); + } else { + /* + * if no whitelist, then check if this devices is + * blacklisted + */ + if (!check_dev_on_list(pci_blacklist, + pci_blacklist_count, dev)) + fn(dev); + } + } +} + +static void do_pci_parity_check(void) +{ + unsigned long flags; + int before_count; + + debugf3("%s()\n", __func__); + + if (!check_pci_parity) + return; + + before_count = atomic_read(&pci_parity_count); + + /* scan all PCI devices looking for a Parity Error on devices and + * bridges + */ + local_irq_save(flags); + edac_pci_dev_parity_iterator(edac_pci_dev_parity_test); + local_irq_restore(flags); + + /* Only if operator has selected panic on PCI Error */ + if (panic_on_pci_parity) { + /* If the count is different 'after' from 'before' */ + if (before_count != atomic_read(&pci_parity_count)) + panic("EDAC: PCI Parity Error"); + } +} + +static inline void clear_pci_parity_errors(void) +{ + /* Clear any PCI bus parity errors that devices initially have logged + * in their registers. + */ + edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); +} + +#else /* CONFIG_PCI */ + +static inline void do_pci_parity_check(void) +{ + /* no-op */ +} + +static inline void clear_pci_parity_errors(void) +{ + /* no-op */ +} + +static void edac_sysfs_pci_teardown(void) +{ +} + +static int edac_sysfs_pci_setup(void) +{ + return 0; +} +#endif /* CONFIG_PCI */ + #ifndef DISABLE_EDAC_SYSFS /* EDAC sysfs CSROW data structures and methods */ @@ -1132,7 +1383,7 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) return err; /* create a symlink for the device */ - err = sysfs_create_link(edac_mci_kobj, &mci->pdev->dev.kobj, + err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj, EDAC_DEVICE_SYMLINK); if (err) @@ -1238,7 +1489,7 @@ void edac_mc_dump_mci(struct mem_ctl_info *mci) debugf4("\tmci->edac_check = %p\n", mci->edac_check); debugf3("\tmci->nr_csrows = %d, csrows = %p\n", mci->nr_csrows, mci->csrows); - debugf3("\tpdev = %p\n", mci->pdev); + debugf3("\tdev = %p\n", mci->dev); debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name); debugf3("\tpvt_info = %p\n\n", mci->pvt_info); @@ -1363,7 +1614,7 @@ void edac_mc_free(struct mem_ctl_info *mci) } EXPORT_SYMBOL_GPL(edac_mc_free); -static struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev) +static struct mem_ctl_info *find_mci_by_dev(struct device *dev) { struct mem_ctl_info *mci; struct list_head *item; @@ -1373,54 +1624,53 @@ static struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev) list_for_each(item, &mc_devices) { mci = list_entry(item, struct mem_ctl_info, link); - if (mci->pdev == pdev) + if (mci->dev == dev) return mci; } return NULL; } -static int add_mc_to_global_list(struct mem_ctl_info *mci) +/* Return 0 on success, 1 on failure. + * Before calling this function, caller must + * assign a unique value to mci->mc_idx. + */ +static int add_mc_to_global_list (struct mem_ctl_info *mci) { struct list_head *item, *insert_before; struct mem_ctl_info *p; - int i; - if (list_empty(&mc_devices)) { - mci->mc_idx = 0; - insert_before = &mc_devices; - } else { - if (find_mci_by_pdev(mci->pdev)) { - edac_printk(KERN_WARNING, EDAC_MC, - "%s (%s) %s %s already assigned %d\n", - mci->pdev->dev.bus_id, - pci_name(mci->pdev), mci->mod_name, - mci->ctl_name, mci->mc_idx); - return 1; - } + insert_before = &mc_devices; - insert_before = NULL; - i = 0; + if (unlikely((p = find_mci_by_dev(mci->dev)) != NULL)) + goto fail0; - list_for_each(item, &mc_devices) { - p = list_entry(item, struct mem_ctl_info, link); + list_for_each(item, &mc_devices) { + p = list_entry(item, struct mem_ctl_info, link); - if (p->mc_idx != i) { - insert_before = item; - break; - } + if (p->mc_idx >= mci->mc_idx) { + if (unlikely(p->mc_idx == mci->mc_idx)) + goto fail1; - i++; + insert_before = item; + break; } - - mci->mc_idx = i; - - if (insert_before == NULL) - insert_before = &mc_devices; } list_add_tail_rcu(&mci->link, insert_before); return 0; + +fail0: + edac_printk(KERN_WARNING, EDAC_MC, + "%s (%s) %s %s already assigned %d\n", p->dev->bus_id, + dev_name(p->dev), p->mod_name, p->ctl_name, p->mc_idx); + return 1; + +fail1: + edac_printk(KERN_WARNING, EDAC_MC, + "bug in low-level driver: attempt to assign\n" + " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__); + return 1; } static void complete_mc_list_del(struct rcu_head *head) @@ -1444,6 +1694,7 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci) * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and * create sysfs entries associated with mci structure * @mci: pointer to the mci structure to be added to the list + * @mc_idx: A unique numeric identifier to be assigned to the 'mci' structure. * * Return: * 0 Success @@ -1451,9 +1702,10 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci) */ /* FIXME - should a warning be printed if no error detection? correction? */ -int edac_mc_add_mc(struct mem_ctl_info *mci) +int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx) { debugf0("%s()\n", __func__); + mci->mc_idx = mc_idx; #ifdef CONFIG_EDAC_DEBUG if (edac_debug_level >= 3) edac_mc_dump_mci(mci); @@ -1486,8 +1738,8 @@ int edac_mc_add_mc(struct mem_ctl_info *mci) } /* Report action taken */ - edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: PCI %s\n", - mci->mod_name, mci->ctl_name, pci_name(mci->pdev)); + edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n", + mci->mod_name, mci->ctl_name, dev_name(mci->dev)); up(&mem_ctls_mutex); return 0; @@ -1504,18 +1756,18 @@ EXPORT_SYMBOL_GPL(edac_mc_add_mc); /** * edac_mc_del_mc: Remove sysfs entries for specified mci structure and * remove mci structure from global list - * @pdev: Pointer to 'struct pci_dev' representing mci structure to remove. + * @pdev: Pointer to 'struct device' representing mci structure to remove. * * Return pointer to removed mci structure, or NULL if device not found. */ -struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev) +struct mem_ctl_info * edac_mc_del_mc(struct device *dev) { struct mem_ctl_info *mci; debugf0("MC: %s()\n", __func__); down(&mem_ctls_mutex); - if ((mci = find_mci_by_pdev(pdev)) == NULL) { + if ((mci = find_mci_by_dev(dev)) == NULL) { up(&mem_ctls_mutex); return NULL; } @@ -1524,8 +1776,8 @@ struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev) del_mc_from_global_list(mci); up(&mem_ctls_mutex); edac_printk(KERN_INFO, EDAC_MC, - "Removed device %d for %s %s: PCI %s\n", mci->mc_idx, - mci->mod_name, mci->ctl_name, pci_name(mci->pdev)); + "Removed device %d for %s %s: DEV %s\n", mci->mc_idx, + mci->mod_name, mci->ctl_name, dev_name(mci->dev)); return mci; } EXPORT_SYMBOL_GPL(edac_mc_del_mc); @@ -1739,244 +1991,6 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) } EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); -#ifdef CONFIG_PCI - -static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) -{ - int where; - u16 status; - - where = secondary ? PCI_SEC_STATUS : PCI_STATUS; - pci_read_config_word(dev, where, &status); - - /* If we get back 0xFFFF then we must suspect that the card has been - * pulled but the Linux PCI layer has not yet finished cleaning up. - * We don't want to report on such devices - */ - - if (status == 0xFFFF) { - u32 sanity; - - pci_read_config_dword(dev, 0, &sanity); - - if (sanity == 0xFFFFFFFF) - return 0; - } - - status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | - PCI_STATUS_PARITY; - - if (status) - /* reset only the bits we are interested in */ - pci_write_config_word(dev, where, status); - - return status; -} - -typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev); - -/* Clear any PCI parity errors logged by this device. */ -static void edac_pci_dev_parity_clear(struct pci_dev *dev) -{ - u8 header_type; - - get_pci_parity_status(dev, 0); - - /* read the device TYPE, looking for bridges */ - pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) - get_pci_parity_status(dev, 1); -} - -/* - * PCI Parity polling - * - */ -static void edac_pci_dev_parity_test(struct pci_dev *dev) -{ - u16 status; - u8 header_type; - - /* read the STATUS register on this device - */ - status = get_pci_parity_status(dev, 0); - - debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id ); - - /* check the status reg for errors */ - if (status) { - if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) - edac_printk(KERN_CRIT, EDAC_PCI, - "Signaled System Error on %s\n", - pci_name(dev)); - - if (status & (PCI_STATUS_PARITY)) { - edac_printk(KERN_CRIT, EDAC_PCI, - "Master Data Parity Error on %s\n", - pci_name(dev)); - - atomic_inc(&pci_parity_count); - } - - if (status & (PCI_STATUS_DETECTED_PARITY)) { - edac_printk(KERN_CRIT, EDAC_PCI, - "Detected Parity Error on %s\n", - pci_name(dev)); - - atomic_inc(&pci_parity_count); - } - } - - /* read the device TYPE, looking for bridges */ - pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); - - debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id ); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - /* On bridges, need to examine secondary status register */ - status = get_pci_parity_status(dev, 1); - - debugf2("PCI SEC_STATUS= 0x%04x %s\n", - status, dev->dev.bus_id ); - - /* check the secondary status reg for errors */ - if (status) { - if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) - edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " - "Signaled System Error on %s\n", - pci_name(dev)); - - if (status & (PCI_STATUS_PARITY)) { - edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " - "Master Data Parity Error on " - "%s\n", pci_name(dev)); - - atomic_inc(&pci_parity_count); - } - - if (status & (PCI_STATUS_DETECTED_PARITY)) { - edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " - "Detected Parity Error on %s\n", - pci_name(dev)); - - atomic_inc(&pci_parity_count); - } - } - } -} - -/* - * check_dev_on_list: Scan for a PCI device on a white/black list - * @list: an EDAC &edac_pci_device_list white/black list pointer - * @free_index: index of next free entry on the list - * @pci_dev: PCI Device pointer - * - * see if list contains the device. - * - * Returns: 0 not found - * 1 found on list - */ -static int check_dev_on_list(struct edac_pci_device_list *list, - int free_index, struct pci_dev *dev) -{ - int i; - int rc = 0; /* Assume not found */ - unsigned short vendor=dev->vendor; - unsigned short device=dev->device; - - /* Scan the list, looking for a vendor/device match */ - for (i = 0; i < free_index; i++, list++ ) { - if ((list->vendor == vendor ) && (list->device == device )) { - rc = 1; - break; - } - } - - return rc; -} - -/* - * pci_dev parity list iterator - * Scan the PCI device list for one iteration, looking for SERRORs - * Master Parity ERRORS or Parity ERRORs on primary or secondary devices - */ -static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) -{ - struct pci_dev *dev = NULL; - - /* request for kernel access to the next PCI device, if any, - * and while we are looking at it have its reference count - * bumped until we are done with it - */ - while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - /* if whitelist exists then it has priority, so only scan - * those devices on the whitelist - */ - if (pci_whitelist_count > 0 ) { - if (check_dev_on_list(pci_whitelist, - pci_whitelist_count, dev)) - fn(dev); - } else { - /* - * if no whitelist, then check if this devices is - * blacklisted - */ - if (!check_dev_on_list(pci_blacklist, - pci_blacklist_count, dev)) - fn(dev); - } - } -} - -static void do_pci_parity_check(void) -{ - unsigned long flags; - int before_count; - - debugf3("%s()\n", __func__); - - if (!check_pci_parity) - return; - - before_count = atomic_read(&pci_parity_count); - - /* scan all PCI devices looking for a Parity Error on devices and - * bridges - */ - local_irq_save(flags); - edac_pci_dev_parity_iterator(edac_pci_dev_parity_test); - local_irq_restore(flags); - - /* Only if operator has selected panic on PCI Error */ - if (panic_on_pci_parity) { - /* If the count is different 'after' from 'before' */ - if (before_count != atomic_read(&pci_parity_count)) - panic("EDAC: PCI Parity Error"); - } -} - -static inline void clear_pci_parity_errors(void) -{ - /* Clear any PCI bus parity errors that devices initially have logged - * in their registers. - */ - edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); -} - -#else /* CONFIG_PCI */ - -static inline void do_pci_parity_check(void) -{ - /* no-op */ -} - -static inline void clear_pci_parity_errors(void) -{ - /* no-op */ -} - -#endif /* CONFIG_PCI */ /* * Iterate over all MC instances and check for ECC, et al, errors @@ -2096,10 +2110,12 @@ MODULE_DESCRIPTION("Core library routines for MC reporting"); module_param(panic_on_ue, int, 0644); MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on"); +#ifdef CONFIG_PCI module_param(check_pci_parity, int, 0644); MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on"); module_param(panic_on_pci_parity, int, 0644); MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on"); +#endif module_param(log_ue, int, 0644); MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on"); module_param(log_ce, int, 0644); diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 8d9e83909b9..bf6ab8a8d5e 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -18,7 +18,6 @@ #ifndef _EDAC_MC_H_ #define _EDAC_MC_H_ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/module.h> @@ -79,15 +78,17 @@ extern int edac_debug_level; #endif /* !CONFIG_EDAC_DEBUG */ -#define edac_xstr(s) edac_str(s) -#define edac_str(s) #s -#define EDAC_MOD_STR edac_xstr(KBUILD_BASENAME) - #define BIT(x) (1 << (x)) #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ PCI_DEVICE_ID_ ## vend ## _ ## dev +#if defined(CONFIG_X86) && defined(CONFIG_PCI) +#define dev_name(dev) pci_name(to_pci_dev(dev)) +#else +#define dev_name(dev) to_platform_device(dev)->name +#endif + /* memory devices */ enum dev_type { DEV_UNKNOWN = 0, @@ -327,10 +328,10 @@ struct mem_ctl_info { struct csrow_info *csrows; /* * FIXME - what about controllers on other busses? - IDs must be - * unique. pdev pointer should be sufficiently unique, but + * unique. dev pointer should be sufficiently unique, but * BUS:SLOT.FUNC numbers may not be unique. */ - struct pci_dev *pdev; + struct device *dev; const char *mod_name; const char *mod_ver; const char *ctl_name; @@ -353,6 +354,8 @@ struct mem_ctl_info { struct completion kobj_complete; }; +#ifdef CONFIG_PCI + /* write all or some bits in a byte-register*/ static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, u8 mask) @@ -401,14 +404,16 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset, pci_write_config_dword(pdev, offset, value); } +#endif /* CONFIG_PCI */ + #ifdef CONFIG_EDAC_DEBUG void edac_mc_dump_channel(struct channel_info *chan); void edac_mc_dump_mci(struct mem_ctl_info *mci); void edac_mc_dump_csrow(struct csrow_info *csrow); #endif /* CONFIG_EDAC_DEBUG */ -extern int edac_mc_add_mc(struct mem_ctl_info *mci); -extern struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev); +extern int edac_mc_add_mc(struct mem_ctl_info *mci,int mc_idx); +extern struct mem_ctl_info * edac_mc_del_mc(struct device *dev); extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page); extern void edac_mc_scrub_block(unsigned long page, unsigned long offset, diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index fd342163cf9..e4bb298e613 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -9,7 +9,6 @@ * by Thayne Harbaugh of Linux Networx. (http://lnxi.com) */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -17,6 +16,9 @@ #include <linux/slab.h> #include "edac_mc.h" +#define I82860_REVISION " Ver: 2.0.1 " __DATE__ +#define EDAC_MOD_STR "i82860_edac" + #define i82860_printk(level, fmt, arg...) \ edac_printk(level, "i82860", fmt, ##arg) @@ -63,17 +65,21 @@ static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code static void i82860_get_error_info(struct mem_ctl_info *mci, struct i82860_error_info *info) { + struct pci_dev *pdev; + + pdev = to_pci_dev(mci->dev); + /* * This is a mess because there is no atomic way to read all the * registers at once and the registers can transition from CE being * overwritten by UE. */ - pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts); - pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap); - pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, &info->derrsyn); - pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts2); + pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts); + pci_read_config_dword(pdev, I82860_EAP, &info->eap); + pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn); + pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts2); - pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003); + pci_write_bits16(pdev, I82860_ERRSTS, 0x0003, 0x0003); /* * If the error is the same for both reads then the first set of reads @@ -84,8 +90,8 @@ static void i82860_get_error_info(struct mem_ctl_info *mci, return; if ((info->errsts ^ info->errsts2) & 0x0003) { - pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap); - pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, + pci_read_config_dword(pdev, I82860_EAP, &info->eap); + pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn); } } @@ -127,15 +133,50 @@ static void i82860_check(struct mem_ctl_info *mci) i82860_process_error_info(mci, &info, 1); } -static int i82860_probe1(struct pci_dev *pdev, int dev_idx) +static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev) { - int rc = -ENODEV; - int index; - struct mem_ctl_info *mci = NULL; unsigned long last_cumul_size; - struct i82860_error_info discard; + u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ + u16 value; + u32 cumul_size; + struct csrow_info *csrow; + int index; + + pci_read_config_word(pdev, I82860_MCHCFG, &mchcfg_ddim); + mchcfg_ddim = mchcfg_ddim & 0x180; + last_cumul_size = 0; + + /* The group row boundary (GRA) reg values are boundary address + * for each DRAM row with a granularity of 16MB. GRA regs are + * cumulative; therefore GRA15 will contain the total memory contained + * in all eight rows. + */ + for (index = 0; index < mci->nr_csrows; index++) { + csrow = &mci->csrows[index]; + pci_read_config_word(pdev, I82860_GBA + index * 2, &value); + cumul_size = (value & I82860_GBA_MASK) << + (I82860_GBA_SHIFT - PAGE_SHIFT); + debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, + cumul_size); - u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ + if (cumul_size == last_cumul_size) + continue; /* not populated */ + + csrow->first_page = last_cumul_size; + csrow->last_page = cumul_size - 1; + csrow->nr_pages = cumul_size - last_cumul_size; + last_cumul_size = cumul_size; + csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */ + csrow->mtype = MEM_RMBS; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE; + } +} + +static int i82860_probe1(struct pci_dev *pdev, int dev_idx) +{ + struct mem_ctl_info *mci; + struct i82860_error_info discard; /* RDRAM has channels but these don't map onto the abstractions that edac uses. @@ -151,67 +192,35 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx) return -ENOMEM; debugf3("%s(): init mci\n", __func__); - mci->pdev = pdev; + mci->dev = &pdev->dev; mci->mtype_cap = MEM_FLAG_DDR; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; /* I"m not sure about this but I think that all RDRAM is SECDED */ mci->edac_cap = EDAC_FLAG_SECDED; - /* adjust FLAGS */ - mci->mod_name = EDAC_MOD_STR; - mci->mod_ver = "$Revision: 1.1.2.6 $"; + mci->mod_ver = I82860_REVISION; mci->ctl_name = i82860_devs[dev_idx].ctl_name; mci->edac_check = i82860_check; mci->ctl_page_to_phys = NULL; + i82860_init_csrows(mci, pdev); + i82860_get_error_info(mci, &discard); /* clear counters */ - pci_read_config_word(mci->pdev, I82860_MCHCFG, &mchcfg_ddim); - mchcfg_ddim = mchcfg_ddim & 0x180; - - /* - * The group row boundary (GRA) reg values are boundary address - * for each DRAM row with a granularity of 16MB. GRA regs are - * cumulative; therefore GRA15 will contain the total memory contained - * in all eight rows. + /* Here we assume that we will never see multiple instances of this + * type of memory controller. The ID is therefore hardcoded to 0. */ - for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { - u16 value; - u32 cumul_size; - struct csrow_info *csrow = &mci->csrows[index]; - - pci_read_config_word(mci->pdev, I82860_GBA + index * 2, - &value); - - cumul_size = (value & I82860_GBA_MASK) << - (I82860_GBA_SHIFT - PAGE_SHIFT); - debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, - cumul_size); - - if (cumul_size == last_cumul_size) - continue; /* not populated */ - - csrow->first_page = last_cumul_size; - csrow->last_page = cumul_size - 1; - csrow->nr_pages = cumul_size - last_cumul_size; - last_cumul_size = cumul_size; - csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */ - csrow->mtype = MEM_RMBS; - csrow->dtype = DEV_UNKNOWN; - csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE; + if (edac_mc_add_mc(mci,0)) { + debugf3("%s(): failed edac_mc_add_mc()\n", __func__); + goto fail; } - i82860_get_error_info(mci, &discard); /* clear counters */ + /* get this far and it's successful */ + debugf3("%s(): success\n", __func__); - if (edac_mc_add_mc(mci)) { - debugf3("%s(): failed edac_mc_add_mc()\n", __func__); - edac_mc_free(mci); - } else { - /* get this far and it's successful */ - debugf3("%s(): success\n", __func__); - rc = 0; - } + return 0; - return rc; +fail: + edac_mc_free(mci); + return -ENODEV; } /* returns count (>= 0), or negative on error */ @@ -240,7 +249,7 @@ static void __devexit i82860_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); diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 0aec92698f1..161fe09a6d3 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -13,7 +13,6 @@ * Note: E7210 appears same as D82875P - zhenyu.z.wang at intel.com */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -21,6 +20,9 @@ #include <linux/slab.h> #include "edac_mc.h" +#define I82875P_REVISION " Ver: 2.0.1 " __DATE__ +#define EDAC_MOD_STR "i82875p_edac" + #define i82875p_printk(level, fmt, arg...) \ edac_printk(level, "i82875p", fmt, ##arg) @@ -185,18 +187,22 @@ static int i82875p_registered = 1; static void i82875p_get_error_info(struct mem_ctl_info *mci, struct i82875p_error_info *info) { + struct pci_dev *pdev; + + pdev = to_pci_dev(mci->dev); + /* * This is a mess because there is no atomic way to read all the * registers at once and the registers can transition from CE being * overwritten by UE. */ - pci_read_config_word(mci->pdev, I82875P_ERRSTS, &info->errsts); - pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap); - pci_read_config_byte(mci->pdev, I82875P_DES, &info->des); - pci_read_config_byte(mci->pdev, I82875P_DERRSYN, &info->derrsyn); - pci_read_config_word(mci->pdev, I82875P_ERRSTS, &info->errsts2); + pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts); + pci_read_config_dword(pdev, I82875P_EAP, &info->eap); + pci_read_config_byte(pdev, I82875P_DES, &info->des); + pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn); + pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2); - pci_write_bits16(mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081); + pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081); /* * If the error is the same then we can for both reads then @@ -208,9 +214,9 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci, return; if ((info->errsts ^ info->errsts2) & 0x0081) { - pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap); - pci_read_config_byte(mci->pdev, I82875P_DES, &info->des); - pci_read_config_byte(mci->pdev, I82875P_DERRSYN, + pci_read_config_dword(pdev, I82875P_EAP, &info->eap); + pci_read_config_byte(pdev, I82875P_DES, &info->des); + pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn); } } @@ -259,116 +265,109 @@ static void i82875p_check(struct mem_ctl_info *mci) extern int pci_proc_attach_device(struct pci_dev *); #endif -static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) +/* Return 0 on success or 1 on failure. */ +static int i82875p_setup_overfl_dev(struct pci_dev *pdev, + struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window) { - int rc = -ENODEV; - int index; - struct mem_ctl_info *mci = NULL; - struct i82875p_pvt *pvt = NULL; - unsigned long last_cumul_size; - struct pci_dev *ovrfl_pdev; - void __iomem *ovrfl_window = NULL; - u32 drc; - u32 drc_chan; /* Number of channels 0=1chan,1=2chan */ - u32 nr_chans; - u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ - struct i82875p_error_info discard; + struct pci_dev *dev; + void __iomem *window; - debugf0("%s()\n", __func__); - ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); + *ovrfl_pdev = NULL; + *ovrfl_window = NULL; + dev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); - if (!ovrfl_pdev) { - /* - * Intel tells BIOS developers to hide device 6 which + if (dev == NULL) { + /* Intel tells BIOS developers to hide device 6 which * configures the overflow device access containing * the DRBs - this is where we expose device 6. * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm */ pci_write_bits8(pdev, 0xf4, 0x2, 0x2); - ovrfl_pdev = - pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0)); + dev = pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0)); - if (!ovrfl_pdev) - return -ENODEV; + if (dev == NULL) + return 1; } + *ovrfl_pdev = dev; + #ifdef CONFIG_PROC_FS - if (!ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) { - i82875p_printk(KERN_ERR, - "%s(): Failed to attach overflow device\n", __func__); - return -ENODEV; + if ((dev->procent == NULL) && pci_proc_attach_device(dev)) { + i82875p_printk(KERN_ERR, "%s(): Failed to attach overflow " + "device\n", __func__); + return 1; } -#endif - /* CONFIG_PROC_FS */ - if (pci_enable_device(ovrfl_pdev)) { - i82875p_printk(KERN_ERR, - "%s(): Failed to enable overflow device\n", __func__); - return -ENODEV; +#endif /* CONFIG_PROC_FS */ + if (pci_enable_device(dev)) { + i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow " + "device\n", __func__); + return 1; } - if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) { + if (pci_request_regions(dev, pci_name(dev))) { #ifdef CORRECT_BIOS goto fail0; #endif } /* cache is irrelevant for PCI bus reads/writes */ - ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0), - pci_resource_len(ovrfl_pdev, 0)); + window = ioremap_nocache(pci_resource_start(dev, 0), + pci_resource_len(dev, 0)); - if (!ovrfl_window) { + if (window == NULL) { i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n", - __func__); + __func__); goto fail1; } - /* need to find out the number of channels */ - drc = readl(ovrfl_window + I82875P_DRC); - drc_chan = ((drc >> 21) & 0x1); - nr_chans = drc_chan + 1; + *ovrfl_window = window; + return 0; - drc_ddim = (drc >> 18) & 0x1; - mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans), - nr_chans); +fail1: + pci_release_regions(dev); - if (!mci) { - rc = -ENOMEM; - goto fail2; - } +#ifdef CORRECT_BIOS +fail0: + pci_disable_device(dev); +#endif + /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */ + return 1; +} - debugf3("%s(): init mci\n", __func__); - mci->pdev = pdev; - mci->mtype_cap = MEM_FLAG_DDR; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; - mci->edac_cap = EDAC_FLAG_UNKNOWN; - /* adjust FLAGS */ - mci->mod_name = EDAC_MOD_STR; - mci->mod_ver = "$Revision: 1.5.2.11 $"; - mci->ctl_name = i82875p_devs[dev_idx].ctl_name; - mci->edac_check = i82875p_check; - mci->ctl_page_to_phys = NULL; - debugf3("%s(): init pvt\n", __func__); - pvt = (struct i82875p_pvt *) mci->pvt_info; - pvt->ovrfl_pdev = ovrfl_pdev; - pvt->ovrfl_window = ovrfl_window; +/* Return 1 if dual channel mode is active. Else return 0. */ +static inline int dual_channel_active(u32 drc) +{ + return (drc >> 21) & 0x1; +} - /* - * The dram row boundary (DRB) reg values are boundary address + +static void i82875p_init_csrows(struct mem_ctl_info *mci, + struct pci_dev *pdev, void __iomem *ovrfl_window, u32 drc) +{ + struct csrow_info *csrow; + unsigned long last_cumul_size; + u8 value; + u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ + u32 cumul_size; + int index; + + drc_ddim = (drc >> 18) & 0x1; + last_cumul_size = 0; + + /* The dram row boundary (DRB) reg values are boundary address * for each DRAM row with a granularity of 32 or 64MB (single/dual * channel operation). DRB regs are cumulative; therefore DRB7 will * contain the total memory contained in all eight rows. */ - for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { - u8 value; - u32 cumul_size; - struct csrow_info *csrow = &mci->csrows[index]; + + for (index = 0; index < mci->nr_csrows; index++) { + csrow = &mci->csrows[index]; value = readb(ovrfl_window + I82875P_DRB + index); cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT); debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, cumul_size); - if (cumul_size == last_cumul_size) continue; /* not populated */ @@ -376,35 +375,75 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) csrow->last_page = cumul_size - 1; csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; - csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ + csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ csrow->mtype = MEM_DDR; csrow->dtype = DEV_UNKNOWN; csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE; } +} + +static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) +{ + int rc = -ENODEV; + struct mem_ctl_info *mci; + struct i82875p_pvt *pvt; + struct pci_dev *ovrfl_pdev; + void __iomem *ovrfl_window; + u32 drc; + u32 nr_chans; + struct i82875p_error_info discard; + + debugf0("%s()\n", __func__); + ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); + + if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window)) + return -ENODEV; + drc = readl(ovrfl_window + I82875P_DRC); + nr_chans = dual_channel_active(drc) + 1; + mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans), + nr_chans); + + if (!mci) { + rc = -ENOMEM; + goto fail0; + } + debugf3("%s(): init mci\n", __func__); + mci->dev = &pdev->dev; + mci->mtype_cap = MEM_FLAG_DDR; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_UNKNOWN; + mci->mod_name = EDAC_MOD_STR; + mci->mod_ver = I82875P_REVISION; + mci->ctl_name = i82875p_devs[dev_idx].ctl_name; + mci->edac_check = i82875p_check; + mci->ctl_page_to_phys = NULL; + debugf3("%s(): init pvt\n", __func__); + pvt = (struct i82875p_pvt *) mci->pvt_info; + pvt->ovrfl_pdev = ovrfl_pdev; + pvt->ovrfl_window = ovrfl_window; + i82875p_init_csrows(mci, pdev, ovrfl_window, drc); i82875p_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 fail3; + goto fail1; } /* get this far and it's successful */ debugf3("%s(): success\n", __func__); return 0; -fail3: +fail1: edac_mc_free(mci); -fail2: +fail0: iounmap(ovrfl_window); - -fail1: pci_release_regions(ovrfl_pdev); -#ifdef CORRECT_BIOS -fail0: -#endif pci_disable_device(ovrfl_pdev); /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */ return rc; @@ -437,7 +476,7 @@ static void __devexit i82875p_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; pvt = (struct i82875p_pvt *) mci->pvt_info; diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index 2c29fafe67c..a49cf0a3939 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -15,7 +15,6 @@ * references to this document given in [] */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -23,6 +22,9 @@ #include <linux/slab.h> #include "edac_mc.h" +#define R82600_REVISION " Ver: 2.0.1 " __DATE__ +#define EDAC_MOD_STR "r82600_edac" + #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); |