]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mtd/mtdpart.c
[PATCH] fix silly ARM non-EABI build error
[linux-2.6-omap-h63xx.git] / drivers / mtd / mtdpart.c
index b92e6bfffaf2afa78cf3aad8fe38d7248509200c..77a7123a5c56514b75de1e519a22916add1dd228 100644 (file)
@@ -5,11 +5,11 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
+ * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $
  *
  *     02-21-2002      Thomas Gleixner <gleixner@autronix.de>
  *                     added support for read_oob, write_oob
- */    
+ */
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -41,29 +41,34 @@ struct mtd_part {
  */
 #define PART(x)  ((struct mtd_part *)(x))
 
-       
-/* 
+
+/*
  * MTD methods which simply translate the effective address and pass through
  * to the _real_ device.
  */
 
-static int part_read (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
+       int res;
+
        if (from >= mtd->size)
                len = 0;
        else if (from + len > mtd->size)
                len = mtd->size - from;
-       if (part->master->read_ecc == NULL)     
-               return part->master->read (part->master, from + part->offset, 
-                                       len, retlen, buf);
-       else
-               return part->master->read_ecc (part->master, from + part->offset, 
-                                       len, retlen, buf, NULL, &mtd->oobinfo);
+       res = part->master->read (part->master, from + part->offset,
+                                  len, retlen, buf);
+       if (unlikely(res)) {
+               if (res == -EUCLEAN)
+                       mtd->ecc_stats.corrected++;
+               if (res == -EBADMSG)
+                       mtd->ecc_stats.failed++;
+       }
+       return res;
 }
 
-static int part_point (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char **buf)
 {
        struct mtd_part *part = PART(mtd);
@@ -71,9 +76,10 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
                len = 0;
        else if (from + len > mtd->size)
                len = mtd->size - from;
-       return part->master->point (part->master, from + part->offset, 
+       return part->master->point (part->master, from + part->offset,
                                    len, retlen, buf);
 }
+
 static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
        struct mtd_part *part = PART(mtd);
@@ -81,38 +87,32 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
        part->master->unpoint (part->master, addr, from + part->offset, len);
 }
 
-
-static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, 
-                       size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
+static int part_read_oob(struct mtd_info *mtd, loff_t from,
+                        struct mtd_oob_ops *ops)
 {
        struct mtd_part *part = PART(mtd);
-       if (oobsel == NULL)
-               oobsel = &mtd->oobinfo;
-       if (from >= mtd->size)
-               len = 0;
-       else if (from + len > mtd->size)
-               len = mtd->size - from;
-       return part->master->read_ecc (part->master, from + part->offset, 
-                                       len, retlen, buf, eccbuf, oobsel);
-}
+       int res;
 
-static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 
-                       size_t *retlen, u_char *buf)
-{
-       struct mtd_part *part = PART(mtd);
        if (from >= mtd->size)
-               len = 0;
-       else if (from + len > mtd->size)
-               len = mtd->size - from;
-       return part->master->read_oob (part->master, from + part->offset, 
-                                       len, retlen, buf);
+               return -EINVAL;
+       if (from + ops->len > mtd->size)
+               return -EINVAL;
+       res = part->master->read_oob(part->master, from + part->offset, ops);
+
+       if (unlikely(res)) {
+               if (res == -EUCLEAN)
+                       mtd->ecc_stats.corrected++;
+               if (res == -EBADMSG)
+                       mtd->ecc_stats.failed++;
+       }
+       return res;
 }
 
-static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->read_user_prot_reg (part->master, from, 
+       return part->master->read_user_prot_reg (part->master, from,
                                        len, retlen, buf);
 }
 
@@ -123,11 +123,11 @@ static int part_get_user_prot_info (struct mtd_info *mtd,
        return part->master->get_user_prot_info (part->master, buf, len);
 }
 
-static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->read_fact_prot_reg (part->master, from, 
+       return part->master->read_fact_prot_reg (part->master, from,
                                        len, retlen, buf);
 }
 
@@ -148,55 +148,34 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
                len = 0;
        else if (to + len > mtd->size)
                len = mtd->size - to;
-       if (part->master->write_ecc == NULL)    
-               return part->master->write (part->master, to + part->offset, 
-                                       len, retlen, buf);
-       else
-               return part->master->write_ecc (part->master, to + part->offset, 
-                                       len, retlen, buf, NULL, &mtd->oobinfo);
-                                                       
+       return part->master->write (part->master, to + part->offset,
+                                   len, retlen, buf);
 }
 
-static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-                       size_t *retlen, const u_char *buf,
-                        u_char *eccbuf, struct nand_oobinfo *oobsel)
+static int part_write_oob(struct mtd_info *mtd, loff_t to,
+                        struct mtd_oob_ops *ops)
 {
        struct mtd_part *part = PART(mtd);
-       if (!(mtd->flags & MTD_WRITEABLE))
-               return -EROFS;
-       if (oobsel == NULL)
-               oobsel = &mtd->oobinfo;
-       if (to >= mtd->size)
-               len = 0;
-       else if (to + len > mtd->size)
-               len = mtd->size - to;
-       return part->master->write_ecc (part->master, to + part->offset, 
-                                       len, retlen, buf, eccbuf, oobsel);
-}
 
-static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
-                       size_t *retlen, const u_char *buf)
-{
-       struct mtd_part *part = PART(mtd);
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
+
        if (to >= mtd->size)
-               len = 0;
-       else if (to + len > mtd->size)
-               len = mtd->size - to;
-       return part->master->write_oob (part->master, to + part->offset, 
-                                       len, retlen, buf);
+               return -EINVAL;
+       if (to + ops->len > mtd->size)
+               return -EINVAL;
+       return part->master->write_oob(part->master, to + part->offset, ops);
 }
 
-static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->write_user_prot_reg (part->master, from, 
+       return part->master->write_user_prot_reg (part->master, from,
                                        len, retlen, buf);
 }
 
-static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) 
+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
 {
        struct mtd_part *part = PART(mtd);
        return part->master->lock_user_prot_reg (part->master, from, len);
@@ -208,52 +187,8 @@ static int part_writev (struct mtd_info *mtd,  const struct kvec *vecs,
        struct mtd_part *part = PART(mtd);
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
-       if (part->master->writev_ecc == NULL)   
-               return part->master->writev (part->master, vecs, count,
+       return part->master->writev (part->master, vecs, count,
                                        to + part->offset, retlen);
-       else
-               return part->master->writev_ecc (part->master, vecs, count,
-                                       to + part->offset, retlen,
-                                       NULL, &mtd->oobinfo);
-}
-
-static int part_readv (struct mtd_info *mtd,  struct kvec *vecs,
-                        unsigned long count, loff_t from, size_t *retlen)
-{
-       struct mtd_part *part = PART(mtd);
-       if (part->master->readv_ecc == NULL)    
-               return part->master->readv (part->master, vecs, count,
-                                       from + part->offset, retlen);
-       else
-               return part->master->readv_ecc (part->master, vecs, count,
-                                       from + part->offset, retlen, 
-                                       NULL, &mtd->oobinfo);
-}
-
-static int part_writev_ecc (struct mtd_info *mtd,  const struct kvec *vecs,
-                        unsigned long count, loff_t to, size_t *retlen,
-                        u_char *eccbuf,  struct nand_oobinfo *oobsel)
-{
-       struct mtd_part *part = PART(mtd);
-       if (!(mtd->flags & MTD_WRITEABLE))
-               return -EROFS;
-       if (oobsel == NULL)
-               oobsel = &mtd->oobinfo;
-       return part->master->writev_ecc (part->master, vecs, count,
-                                       to + part->offset, retlen,
-                                       eccbuf, oobsel);
-}
-
-static int part_readv_ecc (struct mtd_info *mtd,  struct kvec *vecs,
-                        unsigned long count, loff_t from, size_t *retlen,
-                        u_char *eccbuf,  struct nand_oobinfo *oobsel)
-{
-       struct mtd_part *part = PART(mtd);
-       if (oobsel == NULL)
-               oobsel = &mtd->oobinfo;
-       return part->master->readv_ecc (part->master, vecs, count,
-                                       from + part->offset, retlen, 
-                                       eccbuf, oobsel);
 }
 
 static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
@@ -286,7 +221,7 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
 static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
 {
        struct mtd_part *part = PART(mtd);
-       if ((len + ofs) > mtd->size) 
+       if ((len + ofs) > mtd->size)
                return -EINVAL;
        return part->master->lock(part->master, ofs + part->offset, len);
 }
@@ -294,7 +229,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
 static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
 {
        struct mtd_part *part = PART(mtd);
-       if ((len + ofs) > mtd->size) 
+       if ((len + ofs) > mtd->size)
                return -EINVAL;
        return part->master->unlock(part->master, ofs + part->offset, len);
 }
@@ -329,16 +264,21 @@ static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
 static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
 {
        struct mtd_part *part = PART(mtd);
+       int res;
+
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
        if (ofs >= mtd->size)
                return -EINVAL;
        ofs += part->offset;
-       return part->master->block_markbad(part->master, ofs);
+       res = part->master->block_markbad(part->master, ofs);
+       if (!res)
+               mtd->ecc_stats.badblocks++;
+       return res;
 }
 
-/* 
- * This function unregisters and destroy all slave MTD objects which are 
+/*
+ * This function unregisters and destroy all slave MTD objects which are
  * attached to the given master MTD object.
  */
 
@@ -371,7 +311,7 @@ int del_mtd_partitions(struct mtd_info *master)
  * (Q: should we register the master MTD object as well?)
  */
 
-int add_mtd_partitions(struct mtd_info *master, 
+int add_mtd_partitions(struct mtd_info *master,
                       const struct mtd_partition *parts,
                       int nbparts)
 {
@@ -398,7 +338,7 @@ int add_mtd_partitions(struct mtd_info *master,
                slave->mtd.type = master->type;
                slave->mtd.flags = master->flags & ~parts[i].mask_flags;
                slave->mtd.size = parts[i].size;
-               slave->mtd.oobblock = master->oobblock;
+               slave->mtd.writesize = master->writesize;
                slave->mtd.oobsize = master->oobsize;
                slave->mtd.ecctype = master->ecctype;
                slave->mtd.eccsize = master->eccsize;
@@ -414,11 +354,7 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.point = part_point;
                        slave->mtd.unpoint = part_unpoint;
                }
-               
-               if (master->read_ecc)
-                       slave->mtd.read_ecc = part_read_ecc;
-               if (master->write_ecc)
-                       slave->mtd.write_ecc = part_write_ecc;
+
                if (master->read_oob)
                        slave->mtd.read_oob = part_read_oob;
                if (master->write_oob)
@@ -443,12 +379,6 @@ int add_mtd_partitions(struct mtd_info *master,
                }
                if (master->writev)
                        slave->mtd.writev = part_writev;
-               if (master->readv)
-                       slave->mtd.readv = part_readv;
-               if (master->writev_ecc)
-                       slave->mtd.writev_ecc = part_writev_ecc;
-               if (master->readv_ecc)
-                       slave->mtd.readv_ecc = part_readv_ecc;
                if (master->lock)
                        slave->mtd.lock = part_lock;
                if (master->unlock)
@@ -465,9 +395,10 @@ int add_mtd_partitions(struct mtd_info *master,
                if (slave->offset == MTDPART_OFS_APPEND)
                        slave->offset = cur_offset;
                if (slave->offset == MTDPART_OFS_NXTBLK) {
-                       u_int32_t emask = master->erasesize-1;
-                       slave->offset = (cur_offset + emask) & ~emask;
-                       if (slave->offset != cur_offset) {
+                       slave->offset = cur_offset;
+                       if ((cur_offset % master->erasesize) != 0) {
+                               /* Round up to next erasesize */
+                               slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
                                printk(KERN_NOTICE "Moving partition %d: "
                                       "0x%08x -> 0x%08x\n", i,
                                       cur_offset, slave->offset);
@@ -476,8 +407,8 @@ int add_mtd_partitions(struct mtd_info *master,
                if (slave->mtd.size == MTDPART_SIZ_FULL)
                        slave->mtd.size = master->size - slave->offset;
                cur_offset = slave->offset + slave->mtd.size;
-       
-               printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, 
+
+               printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
                        slave->offset + slave->mtd.size, slave->mtd.name);
 
                /* let's do some sanity checks */
@@ -497,7 +428,7 @@ int add_mtd_partitions(struct mtd_info *master,
                        /* Deal with variable erase size stuff */
                        int i;
                        struct mtd_erase_region_info *regions = master->eraseregions;
-                       
+
                        /* Find the first erase regions which is part of this partition. */
                        for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
                                ;
@@ -512,7 +443,7 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.erasesize = master->erasesize;
                }
 
-               if ((slave->mtd.flags & MTD_WRITEABLE) && 
+               if ((slave->mtd.flags & MTD_WRITEABLE) &&
                    (slave->offset % slave->mtd.erasesize)) {
                        /* Doesn't start on a boundary of major erase size */
                        /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
@@ -520,15 +451,24 @@ int add_mtd_partitions(struct mtd_info *master,
                        printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
                                parts[i].name);
                }
-               if ((slave->mtd.flags & MTD_WRITEABLE) && 
+               if ((slave->mtd.flags & MTD_WRITEABLE) &&
                    (slave->mtd.size % slave->mtd.erasesize)) {
                        slave->mtd.flags &= ~MTD_WRITEABLE;
                        printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
                                parts[i].name);
                }
 
-               /* copy oobinfo from master */ 
-               memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
+               slave->mtd.ecclayout = master->ecclayout;
+               if (master->block_isbad) {
+                       uint32_t offs = 0;
+
+                       while(offs < slave->mtd.size) {
+                               if (master->block_isbad(master,
+                                                       offs + slave->offset))
+                                       slave->mtd.ecc_stats.badblocks++;
+                               offs += slave->mtd.erasesize;
+                       }
+               }
 
                if(parts[i].mtdp)
                {       /* store the object pointer (caller may or may not register it */
@@ -588,12 +528,12 @@ int deregister_mtd_parser(struct mtd_part_parser *p)
        return 0;
 }
 
-int parse_mtd_partitions(struct mtd_info *master, const char **types, 
+int parse_mtd_partitions(struct mtd_info *master, const char **types,
                         struct mtd_partition **pparts, unsigned long origin)
 {
        struct mtd_part_parser *parser;
        int ret = 0;
-               
+
        for ( ; ret <= 0 && *types; types++) {
                parser = get_partition_parser(*types);
 #ifdef CONFIG_KMOD
@@ -607,7 +547,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
                }
                ret = (*parser->parse_fn)(master, pparts, origin);
                if (ret > 0) {
-                       printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", 
+                       printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
                               ret, parser->name, master->name);
                }
                put_partition_parser(parser);