diff options
-rw-r--r-- | Documentation/drivers/edac/edac.txt | 16 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 55 | ||||
-rw-r--r-- | drivers/edac/edac_mc.h | 12 |
3 files changed, 82 insertions, 1 deletions
diff --git a/Documentation/drivers/edac/edac.txt b/Documentation/drivers/edac/edac.txt index 7b3d969d2964..3c5a9e4297b4 100644 --- a/Documentation/drivers/edac/edac.txt +++ b/Documentation/drivers/edac/edac.txt | |||
@@ -339,7 +339,21 @@ Device Symlink: | |||
339 | 339 | ||
340 | 'device' | 340 | 'device' |
341 | 341 | ||
342 | Symlink to the memory controller device | 342 | Symlink to the memory controller device. |
343 | |||
344 | Sdram memory scrubbing rate: | ||
345 | |||
346 | 'sdram_scrub_rate' | ||
347 | |||
348 | Read/Write attribute file that controls memory scrubbing. The scrubbing | ||
349 | rate is set by writing a minimum bandwith in bytes/sec to the attribute | ||
350 | file. The rate will be translated to an internal value that gives at | ||
351 | least the specified rate. | ||
352 | |||
353 | Reading the file will return the actual scrubbing rate employed. | ||
354 | |||
355 | If configuration fails or memory scrubbing is not implemented, the value | ||
356 | of the attribute file will be -1. | ||
343 | 357 | ||
344 | 358 | ||
345 | 359 | ||
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 1b4fc9221803..1df8c0c5d40a 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, | |||
927 | return count; | 927 | return count; |
928 | } | 928 | } |
929 | 929 | ||
930 | /* memory scrubbing */ | ||
931 | static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci, | ||
932 | const char *data, size_t count) | ||
933 | { | ||
934 | u32 bandwidth = -1; | ||
935 | |||
936 | if (mci->set_sdram_scrub_rate) { | ||
937 | |||
938 | memctrl_int_store(&bandwidth, data, count); | ||
939 | |||
940 | if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) { | ||
941 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
942 | "Scrub rate set successfully, applied: %d\n", | ||
943 | bandwidth); | ||
944 | } else { | ||
945 | /* FIXME: error codes maybe? */ | ||
946 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
947 | "Scrub rate set FAILED, could not apply: %d\n", | ||
948 | bandwidth); | ||
949 | } | ||
950 | } else { | ||
951 | /* FIXME: produce "not implemented" ERROR for user-side. */ | ||
952 | edac_printk(KERN_WARNING, EDAC_MC, | ||
953 | "Memory scrubbing 'set'control is not implemented!\n"); | ||
954 | } | ||
955 | return count; | ||
956 | } | ||
957 | |||
958 | static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) | ||
959 | { | ||
960 | u32 bandwidth = -1; | ||
961 | |||
962 | if (mci->get_sdram_scrub_rate) { | ||
963 | if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) { | ||
964 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
965 | "Scrub rate successfully, fetched: %d\n", | ||
966 | bandwidth); | ||
967 | } else { | ||
968 | /* FIXME: error codes maybe? */ | ||
969 | edac_printk(KERN_DEBUG, EDAC_MC, | ||
970 | "Scrub rate fetch FAILED, got: %d\n", | ||
971 | bandwidth); | ||
972 | } | ||
973 | } else { | ||
974 | /* FIXME: produce "not implemented" ERROR for user-side. */ | ||
975 | edac_printk(KERN_WARNING, EDAC_MC, | ||
976 | "Memory scrubbing 'get' control is not implemented!\n"); | ||
977 | } | ||
978 | return sprintf(data, "%d\n", bandwidth); | ||
979 | } | ||
980 | |||
930 | /* default attribute files for the MCI object */ | 981 | /* default attribute files for the MCI object */ |
931 | static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) | 982 | static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) |
932 | { | 983 | { |
@@ -1033,6 +1084,9 @@ MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL); | |||
1033 | MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL); | 1084 | MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL); |
1034 | MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); | 1085 | MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL); |
1035 | 1086 | ||
1087 | /* memory scrubber attribute file */ | ||
1088 | MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store); | ||
1089 | |||
1036 | static struct mcidev_attribute *mci_attr[] = { | 1090 | static struct mcidev_attribute *mci_attr[] = { |
1037 | &mci_attr_reset_counters, | 1091 | &mci_attr_reset_counters, |
1038 | &mci_attr_mc_name, | 1092 | &mci_attr_mc_name, |
@@ -1042,6 +1096,7 @@ static struct mcidev_attribute *mci_attr[] = { | |||
1042 | &mci_attr_ce_noinfo_count, | 1096 | &mci_attr_ce_noinfo_count, |
1043 | &mci_attr_ue_count, | 1097 | &mci_attr_ue_count, |
1044 | &mci_attr_ce_count, | 1098 | &mci_attr_ce_count, |
1099 | &mci_attr_sdram_scrub_rate, | ||
1045 | NULL | 1100 | NULL |
1046 | }; | 1101 | }; |
1047 | 1102 | ||
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index a1cfd4e3c97d..c41986a9ed5b 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h | |||
@@ -315,6 +315,18 @@ struct mem_ctl_info { | |||
315 | unsigned long scrub_cap; /* chipset scrub capabilities */ | 315 | unsigned long scrub_cap; /* chipset scrub capabilities */ |
316 | enum scrub_type scrub_mode; /* current scrub mode */ | 316 | enum scrub_type scrub_mode; /* current scrub mode */ |
317 | 317 | ||
318 | /* Translates sdram memory scrub rate given in bytes/sec to the | ||
319 | internal representation and configures whatever else needs | ||
320 | to be configured. | ||
321 | */ | ||
322 | int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw); | ||
323 | |||
324 | /* Get the current sdram memory scrub rate from the internal | ||
325 | representation and converts it to the closest matching | ||
326 | bandwith in bytes/sec. | ||
327 | */ | ||
328 | int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw); | ||
329 | |||
318 | /* pointer to edac checking routine */ | 330 | /* pointer to edac checking routine */ |
319 | void (*edac_check) (struct mem_ctl_info * mci); | 331 | void (*edac_check) (struct mem_ctl_info * mci); |
320 | /* | 332 | /* |