aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nandsim.c
diff options
context:
space:
mode:
authorVijay Kumar <vijaykumar@bravegnu.org>2006-10-08 12:32:31 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2006-10-21 11:40:27 -0400
commitd086d43640a40dda7783f3c56724048685586d17 (patch)
tree32ad427c5f8376d490d570fc03242cbde4904b6b /drivers/mtd/nand/nandsim.c
parent47e37743381823a5c2d51ef88cfc3d6cff1f8580 (diff)
[MTD] NAND: nandsim page-wise allocation (2/2)
For page wise allocation, an array of flash page pointers is allocated during initialization. The flash pages are themselves allocated when a write occurs to the page. The flash pages are deallocated when they are erased. Signed-off-by: Vijay Kumar <vijaykumar@bravegnu.org> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers/mtd/nand/nandsim.c')
-rw-r--r--drivers/mtd/nand/nandsim.c162
1 files changed, 138 insertions, 24 deletions
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 5dd3c4eb4f01..f00e195f4711 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -227,6 +227,14 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
227#define NS_MAX_PREVSTATES 1 227#define NS_MAX_PREVSTATES 1
228 228
229/* 229/*
230 * A union to represent flash memory contents and flash buffer.
231 */
232union ns_mem {
233 u_char *byte; /* for byte access */
234 uint16_t *word; /* for 16-bit word access */
235};
236
237/*
230 * The structure which describes all the internal simulator data. 238 * The structure which describes all the internal simulator data.
231 */ 239 */
232struct nandsim { 240struct nandsim {
@@ -243,17 +251,11 @@ struct nandsim {
243 uint16_t npstates; /* number of previous states saved */ 251 uint16_t npstates; /* number of previous states saved */
244 uint16_t stateidx; /* current state index */ 252 uint16_t stateidx; /* current state index */
245 253
246 /* The simulated NAND flash image */ 254 /* The simulated NAND flash pages array */
247 union flash_media { 255 union ns_mem *pages;
248 u_char *byte;
249 uint16_t *word;
250 } mem;
251 256
252 /* Internal buffer of page + OOB size bytes */ 257 /* Internal buffer of page + OOB size bytes */
253 union internal_buffer { 258 union ns_mem buf;
254 u_char *byte; /* for byte access */
255 uint16_t *word; /* for 16-bit word access */
256 } buf;
257 259
258 /* NAND flash "geometry" */ 260 /* NAND flash "geometry" */
259 struct nandsin_geometry { 261 struct nandsin_geometry {
@@ -342,6 +344,46 @@ static struct mtd_info *nsmtd;
342static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; 344static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
343 345
344/* 346/*
347 * Allocate array of page pointers and initialize the array to NULL
348 * pointers.
349 *
350 * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
351 */
352static int
353alloc_device(struct nandsim *ns)
354{
355 int i;
356
357 ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
358 if (!ns->pages) {
359 NS_ERR("alloc_map: unable to allocate page array\n");
360 return -ENOMEM;
361 }
362 for (i = 0; i < ns->geom.pgnum; i++) {
363 ns->pages[i].byte = NULL;
364 }
365
366 return 0;
367}
368
369/*
370 * Free any allocated pages, and free the array of page pointers.
371 */
372static void
373free_device(struct nandsim *ns)
374{
375 int i;
376
377 if (ns->pages) {
378 for (i = 0; i < ns->geom.pgnum; i++) {
379 if (ns->pages[i].byte)
380 kfree(ns->pages[i].byte);
381 }
382 vfree(ns->pages);
383 }
384}
385
386/*
345 * Initialize the nandsim structure. 387 * Initialize the nandsim structure.
346 * 388 *
347 * RETURNS: 0 if success, -ERRNO if failure. 389 * RETURNS: 0 if success, -ERRNO if failure.
@@ -435,14 +477,8 @@ init_nandsim(struct mtd_info *mtd)
435 printk("sector address bytes: %u\n", ns->geom.secaddrbytes); 477 printk("sector address bytes: %u\n", ns->geom.secaddrbytes);
436 printk("options: %#x\n", ns->options); 478 printk("options: %#x\n", ns->options);
437 479
438 /* Map / allocate and initialize the flash image */ 480 if (alloc_device(ns) != 0)
439 ns->mem.byte = vmalloc(ns->geom.totszoob); 481 goto error;
440 if (!ns->mem.byte) {
441 NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n",
442 ns->geom.totszoob);
443 return -ENOMEM;
444 }
445 memset(ns->mem.byte, 0xFF, ns->geom.totszoob);
446 482
447 /* Allocate / initialize the internal buffer */ 483 /* Allocate / initialize the internal buffer */
448 ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); 484 ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
@@ -461,7 +497,7 @@ init_nandsim(struct mtd_info *mtd)
461 return 0; 497 return 0;
462 498
463error: 499error:
464 vfree(ns->mem.byte); 500 free_device(ns);
465 501
466 return -ENOMEM; 502 return -ENOMEM;
467} 503}
@@ -473,7 +509,7 @@ static void
473free_nandsim(struct nandsim *ns) 509free_nandsim(struct nandsim *ns)
474{ 510{
475 kfree(ns->buf.byte); 511 kfree(ns->buf.byte);
476 vfree(ns->mem.byte); 512 free_device(ns);
477 513
478 return; 514 return;
479} 515}
@@ -769,6 +805,84 @@ find_operation(struct nandsim *ns, uint32_t flag)
769} 805}
770 806
771/* 807/*
808 * Returns a pointer to the current page.
809 */
810static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
811{
812 return &(ns->pages[ns->regs.row]);
813}
814
815/*
816 * Retuns a pointer to the current byte, within the current page.
817 */
818static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
819{
820 return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
821}
822
823/*
824 * Fill the NAND buffer with data read from the specified page.
825 */
826static void read_page(struct nandsim *ns, int num)
827{
828 union ns_mem *mypage;
829
830 mypage = NS_GET_PAGE(ns);
831 if (mypage->byte == NULL) {
832 NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
833 memset(ns->buf.byte, 0xFF, num);
834 } else {
835 NS_DBG("read_page: page %d allocated, reading from %d\n",
836 ns->regs.row, ns->regs.column + ns->regs.off);
837 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
838 }
839}
840
841/*
842 * Erase all pages in the specified sector.
843 */
844static void erase_sector(struct nandsim *ns)
845{
846 union ns_mem *mypage;
847 int i;
848
849 mypage = NS_GET_PAGE(ns);
850 for (i = 0; i < ns->geom.pgsec; i++) {
851 if (mypage->byte != NULL) {
852 NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
853 kfree(mypage->byte);
854 mypage->byte = NULL;
855 }
856 mypage++;
857 }
858}
859
860/*
861 * Program the specified page with the contents from the NAND buffer.
862 */
863static int prog_page(struct nandsim *ns, int num)
864{
865 union ns_mem *mypage;
866 u_char *pg_off;
867
868 mypage = NS_GET_PAGE(ns);
869 if (mypage->byte == NULL) {
870 NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
871 mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
872 if (mypage->byte == NULL) {
873 NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
874 return -1;
875 }
876 memset(mypage->byte, 0xFF, ns->geom.pgszoob);
877 }
878
879 pg_off = NS_PAGE_BYTE_OFF(ns);
880 memcpy(pg_off, ns->buf.byte, num);
881
882 return 0;
883}
884
885/*
772 * If state has any action bit, perform this action. 886 * If state has any action bit, perform this action.
773 * 887 *
774 * RETURNS: 0 if success, -1 if error. 888 * RETURNS: 0 if success, -1 if error.
@@ -776,7 +890,7 @@ find_operation(struct nandsim *ns, uint32_t flag)
776static int 890static int
777do_state_action(struct nandsim *ns, uint32_t action) 891do_state_action(struct nandsim *ns, uint32_t action)
778{ 892{
779 int i, num; 893 int num;
780 int busdiv = ns->busw == 8 ? 1 : 2; 894 int busdiv = ns->busw == 8 ? 1 : 2;
781 895
782 action &= ACTION_MASK; 896 action &= ACTION_MASK;
@@ -800,7 +914,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
800 break; 914 break;
801 } 915 }
802 num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; 916 num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
803 memcpy(ns->buf.byte, ns->mem.byte + NS_RAW_OFFSET(ns) + ns->regs.off, num); 917 read_page(ns, num);
804 918
805 NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", 919 NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
806 num, NS_RAW_OFFSET(ns) + ns->regs.off); 920 num, NS_RAW_OFFSET(ns) + ns->regs.off);
@@ -841,7 +955,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
841 ns->regs.row, NS_RAW_OFFSET(ns)); 955 ns->regs.row, NS_RAW_OFFSET(ns));
842 NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); 956 NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
843 957
844 memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob); 958 erase_sector(ns);
845 959
846 NS_MDELAY(erase_delay); 960 NS_MDELAY(erase_delay);
847 961
@@ -864,8 +978,8 @@ do_state_action(struct nandsim *ns, uint32_t action)
864 return -1; 978 return -1;
865 } 979 }
866 980
867 for (i = 0; i < num; i++) 981 if (prog_page(ns, num) == -1)
868 ns->mem.byte[NS_RAW_OFFSET(ns) + ns->regs.off + i] &= ns->buf.byte[i]; 982 return -1;
869 983
870 NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", 984 NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
871 num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); 985 num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);