diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 97 |
1 files changed, 73 insertions, 24 deletions
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c3bca9590ad2..638e6c256d3e 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -37,6 +37,7 @@ | |||
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> | ||
40 | 41 | ||
41 | /* Default simulator parameters values */ | 42 | /* Default simulator parameters values */ |
42 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 43 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
@@ -90,6 +91,8 @@ static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH; | |||
90 | static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; | 91 | static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; |
91 | static uint log = CONFIG_NANDSIM_LOG; | 92 | static uint log = CONFIG_NANDSIM_LOG; |
92 | static uint dbg = CONFIG_NANDSIM_DBG; | 93 | static uint dbg = CONFIG_NANDSIM_DBG; |
94 | static unsigned long parts[MAX_MTD_DEVICES]; | ||
95 | static unsigned int parts_num; | ||
93 | 96 | ||
94 | module_param(first_id_byte, uint, 0400); | 97 | module_param(first_id_byte, uint, 0400); |
95 | module_param(second_id_byte, uint, 0400); | 98 | module_param(second_id_byte, uint, 0400); |
@@ -104,6 +107,7 @@ module_param(bus_width, uint, 0400); | |||
104 | module_param(do_delays, uint, 0400); | 107 | module_param(do_delays, uint, 0400); |
105 | module_param(log, uint, 0400); | 108 | module_param(log, uint, 0400); |
106 | module_param(dbg, uint, 0400); | 109 | module_param(dbg, uint, 0400); |
110 | module_param_array(parts, ulong, &parts_num, 0400); | ||
107 | 111 | ||
108 | MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); | 112 | MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); |
109 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); | 113 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); |
@@ -118,6 +122,7 @@ 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"); | 122 | MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero"); |
119 | MODULE_PARM_DESC(log, "Perform logging if not zero"); | 123 | MODULE_PARM_DESC(log, "Perform logging if not zero"); |
120 | MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | 124 | MODULE_PARM_DESC(dbg, "Output debug information if not zero"); |
125 | MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas"); | ||
121 | 126 | ||
122 | /* The largest possible page size */ | 127 | /* The largest possible page size */ |
123 | #define NS_LARGEST_PAGE_SIZE 2048 | 128 | #define NS_LARGEST_PAGE_SIZE 2048 |
@@ -131,9 +136,9 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
131 | #define NS_DBG(args...) \ | 136 | #define NS_DBG(args...) \ |
132 | do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) | 137 | do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) |
133 | #define NS_WARN(args...) \ | 138 | #define NS_WARN(args...) \ |
134 | do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0) | 139 | do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0) |
135 | #define NS_ERR(args...) \ | 140 | #define NS_ERR(args...) \ |
136 | do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0) | 141 | do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0) |
137 | 142 | ||
138 | /* Busy-wait delay macros (microseconds, milliseconds) */ | 143 | /* Busy-wait delay macros (microseconds, milliseconds) */ |
139 | #define NS_UDELAY(us) \ | 144 | #define NS_UDELAY(us) \ |
@@ -238,7 +243,8 @@ union ns_mem { | |||
238 | * The structure which describes all the internal simulator data. | 243 | * The structure which describes all the internal simulator data. |
239 | */ | 244 | */ |
240 | struct nandsim { | 245 | struct nandsim { |
241 | struct mtd_partition part; | 246 | struct mtd_partition partitions[MAX_MTD_DEVICES]; |
247 | unsigned int nbparts; | ||
242 | 248 | ||
243 | uint busw; /* flash chip bus width (8 or 16) */ | 249 | uint busw; /* flash chip bus width (8 or 16) */ |
244 | u_char ids[4]; /* chip's ID bytes */ | 250 | u_char ids[4]; /* chip's ID bytes */ |
@@ -381,6 +387,13 @@ static void free_device(struct nandsim *ns) | |||
381 | } | 387 | } |
382 | } | 388 | } |
383 | 389 | ||
390 | static char *get_partition_name(int i) | ||
391 | { | ||
392 | char buf[64]; | ||
393 | sprintf(buf, "NAND simulator partition %d", i); | ||
394 | return kstrdup(buf, GFP_KERNEL); | ||
395 | } | ||
396 | |||
384 | /* | 397 | /* |
385 | * Initialize the nandsim structure. | 398 | * Initialize the nandsim structure. |
386 | * | 399 | * |
@@ -390,7 +403,9 @@ static int init_nandsim(struct mtd_info *mtd) | |||
390 | { | 403 | { |
391 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 404 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
392 | struct nandsim *ns = (struct nandsim *)(chip->priv); | 405 | struct nandsim *ns = (struct nandsim *)(chip->priv); |
393 | int i; | 406 | int i, ret = 0; |
407 | u_int32_t remains; | ||
408 | u_int32_t next_offset; | ||
394 | 409 | ||
395 | if (NS_IS_INITIALIZED(ns)) { | 410 | if (NS_IS_INITIALIZED(ns)) { |
396 | NS_ERR("init_nandsim: nandsim is already initialized\n"); | 411 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
@@ -448,6 +463,40 @@ static int init_nandsim(struct mtd_info *mtd) | |||
448 | } | 463 | } |
449 | } | 464 | } |
450 | 465 | ||
466 | /* Fill the partition_info structure */ | ||
467 | if (parts_num > ARRAY_SIZE(ns->partitions)) { | ||
468 | NS_ERR("too many partitions.\n"); | ||
469 | ret = -EINVAL; | ||
470 | goto error; | ||
471 | } | ||
472 | remains = ns->geom.totsz; | ||
473 | next_offset = 0; | ||
474 | for (i = 0; i < parts_num; ++i) { | ||
475 | unsigned long part = parts[i]; | ||
476 | if (!part || part > remains / ns->geom.secsz) { | ||
477 | NS_ERR("bad partition size.\n"); | ||
478 | ret = -EINVAL; | ||
479 | goto error; | ||
480 | } | ||
481 | ns->partitions[i].name = get_partition_name(i); | ||
482 | ns->partitions[i].offset = next_offset; | ||
483 | ns->partitions[i].size = part * ns->geom.secsz; | ||
484 | next_offset += ns->partitions[i].size; | ||
485 | remains -= ns->partitions[i].size; | ||
486 | } | ||
487 | ns->nbparts = parts_num; | ||
488 | if (remains) { | ||
489 | if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { | ||
490 | NS_ERR("too many partitions.\n"); | ||
491 | ret = -EINVAL; | ||
492 | goto error; | ||
493 | } | ||
494 | ns->partitions[i].name = get_partition_name(i); | ||
495 | ns->partitions[i].offset = next_offset; | ||
496 | ns->partitions[i].size = remains; | ||
497 | ns->nbparts += 1; | ||
498 | } | ||
499 | |||
451 | /* Detect how many ID bytes the NAND chip outputs */ | 500 | /* Detect how many ID bytes the NAND chip outputs */ |
452 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 501 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
453 | if (second_id_byte != nand_flash_ids[i].id) | 502 | if (second_id_byte != nand_flash_ids[i].id) |
@@ -474,7 +523,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
474 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); | 523 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); |
475 | printk("options: %#x\n", ns->options); | 524 | printk("options: %#x\n", ns->options); |
476 | 525 | ||
477 | if (alloc_device(ns) != 0) | 526 | if ((ret = alloc_device(ns)) != 0) |
478 | goto error; | 527 | goto error; |
479 | 528 | ||
480 | /* Allocate / initialize the internal buffer */ | 529 | /* Allocate / initialize the internal buffer */ |
@@ -482,21 +531,17 @@ static int init_nandsim(struct mtd_info *mtd) | |||
482 | if (!ns->buf.byte) { | 531 | if (!ns->buf.byte) { |
483 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", | 532 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", |
484 | ns->geom.pgszoob); | 533 | ns->geom.pgszoob); |
534 | ret = -ENOMEM; | ||
485 | goto error; | 535 | goto error; |
486 | } | 536 | } |
487 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); | 537 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); |
488 | 538 | ||
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; | 539 | return 0; |
495 | 540 | ||
496 | error: | 541 | error: |
497 | free_device(ns); | 542 | free_device(ns); |
498 | 543 | ||
499 | return -ENOMEM; | 544 | return ret; |
500 | } | 545 | } |
501 | 546 | ||
502 | /* | 547 | /* |
@@ -1503,7 +1548,7 @@ static int __init ns_init_module(void) | |||
1503 | { | 1548 | { |
1504 | struct nand_chip *chip; | 1549 | struct nand_chip *chip; |
1505 | struct nandsim *nand; | 1550 | struct nandsim *nand; |
1506 | int retval = -ENOMEM; | 1551 | int retval = -ENOMEM, i; |
1507 | 1552 | ||
1508 | if (bus_width != 8 && bus_width != 16) { | 1553 | if (bus_width != 8 && bus_width != 16) { |
1509 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); | 1554 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); |
@@ -1564,21 +1609,23 @@ static int __init ns_init_module(void) | |||
1564 | goto error; | 1609 | goto error; |
1565 | } | 1610 | } |
1566 | 1611 | ||
1567 | if ((retval = init_nandsim(nsmtd)) != 0) { | 1612 | if ((retval = init_nandsim(nsmtd)) != 0) |
1568 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); | 1613 | goto err_exit; |
1569 | goto error; | ||
1570 | } | ||
1571 | 1614 | ||
1572 | if ((retval = nand_default_bbt(nsmtd)) != 0) { | 1615 | if ((retval = nand_default_bbt(nsmtd)) != 0) |
1573 | free_nandsim(nand); | 1616 | goto err_exit; |
1574 | goto error; | ||
1575 | } | ||
1576 | 1617 | ||
1577 | /* Register NAND as one big partition */ | 1618 | /* Register NAND partitions */ |
1578 | add_mtd_partitions(nsmtd, &nand->part, 1); | 1619 | if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0) |
1620 | goto err_exit; | ||
1579 | 1621 | ||
1580 | return 0; | 1622 | return 0; |
1581 | 1623 | ||
1624 | err_exit: | ||
1625 | free_nandsim(nand); | ||
1626 | nand_release(nsmtd); | ||
1627 | for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) | ||
1628 | kfree(nand->partitions[i].name); | ||
1582 | error: | 1629 | error: |
1583 | kfree(nsmtd); | 1630 | kfree(nsmtd); |
1584 | 1631 | ||
@@ -1593,9 +1640,12 @@ module_init(ns_init_module); | |||
1593 | static void __exit ns_cleanup_module(void) | 1640 | static void __exit ns_cleanup_module(void) |
1594 | { | 1641 | { |
1595 | struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); | 1642 | struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); |
1643 | int i; | ||
1596 | 1644 | ||
1597 | free_nandsim(ns); /* Free nandsim private resources */ | 1645 | free_nandsim(ns); /* Free nandsim private resources */ |
1598 | nand_release(nsmtd); /* Unregisterd drived */ | 1646 | nand_release(nsmtd); /* Unregister driver */ |
1647 | for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) | ||
1648 | kfree(ns->partitions[i].name); | ||
1599 | kfree(nsmtd); /* Free other structures */ | 1649 | kfree(nsmtd); /* Free other structures */ |
1600 | } | 1650 | } |
1601 | 1651 | ||
@@ -1604,4 +1654,3 @@ module_exit(ns_cleanup_module); | |||
1604 | MODULE_LICENSE ("GPL"); | 1654 | MODULE_LICENSE ("GPL"); |
1605 | MODULE_AUTHOR ("Artem B. Bityuckiy"); | 1655 | MODULE_AUTHOR ("Artem B. Bityuckiy"); |
1606 | MODULE_DESCRIPTION ("The NAND flash simulator"); | 1656 | MODULE_DESCRIPTION ("The NAND flash simulator"); |
1607 | |||