aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/edac/edac_mc.c120
-rw-r--r--drivers/edac/edac_mc.h16
2 files changed, 130 insertions, 6 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 1df8c0c5d40..7b622300d0e 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -1497,11 +1497,11 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
/* set load time so that error rate can be tracked */
mci->start_time = jiffies;
- if (edac_create_sysfs_mci_device(mci)) {
- edac_mc_printk(mci, KERN_WARNING,
+ if (edac_create_sysfs_mci_device(mci)) {
+ edac_mc_printk(mci, KERN_WARNING,
"failed to create sysfs device\n");
- goto fail1;
- }
+ goto fail1;
+ }
/* Report action taken */
edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n",
@@ -1758,6 +1758,116 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
+/*************************************************************
+ * On Fully Buffered DIMM modules, this help function is
+ * called to process UE events
+ */
+void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channela,
+ unsigned int channelb,
+ char *msg)
+{
+ int len = EDAC_MC_LABEL_LEN * 4;
+ char labels[len + 1];
+ char *pos = labels;
+ int chars;
+
+ if (csrow >= mci->nr_csrows) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: row out of range (%d >= %d)\n",
+ csrow, mci->nr_csrows);
+ edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+
+ if (channela >= mci->csrows[csrow].nr_channels) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: channel-a out of range "
+ "(%d >= %d)\n",
+ channela, mci->csrows[csrow].nr_channels);
+ edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+
+ if (channelb >= mci->csrows[csrow].nr_channels) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: channel-b out of range "
+ "(%d >= %d)\n",
+ channelb, mci->csrows[csrow].nr_channels);
+ edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+
+ mci->ue_count++;
+ mci->csrows[csrow].ue_count++;
+
+ /* Generate the DIMM labels from the specified channels */
+ chars = snprintf(pos, len + 1, "%s",
+ mci->csrows[csrow].channels[channela].label);
+ len -= chars; pos += chars;
+ chars = snprintf(pos, len + 1, "-%s",
+ mci->csrows[csrow].channels[channelb].label);
+
+ if (log_ue)
+ edac_mc_printk(mci, KERN_EMERG,
+ "UE row %d, channel-a= %d channel-b= %d "
+ "labels \"%s\": %s\n", csrow, channela, channelb,
+ labels, msg);
+
+ if (panic_on_ue)
+ panic("UE row %d, channel-a= %d channel-b= %d "
+ "labels \"%s\": %s\n", csrow, channela,
+ channelb, labels, msg);
+}
+EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
+
+/*************************************************************
+ * On Fully Buffered DIMM modules, this help function is
+ * called to process CE events
+ */
+void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channel,
+ char *msg)
+{
+
+ /* Ensure boundary values */
+ if (csrow >= mci->nr_csrows) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: row out of range (%d >= %d)\n",
+ csrow, mci->nr_csrows);
+ edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+ if (channel >= mci->csrows[csrow].nr_channels) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: channel out of range (%d >= %d)\n",
+ channel, mci->csrows[csrow].nr_channels);
+ edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+
+ if (log_ce)
+ /* FIXME - put in DIMM location */
+ edac_mc_printk(mci, KERN_WARNING,
+ "CE row %d, channel %d, label \"%s\": %s\n",
+ csrow, channel,
+ mci->csrows[csrow].channels[channel].label,
+ msg);
+
+ mci->ce_count++;
+ mci->csrows[csrow].ce_count++;
+ mci->csrows[csrow].channels[channel].ce_count++;
+}
+EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
+
+
/*
* Iterate over all MC instances and check for ECC, et al, errors
*/
@@ -1861,7 +1971,7 @@ static void __exit edac_mc_exit(void)
debugf0("%s()\n", __func__);
kthread_stop(edac_thread);
- /* tear down the sysfs device */
+ /* tear down the sysfs device */
edac_sysfs_memctrl_teardown();
edac_sysfs_pci_teardown();
}
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h
index c41986a9ed5..713444cc410 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_mc.h
@@ -123,7 +123,9 @@ enum mem_type {
MEM_RDR, /* Registered single data rate SDRAM */
MEM_DDR, /* Double data rate SDRAM */
MEM_RDDR, /* Registered Double data rate SDRAM */
- MEM_RMBS /* Rambus DRAM */
+ MEM_RMBS, /* Rambus DRAM */
+ MEM_DDR2, /* DDR2 RAM */
+ MEM_FB_DDR2, /* fully buffered DDR2 */
};
#define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
@@ -137,6 +139,8 @@ enum mem_type {
#define MEM_FLAG_DDR BIT(MEM_DDR)
#define MEM_FLAG_RDDR BIT(MEM_RDDR)
#define MEM_FLAG_RMBS BIT(MEM_RMBS)
+#define MEM_FLAG_DDR2 BIT(MEM_DDR2)
+#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
/* chipset Error Detection and Correction capabilities and mode */
enum edac_type {
@@ -329,6 +333,7 @@ struct mem_ctl_info {
/* pointer to edac checking routine */
void (*edac_check) (struct mem_ctl_info * mci);
+
/*
* Remaps memory pages: controller pages to physical pages.
* For most MC's, this will be NULL.
@@ -453,6 +458,15 @@ extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
int row, const char *msg);
extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
const char *msg);
+extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channel0,
+ unsigned int channel1,
+ char *msg);
+extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channel,
+ char *msg);
/*
* This kmalloc's and initializes all the structures.