aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorAdrian Hunter <ext-adrian.hunter@nokia.com>2007-03-19 06:40:41 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-04-17 13:55:29 -0400
commit57aa6b545f6f772dd317ccd29bdada999b16a13d (patch)
treeefed75ea30b11cec3deaeb8025381f68a8d1ff42 /drivers/mtd
parent514087e74fb401a6621e8c836f4eaab87c269f24 (diff)
[MTD] nandsim: Enhance nandsim optionally to report wear information
A new module parameter 'rptwear' specifies how many erases between reporting wear information. Zero means never. Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/nandsim.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 05b42077d22f..1a44ef63c8d1 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -99,6 +99,7 @@ static char *weakblocks = NULL;
99static char *weakpages = NULL; 99static char *weakpages = NULL;
100static unsigned int bitflips = 0; 100static unsigned int bitflips = 0;
101static char *gravepages = NULL; 101static char *gravepages = NULL;
102static unsigned int rptwear = 0;
102 103
103module_param(first_id_byte, uint, 0400); 104module_param(first_id_byte, uint, 0400);
104module_param(second_id_byte, uint, 0400); 105module_param(second_id_byte, uint, 0400);
@@ -119,6 +120,7 @@ module_param(weakblocks, charp, 0400);
119module_param(weakpages, charp, 0400); 120module_param(weakpages, charp, 0400);
120module_param(bitflips, uint, 0400); 121module_param(bitflips, uint, 0400);
121module_param(gravepages, charp, 0400); 122module_param(gravepages, charp, 0400);
123module_param(rptwear, uint, 0400);
122 124
123MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); 125MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");
124MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); 126MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
@@ -146,6 +148,7 @@ MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (z
146MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" 148MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]"
147 " separated by commas e.g. 1401:2 means page 1401" 149 " separated by commas e.g. 1401:2 means page 1401"
148 " can be read only twice before failing"); 150 " can be read only twice before failing");
151MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if not zero");
149 152
150/* The largest possible page size */ 153/* The largest possible page size */
151#define NS_LARGEST_PAGE_SIZE 2048 154#define NS_LARGEST_PAGE_SIZE 2048
@@ -162,6 +165,8 @@ MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (default
162 do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0) 165 do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
163#define NS_ERR(args...) \ 166#define NS_ERR(args...) \
164 do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0) 167 do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
168#define NS_INFO(args...) \
169 do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
165 170
166/* Busy-wait delay macros (microseconds, milliseconds) */ 171/* Busy-wait delay macros (microseconds, milliseconds) */
167#define NS_UDELAY(us) \ 172#define NS_UDELAY(us) \
@@ -394,6 +399,11 @@ struct grave_page {
394 399
395static LIST_HEAD(grave_pages); 400static LIST_HEAD(grave_pages);
396 401
402static unsigned long *erase_block_wear = NULL;
403static unsigned int wear_eb_count = 0;
404static unsigned long total_wear = 0;
405static unsigned int rptwear_cnt = 0;
406
397/* MTD structure for NAND controller */ 407/* MTD structure for NAND controller */
398static struct mtd_info *nsmtd; 408static struct mtd_info *nsmtd;
399 409
@@ -801,6 +811,89 @@ static void free_lists(void)
801 list_del(pos); 811 list_del(pos);
802 kfree(list_entry(pos, struct grave_page, list)); 812 kfree(list_entry(pos, struct grave_page, list));
803 } 813 }
814 kfree(erase_block_wear);
815}
816
817static int setup_wear_reporting(struct mtd_info *mtd)
818{
819 size_t mem;
820
821 if (!rptwear)
822 return 0;
823 wear_eb_count = mtd->size / mtd->erasesize;
824 mem = wear_eb_count * sizeof(unsigned long);
825 if (mem / sizeof(unsigned long) != wear_eb_count) {
826 NS_ERR("Too many erase blocks for wear reporting\n");
827 return -ENOMEM;
828 }
829 erase_block_wear = kzalloc(mem, GFP_KERNEL);
830 if (!erase_block_wear) {
831 NS_ERR("Too many erase blocks for wear reporting\n");
832 return -ENOMEM;
833 }
834 return 0;
835}
836
837static void update_wear(unsigned int erase_block_no)
838{
839 unsigned long wmin = -1, wmax = 0, avg;
840 unsigned long deciles[10], decile_max[10], tot = 0;
841 unsigned int i;
842
843 if (!erase_block_wear)
844 return;
845 total_wear += 1;
846 if (total_wear == 0)
847 NS_ERR("Erase counter total overflow\n");
848 erase_block_wear[erase_block_no] += 1;
849 if (erase_block_wear[erase_block_no] == 0)
850 NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
851 rptwear_cnt += 1;
852 if (rptwear_cnt < rptwear)
853 return;
854 rptwear_cnt = 0;
855 /* Calc wear stats */
856 for (i = 0; i < wear_eb_count; ++i) {
857 unsigned long wear = erase_block_wear[i];
858 if (wear < wmin)
859 wmin = wear;
860 if (wear > wmax)
861 wmax = wear;
862 tot += wear;
863 }
864 for (i = 0; i < 9; ++i) {
865 deciles[i] = 0;
866 decile_max[i] = (wmax * (i + 1) + 5) / 10;
867 }
868 deciles[9] = 0;
869 decile_max[9] = wmax;
870 for (i = 0; i < wear_eb_count; ++i) {
871 int d;
872 unsigned long wear = erase_block_wear[i];
873 for (d = 0; d < 10; ++d)
874 if (wear <= decile_max[d]) {
875 deciles[d] += 1;
876 break;
877 }
878 }
879 avg = tot / wear_eb_count;
880 /* Output wear report */
881 NS_INFO("*** Wear Report ***\n");
882 NS_INFO("Total numbers of erases: %lu\n", tot);
883 NS_INFO("Number of erase blocks: %u\n", wear_eb_count);
884 NS_INFO("Average number of erases: %lu\n", avg);
885 NS_INFO("Maximum number of erases: %lu\n", wmax);
886 NS_INFO("Minimum number of erases: %lu\n", wmin);
887 for (i = 0; i < 10; ++i) {
888 unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
889 if (from > decile_max[i])
890 continue;
891 NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n",
892 from,
893 decile_max[i],
894 deciles[i]);
895 }
896 NS_INFO("*** End of Wear Report ***\n");
804} 897}
805 898
806/* 899/*
@@ -1268,6 +1361,9 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
1268 1361
1269 NS_MDELAY(erase_delay); 1362 NS_MDELAY(erase_delay);
1270 1363
1364 if (erase_block_wear)
1365 update_wear(erase_block_no);
1366
1271 if (erase_error(erase_block_no)) { 1367 if (erase_error(erase_block_no)) {
1272 NS_WARN("simulating erase failure in erase block %u\n", erase_block_no); 1368 NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
1273 return -1; 1369 return -1;
@@ -1903,6 +1999,9 @@ static int __init ns_init_module(void)
1903 goto error; 1999 goto error;
1904 } 2000 }
1905 2001
2002 if ((retval = setup_wear_reporting(nsmtd)) != 0)
2003 goto err_exit;
2004
1906 if ((retval = init_nandsim(nsmtd)) != 0) 2005 if ((retval = init_nandsim(nsmtd)) != 0)
1907 goto err_exit; 2006 goto err_exit;
1908 2007