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) |
