diff options
Diffstat (limited to 'drivers/mtd/nand/nandsim.c')
-rw-r--r-- | drivers/mtd/nand/nandsim.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index bb885d1fcab5..ecd70e2504f6 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -21,8 +21,6 @@ | |||
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA |
24 | * | ||
25 | * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $ | ||
26 | */ | 24 | */ |
27 | 25 | ||
28 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -39,6 +37,7 @@ | |||
39 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
40 | #include <linux/list.h> | 38 | #include <linux/list.h> |
41 | #include <linux/random.h> | 39 | #include <linux/random.h> |
40 | #include <asm/div64.h> | ||
42 | 41 | ||
43 | /* Default simulator parameters values */ | 42 | /* Default simulator parameters values */ |
44 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 43 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
@@ -298,11 +297,11 @@ struct nandsim { | |||
298 | 297 | ||
299 | /* NAND flash "geometry" */ | 298 | /* NAND flash "geometry" */ |
300 | struct nandsin_geometry { | 299 | struct nandsin_geometry { |
301 | uint32_t totsz; /* total flash size, bytes */ | 300 | uint64_t totsz; /* total flash size, bytes */ |
302 | uint32_t secsz; /* flash sector (erase block) size, bytes */ | 301 | uint32_t secsz; /* flash sector (erase block) size, bytes */ |
303 | uint pgsz; /* NAND flash page size, bytes */ | 302 | uint pgsz; /* NAND flash page size, bytes */ |
304 | uint oobsz; /* page OOB area size, bytes */ | 303 | uint oobsz; /* page OOB area size, bytes */ |
305 | uint32_t totszoob; /* total flash size including OOB, bytes */ | 304 | uint64_t totszoob; /* total flash size including OOB, bytes */ |
306 | uint pgszoob; /* page size including OOB , bytes*/ | 305 | uint pgszoob; /* page size including OOB , bytes*/ |
307 | uint secszoob; /* sector size including OOB, bytes */ | 306 | uint secszoob; /* sector size including OOB, bytes */ |
308 | uint pgnum; /* total number of pages */ | 307 | uint pgnum; /* total number of pages */ |
@@ -459,6 +458,12 @@ static char *get_partition_name(int i) | |||
459 | return kstrdup(buf, GFP_KERNEL); | 458 | return kstrdup(buf, GFP_KERNEL); |
460 | } | 459 | } |
461 | 460 | ||
461 | static u_int64_t divide(u_int64_t n, u_int32_t d) | ||
462 | { | ||
463 | do_div(n, d); | ||
464 | return n; | ||
465 | } | ||
466 | |||
462 | /* | 467 | /* |
463 | * Initialize the nandsim structure. | 468 | * Initialize the nandsim structure. |
464 | * | 469 | * |
@@ -469,8 +474,8 @@ static int init_nandsim(struct mtd_info *mtd) | |||
469 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 474 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
470 | struct nandsim *ns = (struct nandsim *)(chip->priv); | 475 | struct nandsim *ns = (struct nandsim *)(chip->priv); |
471 | int i, ret = 0; | 476 | int i, ret = 0; |
472 | u_int32_t remains; | 477 | u_int64_t remains; |
473 | u_int32_t next_offset; | 478 | u_int64_t next_offset; |
474 | 479 | ||
475 | if (NS_IS_INITIALIZED(ns)) { | 480 | if (NS_IS_INITIALIZED(ns)) { |
476 | NS_ERR("init_nandsim: nandsim is already initialized\n"); | 481 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
@@ -487,8 +492,8 @@ static int init_nandsim(struct mtd_info *mtd) | |||
487 | ns->geom.oobsz = mtd->oobsize; | 492 | ns->geom.oobsz = mtd->oobsize; |
488 | ns->geom.secsz = mtd->erasesize; | 493 | ns->geom.secsz = mtd->erasesize; |
489 | ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; | 494 | ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; |
490 | ns->geom.pgnum = ns->geom.totsz / ns->geom.pgsz; | 495 | ns->geom.pgnum = divide(ns->geom.totsz, ns->geom.pgsz); |
491 | ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz; | 496 | ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz; |
492 | ns->geom.secshift = ffs(ns->geom.secsz) - 1; | 497 | ns->geom.secshift = ffs(ns->geom.secsz) - 1; |
493 | ns->geom.pgshift = chip->page_shift; | 498 | ns->geom.pgshift = chip->page_shift; |
494 | ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; | 499 | ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; |
@@ -511,7 +516,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
511 | } | 516 | } |
512 | 517 | ||
513 | if (ns->options & OPT_SMALLPAGE) { | 518 | if (ns->options & OPT_SMALLPAGE) { |
514 | if (ns->geom.totsz < (32 << 20)) { | 519 | if (ns->geom.totsz <= (32 << 20)) { |
515 | ns->geom.pgaddrbytes = 3; | 520 | ns->geom.pgaddrbytes = 3; |
516 | ns->geom.secaddrbytes = 2; | 521 | ns->geom.secaddrbytes = 2; |
517 | } else { | 522 | } else { |
@@ -537,15 +542,16 @@ static int init_nandsim(struct mtd_info *mtd) | |||
537 | remains = ns->geom.totsz; | 542 | remains = ns->geom.totsz; |
538 | next_offset = 0; | 543 | next_offset = 0; |
539 | for (i = 0; i < parts_num; ++i) { | 544 | for (i = 0; i < parts_num; ++i) { |
540 | unsigned long part = parts[i]; | 545 | u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; |
541 | if (!part || part > remains / ns->geom.secsz) { | 546 | |
547 | if (!part_sz || part_sz > remains) { | ||
542 | NS_ERR("bad partition size.\n"); | 548 | NS_ERR("bad partition size.\n"); |
543 | ret = -EINVAL; | 549 | ret = -EINVAL; |
544 | goto error; | 550 | goto error; |
545 | } | 551 | } |
546 | ns->partitions[i].name = get_partition_name(i); | 552 | ns->partitions[i].name = get_partition_name(i); |
547 | ns->partitions[i].offset = next_offset; | 553 | ns->partitions[i].offset = next_offset; |
548 | ns->partitions[i].size = part * ns->geom.secsz; | 554 | ns->partitions[i].size = part_sz; |
549 | next_offset += ns->partitions[i].size; | 555 | next_offset += ns->partitions[i].size; |
550 | remains -= ns->partitions[i].size; | 556 | remains -= ns->partitions[i].size; |
551 | } | 557 | } |
@@ -573,7 +579,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
573 | if (ns->busw == 16) | 579 | if (ns->busw == 16) |
574 | NS_WARN("16-bit flashes support wasn't tested\n"); | 580 | NS_WARN("16-bit flashes support wasn't tested\n"); |
575 | 581 | ||
576 | printk("flash size: %u MiB\n", ns->geom.totsz >> 20); | 582 | printk("flash size: %llu MiB\n", ns->geom.totsz >> 20); |
577 | printk("page size: %u bytes\n", ns->geom.pgsz); | 583 | printk("page size: %u bytes\n", ns->geom.pgsz); |
578 | printk("OOB area size: %u bytes\n", ns->geom.oobsz); | 584 | printk("OOB area size: %u bytes\n", ns->geom.oobsz); |
579 | printk("sector size: %u KiB\n", ns->geom.secsz >> 10); | 585 | printk("sector size: %u KiB\n", ns->geom.secsz >> 10); |
@@ -583,7 +589,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
583 | printk("bits in sector size: %u\n", ns->geom.secshift); | 589 | printk("bits in sector size: %u\n", ns->geom.secshift); |
584 | printk("bits in page size: %u\n", ns->geom.pgshift); | 590 | printk("bits in page size: %u\n", ns->geom.pgshift); |
585 | printk("bits in OOB size: %u\n", ns->geom.oobshift); | 591 | printk("bits in OOB size: %u\n", ns->geom.oobshift); |
586 | printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10); | 592 | printk("flash size with OOB: %llu KiB\n", ns->geom.totszoob >> 10); |
587 | printk("page address bytes: %u\n", ns->geom.pgaddrbytes); | 593 | printk("page address bytes: %u\n", ns->geom.pgaddrbytes); |
588 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); | 594 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); |
589 | printk("options: %#x\n", ns->options); | 595 | printk("options: %#x\n", ns->options); |
@@ -825,7 +831,7 @@ static int setup_wear_reporting(struct mtd_info *mtd) | |||
825 | 831 | ||
826 | if (!rptwear) | 832 | if (!rptwear) |
827 | return 0; | 833 | return 0; |
828 | wear_eb_count = mtd->size / mtd->erasesize; | 834 | wear_eb_count = divide(mtd->size, mtd->erasesize); |
829 | mem = wear_eb_count * sizeof(unsigned long); | 835 | mem = wear_eb_count * sizeof(unsigned long); |
830 | if (mem / sizeof(unsigned long) != wear_eb_count) { | 836 | if (mem / sizeof(unsigned long) != wear_eb_count) { |
831 | NS_ERR("Too many erase blocks for wear reporting\n"); | 837 | NS_ERR("Too many erase blocks for wear reporting\n"); |
@@ -2013,7 +2019,7 @@ static int __init ns_init_module(void) | |||
2013 | } | 2019 | } |
2014 | 2020 | ||
2015 | if (overridesize) { | 2021 | if (overridesize) { |
2016 | u_int32_t new_size = nsmtd->erasesize << overridesize; | 2022 | u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; |
2017 | if (new_size >> overridesize != nsmtd->erasesize) { | 2023 | if (new_size >> overridesize != nsmtd->erasesize) { |
2018 | NS_ERR("overridesize is too big\n"); | 2024 | NS_ERR("overridesize is too big\n"); |
2019 | goto err_exit; | 2025 | goto err_exit; |
@@ -2021,7 +2027,8 @@ static int __init ns_init_module(void) | |||
2021 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ | 2027 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ |
2022 | nsmtd->size = new_size; | 2028 | nsmtd->size = new_size; |
2023 | chip->chipsize = new_size; | 2029 | chip->chipsize = new_size; |
2024 | chip->chip_shift = ffs(new_size) - 1; | 2030 | chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1; |
2031 | chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; | ||
2025 | } | 2032 | } |
2026 | 2033 | ||
2027 | if ((retval = setup_wear_reporting(nsmtd)) != 0) | 2034 | if ((retval = setup_wear_reporting(nsmtd)) != 0) |