summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/drivers/edac/edac.txt16
-rw-r--r--drivers/edac/edac_mc.c55
-rw-r--r--drivers/edac/edac_mc.h12
3 files changed, 82 insertions, 1 deletions
diff --git a/Documentation/drivers/edac/edac.txt b/Documentation/drivers/edac/edac.txt
index 7b3d969d296..3c5a9e4297b 100644
--- a/Documentation/drivers/edac/edac.txt
+++ b/Documentation/drivers/edac/edac.txt
@@ -339,7 +339,21 @@ Device Symlink:
'device'
- Symlink to the memory controller device
+ Symlink to the memory controller device.
+
+Sdram memory scrubbing rate:
+
+ 'sdram_scrub_rate'
+
+ Read/Write attribute file that controls memory scrubbing. The scrubbing
+ rate is set by writing a minimum bandwith in bytes/sec to the attribute
+ file. The rate will be translated to an internal value that gives at
+ least the specified rate.
+
+ Reading the file will return the actual scrubbing rate employed.
+
+ If configuration fails or memory scrubbing is not implemented, the value
+ of the attribute file will be -1.
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 1b4fc922180..1df8c0c5d40 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -927,6 +927,57 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
return count;
}
+/* memory scrubbing */
+static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ u32 bandwidth = -1;
+
+ if (mci->set_sdram_scrub_rate) {
+
+ memctrl_int_store(&bandwidth, data, count);
+
+ if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set successfully, applied: %d\n",
+ bandwidth);
+ } else {
+ /* FIXME: error codes maybe? */
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set FAILED, could not apply: %d\n",
+ bandwidth);
+ }
+ } else {
+ /* FIXME: produce "not implemented" ERROR for user-side. */
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrubbing 'set'control is not implemented!\n");
+ }
+ return count;
+}
+
+static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
+{
+ u32 bandwidth = -1;
+
+ if (mci->get_sdram_scrub_rate) {
+ if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate successfully, fetched: %d\n",
+ bandwidth);
+ } else {
+ /* FIXME: error codes maybe? */
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate fetch FAILED, got: %d\n",
+ bandwidth);
+ }
+ } else {
+ /* FIXME: produce "not implemented" ERROR for user-side. */
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrubbing 'get' control is not implemented!\n");
+ }
+ return sprintf(data, "%d\n", bandwidth);
+}
+
/* default attribute files for the MCI object */
static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
{
@@ -1033,6 +1084,9 @@ MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
+/* memory scrubber attribute file */
+MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store);
+
static struct mcidev_attribute *mci_attr[] = {
&mci_attr_reset_counters,
&mci_attr_mc_name,
@@ -1042,6 +1096,7 @@ static struct mcidev_attribute *mci_attr[] = {
&mci_attr_ce_noinfo_count,
&mci_attr_ue_count,
&mci_attr_ce_count,
+ &mci_attr_sdram_scrub_rate,
NULL
};
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h
index a1cfd4e3c97..c41986a9ed5 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_mc.h
@@ -315,6 +315,18 @@ struct mem_ctl_info {
unsigned long scrub_cap; /* chipset scrub capabilities */
enum scrub_type scrub_mode; /* current scrub mode */
+ /* Translates sdram memory scrub rate given in bytes/sec to the
+ internal representation and configures whatever else needs
+ to be configured.
+ */
+ int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+
+ /* Get the current sdram memory scrub rate from the internal
+ representation and converts it to the closest matching
+ bandwith in bytes/sec.
+ */
+ int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+
/* pointer to edac checking routine */
void (*edac_check) (struct mem_ctl_info * mci);
/*