diff options
Diffstat (limited to 'drivers/mtd/nand/nandsim.c')
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 518 |
1 files changed, 492 insertions, 26 deletions
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c3bca9590ad2..205df0f771fe 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/mtd/nand.h> | 37 | #include <linux/mtd/nand.h> |
38 | #include <linux/mtd/partitions.h> | 38 | #include <linux/mtd/partitions.h> |
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/list.h> | ||
41 | #include <linux/random.h> | ||
40 | 42 | ||
41 | /* Default simulator parameters values */ | 43 | /* Default simulator parameters values */ |
42 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 44 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
@@ -90,6 +92,15 @@ static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH; | |||
90 | static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; | 92 | static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; |
91 | static uint log = CONFIG_NANDSIM_LOG; | 93 | static uint log = CONFIG_NANDSIM_LOG; |
92 | static uint dbg = CONFIG_NANDSIM_DBG; | 94 | static uint dbg = CONFIG_NANDSIM_DBG; |
95 | static unsigned long parts[MAX_MTD_DEVICES]; | ||
96 | static unsigned int parts_num; | ||
97 | static char *badblocks = NULL; | ||
98 | static char *weakblocks = NULL; | ||
99 | static char *weakpages = NULL; | ||
100 | static unsigned int bitflips = 0; | ||
101 | static char *gravepages = NULL; | ||
102 | static unsigned int rptwear = 0; | ||
103 | static unsigned int overridesize = 0; | ||
93 | 104 | ||
94 | module_param(first_id_byte, uint, 0400); | 105 | module_param(first_id_byte, uint, 0400); |
95 | module_param(second_id_byte, uint, 0400); | 106 | module_param(second_id_byte, uint, 0400); |
@@ -104,8 +115,16 @@ module_param(bus_width, uint, 0400); | |||
104 | module_param(do_delays, uint, 0400); | 115 | module_param(do_delays, uint, 0400); |
105 | module_param(log, uint, 0400); | 116 | module_param(log, uint, 0400); |
106 | module_param(dbg, uint, 0400); | 117 | module_param(dbg, uint, 0400); |
107 | 118 | module_param_array(parts, ulong, &parts_num, 0400); | |
108 | MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); | 119 | module_param(badblocks, charp, 0400); |
120 | module_param(weakblocks, charp, 0400); | ||
121 | module_param(weakpages, charp, 0400); | ||
122 | module_param(bitflips, uint, 0400); | ||
123 | module_param(gravepages, charp, 0400); | ||
124 | module_param(rptwear, uint, 0400); | ||
125 | module_param(overridesize, uint, 0400); | ||
126 | |||
127 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); | ||
109 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); | 128 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); |
110 | MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); | 129 | MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); |
111 | MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); | 130 | MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); |
@@ -118,6 +137,23 @@ MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)"); | |||
118 | MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero"); | 137 | MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero"); |
119 | MODULE_PARM_DESC(log, "Perform logging if not zero"); | 138 | MODULE_PARM_DESC(log, "Perform logging if not zero"); |
120 | MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | 139 | MODULE_PARM_DESC(dbg, "Output debug information if not zero"); |
140 | MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas"); | ||
141 | /* Page and erase block positions for the following parameters are independent of any partitions */ | ||
142 | MODULE_PARM_DESC(badblocks, "Erase blocks that are initially marked bad, separated by commas"); | ||
143 | MODULE_PARM_DESC(weakblocks, "Weak erase blocks [: remaining erase cycles (defaults to 3)]" | ||
144 | " separated by commas e.g. 113:2 means eb 113" | ||
145 | " can be erased only twice before failing"); | ||
146 | MODULE_PARM_DESC(weakpages, "Weak pages [: maximum writes (defaults to 3)]" | ||
147 | " separated by commas e.g. 1401:2 means page 1401" | ||
148 | " can be written only twice before failing"); | ||
149 | MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (zero by default)"); | ||
150 | MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" | ||
151 | " separated by commas e.g. 1401:2 means page 1401" | ||
152 | " can be read only twice before failing"); | ||
153 | MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if not zero"); | ||
154 | MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " | ||
155 | "The size is specified in erase blocks and as the exponent of a power of two" | ||
156 | " e.g. 5 means a size of 32 erase blocks"); | ||
121 | 157 | ||
122 | /* The largest possible page size */ | 158 | /* The largest possible page size */ |
123 | #define NS_LARGEST_PAGE_SIZE 2048 | 159 | #define NS_LARGEST_PAGE_SIZE 2048 |
@@ -131,9 +167,11 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
131 | #define NS_DBG(args...) \ | 167 | #define NS_DBG(args...) \ |
132 | do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) | 168 | do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) |
133 | #define NS_WARN(args...) \ | 169 | #define NS_WARN(args...) \ |
134 | do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0) | 170 | do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0) |
135 | #define NS_ERR(args...) \ | 171 | #define NS_ERR(args...) \ |
136 | do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0) | 172 | do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0) |
173 | #define NS_INFO(args...) \ | ||
174 | do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0) | ||
137 | 175 | ||
138 | /* Busy-wait delay macros (microseconds, milliseconds) */ | 176 | /* Busy-wait delay macros (microseconds, milliseconds) */ |
139 | #define NS_UDELAY(us) \ | 177 | #define NS_UDELAY(us) \ |
@@ -238,7 +276,8 @@ union ns_mem { | |||
238 | * The structure which describes all the internal simulator data. | 276 | * The structure which describes all the internal simulator data. |
239 | */ | 277 | */ |
240 | struct nandsim { | 278 | struct nandsim { |
241 | struct mtd_partition part; | 279 | struct mtd_partition partitions[MAX_MTD_DEVICES]; |
280 | unsigned int nbparts; | ||
242 | 281 | ||
243 | uint busw; /* flash chip bus width (8 or 16) */ | 282 | uint busw; /* flash chip bus width (8 or 16) */ |
244 | u_char ids[4]; /* chip's ID bytes */ | 283 | u_char ids[4]; /* chip's ID bytes */ |
@@ -338,6 +377,38 @@ static struct nandsim_operations { | |||
338 | STATE_DATAOUT, STATE_READY}} | 377 | STATE_DATAOUT, STATE_READY}} |
339 | }; | 378 | }; |
340 | 379 | ||
380 | struct weak_block { | ||
381 | struct list_head list; | ||
382 | unsigned int erase_block_no; | ||
383 | unsigned int max_erases; | ||
384 | unsigned int erases_done; | ||
385 | }; | ||
386 | |||
387 | static LIST_HEAD(weak_blocks); | ||
388 | |||
389 | struct weak_page { | ||
390 | struct list_head list; | ||
391 | unsigned int page_no; | ||
392 | unsigned int max_writes; | ||
393 | unsigned int writes_done; | ||
394 | }; | ||
395 | |||
396 | static LIST_HEAD(weak_pages); | ||
397 | |||
398 | struct grave_page { | ||
399 | struct list_head list; | ||
400 | unsigned int page_no; | ||
401 | unsigned int max_reads; | ||
402 | unsigned int reads_done; | ||
403 | }; | ||
404 | |||
405 | static LIST_HEAD(grave_pages); | ||
406 | |||
407 | static unsigned long *erase_block_wear = NULL; | ||
408 | static unsigned int wear_eb_count = 0; | ||
409 | static unsigned long total_wear = 0; | ||
410 | static unsigned int rptwear_cnt = 0; | ||
411 | |||
341 | /* MTD structure for NAND controller */ | 412 | /* MTD structure for NAND controller */ |
342 | static struct mtd_info *nsmtd; | 413 | static struct mtd_info *nsmtd; |
343 | 414 | ||
@@ -381,6 +452,13 @@ static void free_device(struct nandsim *ns) | |||
381 | } | 452 | } |
382 | } | 453 | } |
383 | 454 | ||
455 | static char *get_partition_name(int i) | ||
456 | { | ||
457 | char buf[64]; | ||
458 | sprintf(buf, "NAND simulator partition %d", i); | ||
459 | return kstrdup(buf, GFP_KERNEL); | ||
460 | } | ||
461 | |||
384 | /* | 462 | /* |
385 | * Initialize the nandsim structure. | 463 | * Initialize the nandsim structure. |
386 | * | 464 | * |
@@ -390,7 +468,9 @@ static int init_nandsim(struct mtd_info *mtd) | |||
390 | { | 468 | { |
391 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 469 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
392 | struct nandsim *ns = (struct nandsim *)(chip->priv); | 470 | struct nandsim *ns = (struct nandsim *)(chip->priv); |
393 | int i; | 471 | int i, ret = 0; |
472 | u_int32_t remains; | ||
473 | u_int32_t next_offset; | ||
394 | 474 | ||
395 | if (NS_IS_INITIALIZED(ns)) { | 475 | if (NS_IS_INITIALIZED(ns)) { |
396 | NS_ERR("init_nandsim: nandsim is already initialized\n"); | 476 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
@@ -448,6 +528,40 @@ static int init_nandsim(struct mtd_info *mtd) | |||
448 | } | 528 | } |
449 | } | 529 | } |
450 | 530 | ||
531 | /* Fill the partition_info structure */ | ||
532 | if (parts_num > ARRAY_SIZE(ns->partitions)) { | ||
533 | NS_ERR("too many partitions.\n"); | ||
534 | ret = -EINVAL; | ||
535 | goto error; | ||
536 | } | ||
537 | remains = ns->geom.totsz; | ||
538 | next_offset = 0; | ||
539 | for (i = 0; i < parts_num; ++i) { | ||
540 | unsigned long part = parts[i]; | ||
541 | if (!part || part > remains / ns->geom.secsz) { | ||
542 | NS_ERR("bad partition size.\n"); | ||
543 | ret = -EINVAL; | ||
544 | goto error; | ||
545 | } | ||
546 | ns->partitions[i].name = get_partition_name(i); | ||
547 | ns->partitions[i].offset = next_offset; | ||
548 | ns->partitions[i].size = part * ns->geom.secsz; | ||
549 | next_offset += ns->partitions[i].size; | ||
550 | remains -= ns->partitions[i].size; | ||
551 | } | ||
552 | ns->nbparts = parts_num; | ||
553 | if (remains) { | ||
554 | if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { | ||
555 | NS_ERR("too many partitions.\n"); | ||
556 | ret = -EINVAL; | ||
557 | goto error; | ||
558 | } | ||
559 | ns->partitions[i].name = get_partition_name(i); | ||
560 | ns->partitions[i].offset = next_offset; | ||
561 | ns->partitions[i].size = remains; | ||
562 | ns->nbparts += 1; | ||
563 | } | ||
564 | |||
451 | /* Detect how many ID bytes the NAND chip outputs */ | 565 | /* Detect how many ID bytes the NAND chip outputs */ |
452 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 566 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
453 | if (second_id_byte != nand_flash_ids[i].id) | 567 | if (second_id_byte != nand_flash_ids[i].id) |
@@ -474,7 +588,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
474 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); | 588 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); |
475 | printk("options: %#x\n", ns->options); | 589 | printk("options: %#x\n", ns->options); |
476 | 590 | ||
477 | if (alloc_device(ns) != 0) | 591 | if ((ret = alloc_device(ns)) != 0) |
478 | goto error; | 592 | goto error; |
479 | 593 | ||
480 | /* Allocate / initialize the internal buffer */ | 594 | /* Allocate / initialize the internal buffer */ |
@@ -482,21 +596,17 @@ static int init_nandsim(struct mtd_info *mtd) | |||
482 | if (!ns->buf.byte) { | 596 | if (!ns->buf.byte) { |
483 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", | 597 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", |
484 | ns->geom.pgszoob); | 598 | ns->geom.pgszoob); |
599 | ret = -ENOMEM; | ||
485 | goto error; | 600 | goto error; |
486 | } | 601 | } |
487 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); | 602 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); |
488 | 603 | ||
489 | /* Fill the partition_info structure */ | ||
490 | ns->part.name = "NAND simulator partition"; | ||
491 | ns->part.offset = 0; | ||
492 | ns->part.size = ns->geom.totsz; | ||
493 | |||
494 | return 0; | 604 | return 0; |
495 | 605 | ||
496 | error: | 606 | error: |
497 | free_device(ns); | 607 | free_device(ns); |
498 | 608 | ||
499 | return -ENOMEM; | 609 | return ret; |
500 | } | 610 | } |
501 | 611 | ||
502 | /* | 612 | /* |
@@ -510,6 +620,287 @@ static void free_nandsim(struct nandsim *ns) | |||
510 | return; | 620 | return; |
511 | } | 621 | } |
512 | 622 | ||
623 | static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) | ||
624 | { | ||
625 | char *w; | ||
626 | int zero_ok; | ||
627 | unsigned int erase_block_no; | ||
628 | loff_t offset; | ||
629 | |||
630 | if (!badblocks) | ||
631 | return 0; | ||
632 | w = badblocks; | ||
633 | do { | ||
634 | zero_ok = (*w == '0' ? 1 : 0); | ||
635 | erase_block_no = simple_strtoul(w, &w, 0); | ||
636 | if (!zero_ok && !erase_block_no) { | ||
637 | NS_ERR("invalid badblocks.\n"); | ||
638 | return -EINVAL; | ||
639 | } | ||
640 | offset = erase_block_no * ns->geom.secsz; | ||
641 | if (mtd->block_markbad(mtd, offset)) { | ||
642 | NS_ERR("invalid badblocks.\n"); | ||
643 | return -EINVAL; | ||
644 | } | ||
645 | if (*w == ',') | ||
646 | w += 1; | ||
647 | } while (*w); | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | static int parse_weakblocks(void) | ||
652 | { | ||
653 | char *w; | ||
654 | int zero_ok; | ||
655 | unsigned int erase_block_no; | ||
656 | unsigned int max_erases; | ||
657 | struct weak_block *wb; | ||
658 | |||
659 | if (!weakblocks) | ||
660 | return 0; | ||
661 | w = weakblocks; | ||
662 | do { | ||
663 | zero_ok = (*w == '0' ? 1 : 0); | ||
664 | erase_block_no = simple_strtoul(w, &w, 0); | ||
665 | if (!zero_ok && !erase_block_no) { | ||
666 | NS_ERR("invalid weakblocks.\n"); | ||
667 | return -EINVAL; | ||
668 | } | ||
669 | max_erases = 3; | ||
670 | if (*w == ':') { | ||
671 | w += 1; | ||
672 | max_erases = simple_strtoul(w, &w, 0); | ||
673 | } | ||
674 | if (*w == ',') | ||
675 | w += 1; | ||
676 | wb = kzalloc(sizeof(*wb), GFP_KERNEL); | ||
677 | if (!wb) { | ||
678 | NS_ERR("unable to allocate memory.\n"); | ||
679 | return -ENOMEM; | ||
680 | } | ||
681 | wb->erase_block_no = erase_block_no; | ||
682 | wb->max_erases = max_erases; | ||
683 | list_add(&wb->list, &weak_blocks); | ||
684 | } while (*w); | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static int erase_error(unsigned int erase_block_no) | ||
689 | { | ||
690 | struct weak_block *wb; | ||
691 | |||
692 | list_for_each_entry(wb, &weak_blocks, list) | ||
693 | if (wb->erase_block_no == erase_block_no) { | ||
694 | if (wb->erases_done >= wb->max_erases) | ||
695 | return 1; | ||
696 | wb->erases_done += 1; | ||
697 | return 0; | ||
698 | } | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int parse_weakpages(void) | ||
703 | { | ||
704 | char *w; | ||
705 | int zero_ok; | ||
706 | unsigned int page_no; | ||
707 | unsigned int max_writes; | ||
708 | struct weak_page *wp; | ||
709 | |||
710 | if (!weakpages) | ||
711 | return 0; | ||
712 | w = weakpages; | ||
713 | do { | ||
714 | zero_ok = (*w == '0' ? 1 : 0); | ||
715 | page_no = simple_strtoul(w, &w, 0); | ||
716 | if (!zero_ok && !page_no) { | ||
717 | NS_ERR("invalid weakpagess.\n"); | ||
718 | return -EINVAL; | ||
719 | } | ||
720 | max_writes = 3; | ||
721 | if (*w == ':') { | ||
722 | w += 1; | ||
723 | max_writes = simple_strtoul(w, &w, 0); | ||
724 | } | ||
725 | if (*w == ',') | ||
726 | w += 1; | ||
727 | wp = kzalloc(sizeof(*wp), GFP_KERNEL); | ||
728 | if (!wp) { | ||
729 | NS_ERR("unable to allocate memory.\n"); | ||
730 | return -ENOMEM; | ||
731 | } | ||
732 | wp->page_no = page_no; | ||
733 | wp->max_writes = max_writes; | ||
734 | list_add(&wp->list, &weak_pages); | ||
735 | } while (*w); | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static int write_error(unsigned int page_no) | ||
740 | { | ||
741 | struct weak_page *wp; | ||
742 | |||
743 | list_for_each_entry(wp, &weak_pages, list) | ||
744 | if (wp->page_no == page_no) { | ||
745 | if (wp->writes_done >= wp->max_writes) | ||
746 | return 1; | ||
747 | wp->writes_done += 1; | ||
748 | return 0; | ||
749 | } | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int parse_gravepages(void) | ||
754 | { | ||
755 | char *g; | ||
756 | int zero_ok; | ||
757 | unsigned int page_no; | ||
758 | unsigned int max_reads; | ||
759 | struct grave_page *gp; | ||
760 | |||
761 | if (!gravepages) | ||
762 | return 0; | ||
763 | g = gravepages; | ||
764 | do { | ||
765 | zero_ok = (*g == '0' ? 1 : 0); | ||
766 | page_no = simple_strtoul(g, &g, 0); | ||
767 | if (!zero_ok && !page_no) { | ||
768 | NS_ERR("invalid gravepagess.\n"); | ||
769 | return -EINVAL; | ||
770 | } | ||
771 | max_reads = 3; | ||
772 | if (*g == ':') { | ||
773 | g += 1; | ||
774 | max_reads = simple_strtoul(g, &g, 0); | ||
775 | } | ||
776 | if (*g == ',') | ||
777 | g += 1; | ||
778 | gp = kzalloc(sizeof(*gp), GFP_KERNEL); | ||
779 | if (!gp) { | ||
780 | NS_ERR("unable to allocate memory.\n"); | ||
781 | return -ENOMEM; | ||
782 | } | ||
783 | gp->page_no = page_no; | ||
784 | gp->max_reads = max_reads; | ||
785 | list_add(&gp->list, &grave_pages); | ||
786 | } while (*g); | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int read_error(unsigned int page_no) | ||
791 | { | ||
792 | struct grave_page *gp; | ||
793 | |||
794 | list_for_each_entry(gp, &grave_pages, list) | ||
795 | if (gp->page_no == page_no) { | ||
796 | if (gp->reads_done >= gp->max_reads) | ||
797 | return 1; | ||
798 | gp->reads_done += 1; | ||
799 | return 0; | ||
800 | } | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static void free_lists(void) | ||
805 | { | ||
806 | struct list_head *pos, *n; | ||
807 | list_for_each_safe(pos, n, &weak_blocks) { | ||
808 | list_del(pos); | ||
809 | kfree(list_entry(pos, struct weak_block, list)); | ||
810 | } | ||
811 | list_for_each_safe(pos, n, &weak_pages) { | ||
812 | list_del(pos); | ||
813 | kfree(list_entry(pos, struct weak_page, list)); | ||
814 | } | ||
815 | list_for_each_safe(pos, n, &grave_pages) { | ||
816 | list_del(pos); | ||
817 | kfree(list_entry(pos, struct grave_page, list)); | ||
818 | } | ||
819 | kfree(erase_block_wear); | ||
820 | } | ||
821 | |||
822 | static int setup_wear_reporting(struct mtd_info *mtd) | ||
823 | { | ||
824 | size_t mem; | ||
825 | |||
826 | if (!rptwear) | ||
827 | return 0; | ||
828 | wear_eb_count = mtd->size / mtd->erasesize; | ||
829 | mem = wear_eb_count * sizeof(unsigned long); | ||
830 | if (mem / sizeof(unsigned long) != wear_eb_count) { | ||
831 | NS_ERR("Too many erase blocks for wear reporting\n"); | ||
832 | return -ENOMEM; | ||
833 | } | ||
834 | erase_block_wear = kzalloc(mem, GFP_KERNEL); | ||
835 | if (!erase_block_wear) { | ||
836 | NS_ERR("Too many erase blocks for wear reporting\n"); | ||
837 | return -ENOMEM; | ||
838 | } | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | static void update_wear(unsigned int erase_block_no) | ||
843 | { | ||
844 | unsigned long wmin = -1, wmax = 0, avg; | ||
845 | unsigned long deciles[10], decile_max[10], tot = 0; | ||
846 | unsigned int i; | ||
847 | |||
848 | if (!erase_block_wear) | ||
849 | return; | ||
850 | total_wear += 1; | ||
851 | if (total_wear == 0) | ||
852 | NS_ERR("Erase counter total overflow\n"); | ||
853 | erase_block_wear[erase_block_no] += 1; | ||
854 | if (erase_block_wear[erase_block_no] == 0) | ||
855 | NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no); | ||
856 | rptwear_cnt += 1; | ||
857 | if (rptwear_cnt < rptwear) | ||
858 | return; | ||
859 | rptwear_cnt = 0; | ||
860 | /* Calc wear stats */ | ||
861 | for (i = 0; i < wear_eb_count; ++i) { | ||
862 | unsigned long wear = erase_block_wear[i]; | ||
863 | if (wear < wmin) | ||
864 | wmin = wear; | ||
865 | if (wear > wmax) | ||
866 | wmax = wear; | ||
867 | tot += wear; | ||
868 | } | ||
869 | for (i = 0; i < 9; ++i) { | ||
870 | deciles[i] = 0; | ||
871 | decile_max[i] = (wmax * (i + 1) + 5) / 10; | ||
872 | } | ||
873 | deciles[9] = 0; | ||
874 | decile_max[9] = wmax; | ||
875 | for (i = 0; i < wear_eb_count; ++i) { | ||
876 | int d; | ||
877 | unsigned long wear = erase_block_wear[i]; | ||
878 | for (d = 0; d < 10; ++d) | ||
879 | if (wear <= decile_max[d]) { | ||
880 | deciles[d] += 1; | ||
881 | break; | ||
882 | } | ||
883 | } | ||
884 | avg = tot / wear_eb_count; | ||
885 | /* Output wear report */ | ||
886 | NS_INFO("*** Wear Report ***\n"); | ||
887 | NS_INFO("Total numbers of erases: %lu\n", tot); | ||
888 | NS_INFO("Number of erase blocks: %u\n", wear_eb_count); | ||
889 | NS_INFO("Average number of erases: %lu\n", avg); | ||
890 | NS_INFO("Maximum number of erases: %lu\n", wmax); | ||
891 | NS_INFO("Minimum number of erases: %lu\n", wmin); | ||
892 | for (i = 0; i < 10; ++i) { | ||
893 | unsigned long from = (i ? decile_max[i - 1] + 1 : 0); | ||
894 | if (from > decile_max[i]) | ||
895 | continue; | ||
896 | NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n", | ||
897 | from, | ||
898 | decile_max[i], | ||
899 | deciles[i]); | ||
900 | } | ||
901 | NS_INFO("*** End of Wear Report ***\n"); | ||
902 | } | ||
903 | |||
513 | /* | 904 | /* |
514 | * Returns the string representation of 'state' state. | 905 | * Returns the string representation of 'state' state. |
515 | */ | 906 | */ |
@@ -822,9 +1213,31 @@ static void read_page(struct nandsim *ns, int num) | |||
822 | NS_DBG("read_page: page %d not allocated\n", ns->regs.row); | 1213 | NS_DBG("read_page: page %d not allocated\n", ns->regs.row); |
823 | memset(ns->buf.byte, 0xFF, num); | 1214 | memset(ns->buf.byte, 0xFF, num); |
824 | } else { | 1215 | } else { |
1216 | unsigned int page_no = ns->regs.row; | ||
825 | NS_DBG("read_page: page %d allocated, reading from %d\n", | 1217 | NS_DBG("read_page: page %d allocated, reading from %d\n", |
826 | ns->regs.row, ns->regs.column + ns->regs.off); | 1218 | ns->regs.row, ns->regs.column + ns->regs.off); |
1219 | if (read_error(page_no)) { | ||
1220 | int i; | ||
1221 | memset(ns->buf.byte, 0xFF, num); | ||
1222 | for (i = 0; i < num; ++i) | ||
1223 | ns->buf.byte[i] = random32(); | ||
1224 | NS_WARN("simulating read error in page %u\n", page_no); | ||
1225 | return; | ||
1226 | } | ||
827 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); | 1227 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); |
1228 | if (bitflips && random32() < (1 << 22)) { | ||
1229 | int flips = 1; | ||
1230 | if (bitflips > 1) | ||
1231 | flips = (random32() % (int) bitflips) + 1; | ||
1232 | while (flips--) { | ||
1233 | int pos = random32() % (num * 8); | ||
1234 | ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); | ||
1235 | NS_WARN("read_page: flipping bit %d in page %d " | ||
1236 | "reading from %d ecc: corrected=%u failed=%u\n", | ||
1237 | pos, ns->regs.row, ns->regs.column + ns->regs.off, | ||
1238 | nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); | ||
1239 | } | ||
1240 | } | ||
828 | } | 1241 | } |
829 | } | 1242 | } |
830 | 1243 | ||
@@ -883,6 +1296,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
883 | { | 1296 | { |
884 | int num; | 1297 | int num; |
885 | int busdiv = ns->busw == 8 ? 1 : 2; | 1298 | int busdiv = ns->busw == 8 ? 1 : 2; |
1299 | unsigned int erase_block_no, page_no; | ||
886 | 1300 | ||
887 | action &= ACTION_MASK; | 1301 | action &= ACTION_MASK; |
888 | 1302 | ||
@@ -942,14 +1356,24 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
942 | 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; | 1356 | 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; |
943 | ns->regs.column = 0; | 1357 | ns->regs.column = 0; |
944 | 1358 | ||
1359 | erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift); | ||
1360 | |||
945 | NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", | 1361 | NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", |
946 | ns->regs.row, NS_RAW_OFFSET(ns)); | 1362 | ns->regs.row, NS_RAW_OFFSET(ns)); |
947 | NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); | 1363 | NS_LOG("erase sector %u\n", erase_block_no); |
948 | 1364 | ||
949 | erase_sector(ns); | 1365 | erase_sector(ns); |
950 | 1366 | ||
951 | NS_MDELAY(erase_delay); | 1367 | NS_MDELAY(erase_delay); |
952 | 1368 | ||
1369 | if (erase_block_wear) | ||
1370 | update_wear(erase_block_no); | ||
1371 | |||
1372 | if (erase_error(erase_block_no)) { | ||
1373 | NS_WARN("simulating erase failure in erase block %u\n", erase_block_no); | ||
1374 | return -1; | ||
1375 | } | ||
1376 | |||
953 | break; | 1377 | break; |
954 | 1378 | ||
955 | case ACTION_PRGPAGE: | 1379 | case ACTION_PRGPAGE: |
@@ -972,6 +1396,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
972 | if (prog_page(ns, num) == -1) | 1396 | if (prog_page(ns, num) == -1) |
973 | return -1; | 1397 | return -1; |
974 | 1398 | ||
1399 | page_no = ns->regs.row; | ||
1400 | |||
975 | NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", | 1401 | NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", |
976 | num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); | 1402 | num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); |
977 | NS_LOG("programm page %d\n", ns->regs.row); | 1403 | NS_LOG("programm page %d\n", ns->regs.row); |
@@ -979,6 +1405,11 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
979 | NS_UDELAY(programm_delay); | 1405 | NS_UDELAY(programm_delay); |
980 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); | 1406 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); |
981 | 1407 | ||
1408 | if (write_error(page_no)) { | ||
1409 | NS_WARN("simulating write failure in page %u\n", page_no); | ||
1410 | return -1; | ||
1411 | } | ||
1412 | |||
982 | break; | 1413 | break; |
983 | 1414 | ||
984 | case ACTION_ZEROOFF: | 1415 | case ACTION_ZEROOFF: |
@@ -1503,7 +1934,7 @@ static int __init ns_init_module(void) | |||
1503 | { | 1934 | { |
1504 | struct nand_chip *chip; | 1935 | struct nand_chip *chip; |
1505 | struct nandsim *nand; | 1936 | struct nandsim *nand; |
1506 | int retval = -ENOMEM; | 1937 | int retval = -ENOMEM, i; |
1507 | 1938 | ||
1508 | if (bus_width != 8 && bus_width != 16) { | 1939 | if (bus_width != 8 && bus_width != 16) { |
1509 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); | 1940 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); |
@@ -1533,6 +1964,8 @@ static int __init ns_init_module(void) | |||
1533 | chip->verify_buf = ns_nand_verify_buf; | 1964 | chip->verify_buf = ns_nand_verify_buf; |
1534 | chip->read_word = ns_nand_read_word; | 1965 | chip->read_word = ns_nand_read_word; |
1535 | chip->ecc.mode = NAND_ECC_SOFT; | 1966 | chip->ecc.mode = NAND_ECC_SOFT; |
1967 | /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */ | ||
1968 | /* and 'badblocks' parameters to work */ | ||
1536 | chip->options |= NAND_SKIP_BBTSCAN; | 1969 | chip->options |= NAND_SKIP_BBTSCAN; |
1537 | 1970 | ||
1538 | /* | 1971 | /* |
@@ -1557,6 +1990,15 @@ static int __init ns_init_module(void) | |||
1557 | 1990 | ||
1558 | nsmtd->owner = THIS_MODULE; | 1991 | nsmtd->owner = THIS_MODULE; |
1559 | 1992 | ||
1993 | if ((retval = parse_weakblocks()) != 0) | ||
1994 | goto error; | ||
1995 | |||
1996 | if ((retval = parse_weakpages()) != 0) | ||
1997 | goto error; | ||
1998 | |||
1999 | if ((retval = parse_gravepages()) != 0) | ||
2000 | goto error; | ||
2001 | |||
1560 | if ((retval = nand_scan(nsmtd, 1)) != 0) { | 2002 | if ((retval = nand_scan(nsmtd, 1)) != 0) { |
1561 | NS_ERR("can't register NAND Simulator\n"); | 2003 | NS_ERR("can't register NAND Simulator\n"); |
1562 | if (retval > 0) | 2004 | if (retval > 0) |
@@ -1564,23 +2006,44 @@ static int __init ns_init_module(void) | |||
1564 | goto error; | 2006 | goto error; |
1565 | } | 2007 | } |
1566 | 2008 | ||
1567 | if ((retval = init_nandsim(nsmtd)) != 0) { | 2009 | if (overridesize) { |
1568 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); | 2010 | u_int32_t new_size = nsmtd->erasesize << overridesize; |
1569 | goto error; | 2011 | if (new_size >> overridesize != nsmtd->erasesize) { |
2012 | NS_ERR("overridesize is too big\n"); | ||
2013 | goto err_exit; | ||
2014 | } | ||
2015 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ | ||
2016 | nsmtd->size = new_size; | ||
2017 | chip->chipsize = new_size; | ||
2018 | chip->chip_shift = ffs(new_size) - 1; | ||
1570 | } | 2019 | } |
1571 | 2020 | ||
1572 | if ((retval = nand_default_bbt(nsmtd)) != 0) { | 2021 | if ((retval = setup_wear_reporting(nsmtd)) != 0) |
1573 | free_nandsim(nand); | 2022 | goto err_exit; |
1574 | goto error; | 2023 | |
1575 | } | 2024 | if ((retval = init_nandsim(nsmtd)) != 0) |
2025 | goto err_exit; | ||
1576 | 2026 | ||
1577 | /* Register NAND as one big partition */ | 2027 | if ((retval = parse_badblocks(nand, nsmtd)) != 0) |
1578 | add_mtd_partitions(nsmtd, &nand->part, 1); | 2028 | goto err_exit; |
2029 | |||
2030 | if ((retval = nand_default_bbt(nsmtd)) != 0) | ||
2031 | goto err_exit; | ||
2032 | |||
2033 | /* Register NAND partitions */ | ||
2034 | if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0) | ||
2035 | goto err_exit; | ||
1579 | 2036 | ||
1580 | return 0; | 2037 | return 0; |
1581 | 2038 | ||
2039 | err_exit: | ||
2040 | free_nandsim(nand); | ||
2041 | nand_release(nsmtd); | ||
2042 | for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) | ||
2043 | kfree(nand->partitions[i].name); | ||
1582 | error: | 2044 | error: |
1583 | kfree(nsmtd); | 2045 | kfree(nsmtd); |
2046 | free_lists(); | ||
1584 | 2047 | ||
1585 | return retval; | 2048 | return retval; |
1586 | } | 2049 | } |
@@ -1593,10 +2056,14 @@ module_init(ns_init_module); | |||
1593 | static void __exit ns_cleanup_module(void) | 2056 | static void __exit ns_cleanup_module(void) |
1594 | { | 2057 | { |
1595 | struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); | 2058 | struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); |
2059 | int i; | ||
1596 | 2060 | ||
1597 | free_nandsim(ns); /* Free nandsim private resources */ | 2061 | free_nandsim(ns); /* Free nandsim private resources */ |
1598 | nand_release(nsmtd); /* Unregisterd drived */ | 2062 | nand_release(nsmtd); /* Unregister driver */ |
2063 | for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) | ||
2064 | kfree(ns->partitions[i].name); | ||
1599 | kfree(nsmtd); /* Free other structures */ | 2065 | kfree(nsmtd); /* Free other structures */ |
2066 | free_lists(); | ||
1600 | } | 2067 | } |
1601 | 2068 | ||
1602 | module_exit(ns_cleanup_module); | 2069 | module_exit(ns_cleanup_module); |
@@ -1604,4 +2071,3 @@ module_exit(ns_cleanup_module); | |||
1604 | MODULE_LICENSE ("GPL"); | 2071 | MODULE_LICENSE ("GPL"); |
1605 | MODULE_AUTHOR ("Artem B. Bityuckiy"); | 2072 | MODULE_AUTHOR ("Artem B. Bityuckiy"); |
1606 | MODULE_DESCRIPTION ("The NAND flash simulator"); | 2073 | MODULE_DESCRIPTION ("The NAND flash simulator"); |
1607 | |||