diff options
| -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 | |||
