lkml.org 
[lkml]   [2008]   [Aug]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 2/2][MTD] Add support for > 2GiB MTD devices
    From 3e33a3cfc289e9baa41f6e7cf4d612d41b88e19b Mon Sep 17 00:00:00 2001
    From: brucle <brucle@selinc.com>
    Date: Wed, 13 Aug 2008 18:07:19 -0700
    Subject: [PATCH] Add support for > 2GiB MTD devices

    Signed-off-by: Bruce D. Leonard <brucle@selinc.com>

    ---
    drivers/mtd/mtdchar.c | 16 ++++++++--------
    drivers/mtd/mtdcore.c | 6 +++---
    drivers/mtd/nand/nand_base.c | 36 ++++++++++++++++++++++++------------
    drivers/mtd/nand/nand_bbt.c | 30 +++++++++++++++---------------
    drivers/mtd/ubi/build.c | 5 +++--
    include/linux/mtd/mtd.h | 27 ++++++++++++++++++++++-----
    include/mtd/mtd-abi.h | 4 ++--
    7 files changed, 77 insertions(+), 47 deletions(-)

    diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
    index d2f3318..2829faa 100644
    --- a/drivers/mtd/mtdchar.c
    +++ b/drivers/mtd/mtdchar.c
    @@ -70,13 +70,13 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
    offset += file->f_pos;
    break;
    case SEEK_END:
    - offset += mtd->size;
    + offset += device_size(mtd);
    break;
    default:
    return -EINVAL;
    }

    - if (offset >= 0 && offset <= mtd->size)
    + if (offset >= 0 && offset <= device_size(mtd))
    return file->f_pos = offset;

    return -EINVAL;
    @@ -173,8 +173,8 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t

    DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");

    - if (*ppos + count > mtd->size)
    - count = mtd->size - *ppos;
    + if (*ppos + count > device_size(mtd))
    + count = device_size(mtd) - *ppos;

    if (!count)
    return 0;
    @@ -266,11 +266,11 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count

    DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");

    - if (*ppos == mtd->size)
    + if (*ppos == device_size(mtd))
    return -ENOSPC;

    - if (*ppos + count > mtd->size)
    - count = mtd->size - *ppos;
    + if (*ppos + count > device_size(mtd))
    + count = device_size(mtd) - *ppos;

    if (!count)
    return 0;
    @@ -426,7 +426,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
    case MEMGETINFO:
    info.type = mtd->type;
    info.flags = mtd->flags;
    - info.size = mtd->size;
    + info.size = device_size(mtd);
    info.erasesize = mtd->erasesize;
    info.writesize = mtd->writesize;
    info.oobsize = mtd->oobsize;
    diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
    index a9d2469..98bc81f 100644
    --- a/drivers/mtd/mtdcore.c
    +++ b/drivers/mtd/mtdcore.c
    @@ -60,7 +60,7 @@ int add_mtd_device(struct mtd_info *mtd)
    /* Some chips always power up locked. Unlock them now */
    if ((mtd->flags & MTD_WRITEABLE)
    && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
    - if (mtd->unlock(mtd, 0, mtd->size))
    + if (mtd->unlock(mtd, 0, device_size(mtd)))
    printk(KERN_WARNING
    "%s: unlock failed, "
    "writes may not work\n",
    @@ -344,8 +344,8 @@ static inline int mtd_proc_info (char *buf, int i)
    if (!this)
    return 0;

    - return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size,
    - this->erasesize, this->name);
    + return sprintf(buf, "mtd%d: %16.16llx %8.8x \"%s\"\n", i,
    + device_size(this), this->erasesize, this->name);
    }

    static int mtd_read_proc (char *page, char **start, off_t off, int count,
    diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
    index d5ac675..2463250 100644
    --- a/drivers/mtd/nand/nand_base.c
    +++ b/drivers/mtd/nand/nand_base.c
    @@ -1179,7 +1179,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
    int ret;

    /* Do not allow reads past end of device */
    - if ((from + len) > mtd->size)
    + if ((from + len) > device_size(mtd))
    return -EINVAL;
    if (!len)
    return 0;
    @@ -1371,8 +1371,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
    }

    /* Do not allow reads past end of device */
    - if (unlikely(from >= mtd->size ||
    - ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
    + if (unlikely(from >= device_size(mtd) ||
    + ops->ooboffs + readlen > ((device_size(mtd) >> chip->page_shift) -
    (from >> chip->page_shift)) * len)) {
    DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
    "Attempt read beyond end of device\n");
    @@ -1448,7 +1448,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
    ops->retlen = 0;

    /* Do not allow reads past end of device */
    - if (ops->datbuf && (from + ops->len) > mtd->size) {
    + if (ops->datbuf && (from + ops->len) > device_size(mtd)) {
    DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
    "Attempt read beyond end of device\n");
    return -EINVAL;
    @@ -1813,7 +1813,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
    int ret;

    /* Do not allow reads past end of device */
    - if ((to + len) > mtd->size)
    + if ((to + len) > device_size(mtd))
    return -EINVAL;
    if (!len)
    return 0;
    @@ -1869,9 +1869,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
    }

    /* Do not allow reads past end of device */
    - if (unlikely(to >= mtd->size ||
    + if (unlikely(to >= device_size(mtd) ||
    ops->ooboffs + ops->ooblen >
    - ((mtd->size >> chip->page_shift) -
    + ((device_size(mtd) >> chip->page_shift) -
    (to >> chip->page_shift)) * len)) {
    DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
    "Attempt write beyond end of device\n");
    @@ -1928,7 +1928,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
    ops->retlen = 0;

    /* Do not allow writes past end of device */
    - if (ops->datbuf && (to + ops->len) > mtd->size) {
    + if (ops->datbuf && (to + ops->len) > device_size(mtd)) {
    DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
    "Attempt read beyond end of device\n");
    return -EINVAL;
    @@ -2019,8 +2019,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
    int rewrite_bbt[NAND_MAX_CHIPS]={0};
    unsigned int bbt_masked_page = 0xffffffff;

    - DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
    - (unsigned int)instr->addr, (unsigned int)instr->len);
    + DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%016llx, len = %i\n",
    + instr->addr, (unsigned int)instr->len);

    /* Start address must align on block boundary */
    if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
    @@ -2036,7 +2036,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
    }

    /* Do not allow erase past end of device */
    - if ((instr->len + instr->addr) > mtd->size) {
    + if ((instr->len + instr->addr) > device_size(mtd)) {
    DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
    "Erase past end of device\n");
    return -EINVAL;
    @@ -2208,7 +2208,7 @@ static void nand_sync(struct mtd_info *mtd)
    static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
    {
    /* Check for invalid offset */
    - if (offs > mtd->size)
    + if (offs > device_size(mtd))
    return -EINVAL;

    return nand_block_checkbad(mtd, offs, 1, 0);
    @@ -2502,6 +2502,18 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
    chip->numchips = i;
    mtd->size = i * chip->chipsize;

    + /* Because mtd->size is 32 bits, if the total 'device size'
    + * is greater than 2GiB it will overflow mtd->size and signal
    + * that we need to use the new MTD mio interface.
    + */
    + if (mtd->size == 0) {
    + mtd->num_eraseblocks = (i * (__u64)(chip->chipsize)) >>
    + chip->phys_erase_shift;
    + } else {
    + /* Can't guarantee mtd was kzalloc'ed */
    + mtd->num_eraseblocks = 0;
    + }
    +
    return 0;
    }

    diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
    index 2f9f0f5..ae6e1a5 100644
    --- a/drivers/mtd/nand/nand_bbt.c
    +++ b/drivers/mtd/nand/nand_bbt.c
    @@ -171,16 +171,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
    if (tmp == msk)
    continue;
    if (reserved_block_code && (tmp == reserved_block_code)) {
    - printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
    - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
    + printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%016llx\n",
    + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
    this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
    mtd->ecc_stats.bbtblocks++;
    continue;
    }
    /* Leave it for now, if its matured we can move this
    * message to MTD_DEBUG_LEVEL0 */
    - printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
    - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
    + printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%016llx\n",
    + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
    /* Factory marked bad or worn out ? */
    if (tmp == 0)
    this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
    @@ -399,7 +399,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
    if (chip == -1) {
    /* Note that numblocks is 2 * (real numblocks) here, see i+=2
    * below as it makes shifting and masking less painful */
    - numblocks = mtd->size >> (this->bbt_erase_shift - 1);
    + numblocks = device_size(mtd) >> (this->bbt_erase_shift - 1);
    startblock = 0;
    from = 0;
    } else {
    @@ -428,8 +428,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,

    if (ret) {
    this->bbt[i >> 3] |= 0x03 << (i & 0x6);
    - printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
    - i >> 1, (unsigned int)from);
    + printk(KERN_WARNING "Bad eraseblock %d at 0x%016llx\n",
    + i >> 1, from);
    mtd->ecc_stats.badblocks++;
    }

    @@ -467,7 +467,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr

    /* Search direction top -> down ? */
    if (td->options & NAND_BBT_LASTBLOCK) {
    - startblock = (mtd->size >> this->bbt_erase_shift) - 1;
    + startblock = (device_size(mtd) >> this->bbt_erase_shift) - 1;
    dir = -1;
    } else {
    startblock = 0;
    @@ -481,7 +481,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
    startblock &= bbtblocks - 1;
    } else {
    chips = 1;
    - bbtblocks = mtd->size >> this->bbt_erase_shift;
    + bbtblocks = device_size(mtd) >> this->bbt_erase_shift;
    }

    /* Number of bits for each erase block in the bbt */
    @@ -587,7 +587,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
    chip = chipsel;
    }
    } else {
    - numblocks = (int)(mtd->size >> this->bbt_erase_shift);
    + numblocks = (int)(device_size(mtd) >> this->bbt_erase_shift);
    nrchips = 1;
    }

    @@ -719,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,

    memset(&einfo, 0, sizeof(einfo));
    einfo.mtd = mtd;
    - einfo.addr = (unsigned long)to;
    + einfo.addr = to;
    einfo.len = 1 << this->bbt_erase_shift;
    res = nand_erase_nand(mtd, &einfo, 1);
    if (res < 0)
    @@ -729,8 +729,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
    if (res < 0)
    goto outerr;

    - printk(KERN_DEBUG "Bad block table written to 0x%08x, version "
    - "0x%02X\n", (unsigned int)to, td->version[chip]);
    + printk(KERN_DEBUG "Bad block table written to 0x%016llx, version "
    + "0x%02X\n", to, td->version[chip]);

    /* Mark it as used */
    td->pages[chip] = page;
    @@ -896,7 +896,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
    nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
    } else {
    chips = 1;
    - nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
    + nrblocks = (int)(device_size(mtd) >> this->bbt_erase_shift);
    }

    for (i = 0; i < chips; i++) {
    @@ -957,7 +957,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
    struct nand_bbt_descr *td = this->bbt_td;
    struct nand_bbt_descr *md = this->bbt_md;

    - len = mtd->size >> (this->bbt_erase_shift + 2);
    + len = device_size(mtd) >> (this->bbt_erase_shift + 2);
    /* Allocate memory (2bit per block) and clear the memory bad block table */
    this->bbt = kzalloc(len, GFP_KERNEL);
    if (!this->bbt) {
    diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
    index c7630a2..6a576d8 100644
    --- a/drivers/mtd/ubi/build.c
    +++ b/drivers/mtd/ubi/build.c
    @@ -561,8 +561,9 @@ static int io_init(struct ubi_device *ubi)
    */

    ubi->peb_size = ubi->mtd->erasesize;
    - ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize;
    - ubi->flash_size = ubi->mtd->size;
    + ubi->peb_count = device_size(ubi->mtd) >>
    + (ffs(ubi->mtd->erasesize) - 1);
    + ubi->flash_size = device_size(ubi->mtd);

    if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
    ubi->bad_allowed = 1;
    diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
    index 9226365..ffa24b6 100644
    --- a/include/linux/mtd/mtd.h
    +++ b/include/linux/mtd/mtd.h
    @@ -26,13 +26,13 @@
    #define MTD_ERASE_FAILED 0x10

    /* If the erase fails, fail_addr might indicate exactly which block failed. If
    - fail_addr = 0xffffffff, the failure was not at the device level or was not
    + fail_addr = 0xffffffffffffffff, the failure was not at the device level or was not
    specific to any particular block. */
    struct erase_info {
    struct mtd_info *mtd;
    - u_int32_t addr;
    + u_int64_t addr;
    u_int32_t len;
    - u_int32_t fail_addr;
    + u_int64_t fail_addr;
    u_long time;
    u_long retries;
    u_int dev;
    @@ -101,6 +101,14 @@ struct mtd_info {
    u_int32_t flags;
    u_int32_t size; // Total size of the MTD

    + /* 'size' is becoming problematic as flash densities increase. Since
    + * the device's size can be calculated by multiplying the number of
    + * erase blocks by the size of the erase block, I've added a new
    + * field 'num_eraseblocks', and wrapped it up in a inline function
    + * (see below).
    + */
    + u_int64_t num_eraseblocks;
    +
    /* "Major" erase size for the device. Naïve users may take this
    * to be the only erase size available, or may use the more detailed
    * information below if they desire
    @@ -188,8 +196,8 @@ struct mtd_info {
    void (*sync) (struct mtd_info *mtd);

    /* Chip-supported device locking */
    - int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
    - int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
    + int (*lock) (struct mtd_info *mtd, loff_t ofs, u_int64_t len);
    + int (*unlock) (struct mtd_info *mtd, loff_t ofs, u_int64_t len);

    /* Power Management functions */
    int (*suspend) (struct mtd_info *mtd);
    @@ -219,6 +227,15 @@ struct mtd_info {
    void (*put_device) (struct mtd_info *mtd);
    };

    +/*
    + * Inline function for determining the size of the MTD device, independant
    + * of old or new way of doing things.
    + *
    + */
    +static inline u_int64_t device_size(struct mtd_info *a)
    +{
    + return a->num_eraseblocks == 0 ? a->size : a->num_eraseblocks * a->erasesize;
    +}

    /* Kernel-side ioctl definitions */

    diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
    index c6c61cd..86347cf 100644
    --- a/include/mtd/mtd-abi.h
    +++ b/include/mtd/mtd-abi.h
    @@ -6,7 +6,7 @@
    #define __MTD_ABI_H__

    struct erase_info_user {
    - uint32_t start;
    + uint64_t start;
    uint32_t length;
    };

    @@ -50,7 +50,7 @@ struct mtd_oob_buf {
    struct mtd_info_user {
    uint8_t type;
    uint32_t flags;
    - uint32_t size; // Total size of the MTD
    + uint64_t size; // Total size of the MTD
    uint32_t erasesize;
    uint32_t writesize;
    uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
    --
    1.5.3.4

    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2008-08-22 04:05    [W:0.047 / U:0.868 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site