X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=drivers%2Fedac%2Fi82443bxgx_edac.c;h=c5305e3ee4346932b44cc73074cb6718bd3a38ad;hb=0b0588d42b2774734b51525fe6550d77f8ea9bc0;hp=a94bb38ea8e498888ec662d6c0327f1bea121954;hpb=20bcb7a81dee21bfa3408f03f46b2891c9b5c84b;p=linux-2.6-omap-h63xx.git diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index a94bb38ea8e..c5305e3ee43 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c @@ -29,13 +29,13 @@ #include +#include #include "edac_core.h" #define I82443_REVISION "0.1" #define EDAC_MOD_STR "i82443bxgx_edac" - /* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory * rows" "The 82443BX supports multiple-bit error detection and @@ -61,67 +61,62 @@ #define I82443BXGX_NR_CHANS 1 #define I82443BXGX_NR_DIMMS 4 - - /* 82443 PCI Device 0 */ -#define I82443BXGX_NBXCFG 0x50 /* 32bit register starting at this PCI - * config space offset */ -#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24 /* Array of bits, zero if - * row is non-ECC */ -#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12 /* 2 bits,00=100MHz,10=66 MHz */ - -#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7 /* 2 bits: */ -#define I82443BXGX_NBXCFG_INTEGRITY_NONE 0x0 /* 00 = Non-ECC */ -#define I82443BXGX_NBXCFG_INTEGRITY_EC 0x1 /* 01 = EC (only) */ -#define I82443BXGX_NBXCFG_INTEGRITY_ECC 0x2 /* 10 = ECC */ -#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB 0x3 /* 11 = ECC + HW Scrub */ +#define I82443BXGX_NBXCFG 0x50 /* 32bit register starting at this PCI + * config space offset */ +#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24 /* Array of bits, zero if + * row is non-ECC */ +#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12 /* 2 bits,00=100MHz,10=66 MHz */ + +#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7 /* 2 bits: */ +#define I82443BXGX_NBXCFG_INTEGRITY_NONE 0x0 /* 00 = Non-ECC */ +#define I82443BXGX_NBXCFG_INTEGRITY_EC 0x1 /* 01 = EC (only) */ +#define I82443BXGX_NBXCFG_INTEGRITY_ECC 0x2 /* 10 = ECC */ +#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB 0x3 /* 11 = ECC + HW Scrub */ #define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE 6 - /* 82443 PCI Device 0 */ -#define I82443BXGX_EAP 0x80 /* 32bit register starting at this PCI - * config space offset, Error Address - * Pointer Register */ -#define I82443BXGX_EAP_OFFSET_EAP 12 /* High 20 bits of error address */ -#define I82443BXGX_EAP_OFFSET_MBE BIT(1) /* Err at EAP was multi-bit (W1TC) */ -#define I82443BXGX_EAP_OFFSET_SBE BIT(0) /* Err at EAP was single-bit (W1TC)*/ - -#define I82443BXGX_ERRCMD 0x90 /* 8bit register starting at this PCI +#define I82443BXGX_EAP 0x80 /* 32bit register starting at this PCI + * config space offset, Error Address + * Pointer Register */ +#define I82443BXGX_EAP_OFFSET_EAP 12 /* High 20 bits of error address */ +#define I82443BXGX_EAP_OFFSET_MBE BIT(1) /* Err at EAP was multi-bit (W1TC) */ +#define I82443BXGX_EAP_OFFSET_SBE BIT(0) /* Err at EAP was single-bit (W1TC) */ + +#define I82443BXGX_ERRCMD 0x90 /* 8bit register starting at this PCI * config space offset. */ -#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1) /* 1 = enable */ -#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0) /* 1 = enable */ +#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1) /* 1 = enable */ +#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0) /* 1 = enable */ -#define I82443BXGX_ERRSTS 0x91 /* 16bit register starting at this PCI +#define I82443BXGX_ERRSTS 0x91 /* 16bit register starting at this PCI * config space offset. */ -#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5 /* 3 bits - first err row multibit */ -#define I82443BXGX_ERRSTS_OFFSET_MEF BIT(4) /* 1 = MBE occurred */ -#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1 /* 3 bits - first err row singlebit */ -#define I82443BXGX_ERRSTS_OFFSET_SEF BIT(0) /* 1 = SBE occurred */ +#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5 /* 3 bits - first err row multibit */ +#define I82443BXGX_ERRSTS_OFFSET_MEF BIT(4) /* 1 = MBE occurred */ +#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1 /* 3 bits - first err row singlebit */ +#define I82443BXGX_ERRSTS_OFFSET_SEF BIT(0) /* 1 = SBE occurred */ - -#define I82443BXGX_DRAMC 0x57 /* 8bit register starting at this PCI - * config space offset. */ -#define I82443BXGX_DRAMC_OFFSET_DT 3 /* 2 bits, DRAM Type */ -#define I82443BXGX_DRAMC_DRAM_IS_EDO 0 /* 00 = EDO */ +#define I82443BXGX_DRAMC 0x57 /* 8bit register starting at this PCI + * config space offset. */ +#define I82443BXGX_DRAMC_OFFSET_DT 3 /* 2 bits, DRAM Type */ +#define I82443BXGX_DRAMC_DRAM_IS_EDO 0 /* 00 = EDO */ #define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1 /* 01 = SDRAM */ -#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2 /* 10 = Registered SDRAM */ - - -#define I82443BXGX_DRB 0x60 /* 8x 8bit registers starting at this PCI - * config space offset. */ +#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2 /* 10 = Registered SDRAM */ +#define I82443BXGX_DRB 0x60 /* 8x 8bit registers starting at this PCI + * config space offset. */ /* FIXME - don't poll when ECC disabled? */ - struct i82443bxgx_edacmc_error_info { u32 eap; }; +static struct edac_pci_ctl_info *i82443bxgx_pci; -static void i82443bxgx_edacmc_get_error_info (struct mem_ctl_info *mci, - struct i82443bxgx_edacmc_error_info *info) +static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci, + struct i82443bxgx_edacmc_error_info + *info) { struct pci_dev *pdev; pdev = to_pci_dev(mci->dev); @@ -139,9 +134,10 @@ static void i82443bxgx_edacmc_get_error_info (struct mem_ctl_info *mci, I82443BXGX_EAP_OFFSET_MBE); } - -static int i82443bxgx_edacmc_process_error_info (struct mem_ctl_info *mci, - struct i82443bxgx_edacmc_error_info *info, int handle_errors) +static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci, + struct + i82443bxgx_edacmc_error_info + *info, int handle_errors) { int error_found = 0; u32 eapaddr, page, pageoffset; @@ -152,31 +148,27 @@ static int i82443bxgx_edacmc_process_error_info (struct mem_ctl_info *mci, page = eapaddr >> PAGE_SHIFT; pageoffset = eapaddr - (page << PAGE_SHIFT); - if (info->eap & I82443BXGX_EAP_OFFSET_SBE) { + if (info->eap & I82443BXGX_EAP_OFFSET_SBE) { error_found = 1; if (handle_errors) - edac_mc_handle_ce( - mci, page, pageoffset, - /* 440BX/GX don't make syndrome information available */ - 0, - edac_mc_find_csrow_by_page(mci, page), - 0, /* channel */ + edac_mc_handle_ce(mci, page, pageoffset, + /* 440BX/GX don't make syndrome information + * available */ + 0, edac_mc_find_csrow_by_page(mci, page), 0, mci->ctl_name); } - if (info->eap & I82443BXGX_EAP_OFFSET_MBE) { + if (info->eap & I82443BXGX_EAP_OFFSET_MBE) { error_found = 1; if (handle_errors) - edac_mc_handle_ue( - mci, page, pageoffset, - edac_mc_find_csrow_by_page(mci, page), - mci->ctl_name); + edac_mc_handle_ue(mci, page, pageoffset, + edac_mc_find_csrow_by_page(mci, page), + mci->ctl_name); } return error_found; } - static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci) { struct i82443bxgx_edacmc_error_info info; @@ -186,11 +178,10 @@ static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci) i82443bxgx_edacmc_process_error_info(mci, &info, 1); } - static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, - struct pci_dev *pdev, - enum edac_type edac_mode, - enum mem_type mtype) + struct pci_dev *pdev, + enum edac_type edac_mode, + enum mem_type mtype) { struct csrow_info *csrow; int index; @@ -233,8 +224,7 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, } } - -static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) +static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; u8 dramc; @@ -245,11 +235,12 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) debugf0("MC: " __FILE__ ": %s()\n", __func__); /* Something is really hosed if PCI config space reads from - the MC aren't working. */ + * the MC aren't working. + */ if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg)) return -EIO; - mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS); + mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0); if (mci == NULL) return -ENOMEM; @@ -260,7 +251,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc); switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) { - case I82443BXGX_DRAMC_DRAM_IS_EDO: + case I82443BXGX_DRAMC_DRAM_IS_EDO: mtype = MEM_EDO; break; case I82443BXGX_DRAMC_DRAM_IS_SDRAM: @@ -270,7 +261,8 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) mtype = MEM_RDR; break; default: - debugf0("Unknown/reserved DRAM type value in DRAMC register!\n"); + debugf0("Unknown/reserved DRAM type value " + "in DRAMC register!\n"); mtype = -MEM_UNKNOWN; } @@ -282,13 +274,12 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) mci->scrub_cap = SCRUB_FLAG_HW_SRC; pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg); ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) & - (BIT(0) | BIT(1))); + (BIT(0) | BIT(1))); mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB) - ? SCRUB_HW_SRC - : SCRUB_NONE; + ? SCRUB_HW_SRC : SCRUB_NONE; - switch(ecc_mode) { + switch (ecc_mode) { case I82443BXGX_NBXCFG_INTEGRITY_NONE: edac_mode = EDAC_NONE; break; @@ -300,8 +291,8 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) edac_mode = EDAC_SECDED; break; default: - debugf0("%s(): Unknown/reserved ECC state in NBXCFG register!\n", - __func__); + debugf0("%s(): Unknown/reserved ECC state " + "in NBXCFG register!\n", __func__); edac_mode = EDAC_UNKNOWN; break; } @@ -312,20 +303,34 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) * here, or we get "phantom" errors occuring at module-load * time. */ pci_write_bits32(pdev, I82443BXGX_EAP, - (I82443BXGX_EAP_OFFSET_SBE | I82443BXGX_EAP_OFFSET_MBE), - (I82443BXGX_EAP_OFFSET_SBE | I82443BXGX_EAP_OFFSET_MBE)); + (I82443BXGX_EAP_OFFSET_SBE | + I82443BXGX_EAP_OFFSET_MBE), + (I82443BXGX_EAP_OFFSET_SBE | + I82443BXGX_EAP_OFFSET_MBE)); mci->mod_name = EDAC_MOD_STR; mci->mod_ver = I82443_REVISION; mci->ctl_name = "I82443BXGX"; + mci->dev_name = pci_name(pdev); mci->edac_check = i82443bxgx_edacmc_check; mci->ctl_page_to_phys = NULL; - if (edac_mc_add_mc(mci, 0)) { + if (edac_mc_add_mc(mci)) { debugf3("%s(): failed edac_mc_add_mc()\n", __func__); goto fail; } + /* allocating generic PCI control info */ + i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); + if (!i82443bxgx_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("MC: " __FILE__ ": %s(): success\n", __func__); return 0; @@ -333,32 +338,35 @@ fail: edac_mc_free(mci); return -ENODEV; } + EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1); /* returns count (>= 0), or negative on error */ static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) + const struct pci_device_id *ent) { debugf0("MC: " __FILE__ ": %s()\n", __func__); /* don't need to call pci_device_enable() */ - return i82443bxgx_edacmc_probe1(pdev, ent->driver_data); + return i82443bxgx_edacmc_probe1(pdev, ent->driver_data); } - static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev) { struct mem_ctl_info *mci; debugf0(__FILE__ ": %s()\n", __func__); - if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL ) + if (i82443bxgx_pci) + edac_pci_release_generic_ctl(i82443bxgx_pci); + + if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) return; edac_mc_free(mci); } -EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one); +EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one); static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)}, @@ -370,7 +378,6 @@ static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl); - static struct pci_driver i82443bxgx_edacmc_driver = { .name = EDAC_MOD_STR, .probe = i82443bxgx_edacmc_init_one, @@ -378,23 +385,25 @@ static struct pci_driver i82443bxgx_edacmc_driver = { .id_table = i82443bxgx_pci_tbl, }; - static int __init i82443bxgx_edacmc_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&i82443bxgx_edacmc_driver); } - static void __exit i82443bxgx_edacmc_exit(void) { pci_unregister_driver(&i82443bxgx_edacmc_driver); } - module_init(i82443bxgx_edacmc_init); module_exit(i82443bxgx_edacmc_exit); - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Small - WPAD"); MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");