mtd: nand: teach write_page and write_page_raw return an error code
authorJosh Wu <josh.wu@atmel.com>
Mon, 25 Jun 2012 10:07:45 +0000 (18:07 +0800)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Fri, 6 Jul 2012 17:17:07 +0000 (18:17 +0100)
There is an implemention of hardware ECC write page function which may return an
error indication.
For instance, using Atmel HW PMECC to write one page into a nand flash, the hardware
engine will compute the BCH ecc code for this page. so we need read a the
status register to theck whether the ecc code is generated.
But we cannot assume the status register always can be ready, for example,
incorrect hardware configuration or hardware issue, in such case we need
write_page() to return a error code.

Since the definition of 'write_page' function in struct nand_ecc_ctrl is 'void'.
So this patch will:
  1. add return 'int' value for 'write_page' function.
  2. to be consitent, add return 'int' value for 'write_page_raw' fuctions too.
  3. add code to test the return value, and if negative, indicate an
  error happend when write page with ECC.
  4. fix the compile warning in all impacted nand flash driver.

Note: I couldn't compile-test all of these easily, as some had ARCH dependencies.

Signed-off-by: Josh Wu <josh.wu@atmel.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
12 files changed:
drivers/mtd/nand/bcm_umi_bch.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/sh_flctl.c
include/linux/mtd/nand.h

index 5914bb32e0014e189cd42aafd34017698222dd27..c8799a001833f71ec2b5a34ee6ea46c8486f351b 100644 (file)
@@ -23,7 +23,7 @@
 /* ---- Private Function Prototypes -------------------------------------- */
 static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
        struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
-static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
+static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
        struct nand_chip *chip, const uint8_t *buf, int oob_required);
 
 /* ---- Private Variables ------------------------------------------------ */
@@ -194,7 +194,7 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
 *  @oob_required:      must write chip->oob_poi to OOB
 *
 ***************************************************************************/
-static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
+static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
        struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
        int sectorIdx = 0;
@@ -214,4 +214,6 @@ static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
        }
 
        bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
index 3f1c18599cbd9484096caed856f69c79c61c2bff..ab0caa74eb43e428b57e298b1ff29d4b7a38a0a0 100644 (file)
@@ -566,11 +566,13 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip
        return 0;
 }
 
-static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-               const uint8_t *buf, int oob_required)
+static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
+               struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
        bf5xx_nand_write_buf(mtd, buf, mtd->writesize);
        bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 /*
index ac0d967ee3fd175a160f29abe9173e9b76f6c53a..08248a0a167e00e68cde8e7c767cabd0dab8cb12 100644 (file)
@@ -520,7 +520,7 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
 };
 
 
-static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
+static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
                                          struct nand_chip *chip,
                                          const uint8_t *buf, int oob_required)
 {
@@ -531,6 +531,8 @@ static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
 
        /* Set up ECC autogeneration */
        cafe->ctl2 |= (1<<30);
+
+       return 0;
 }
 
 static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
@@ -542,9 +544,12 @@ static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
        if (unlikely(raw))
-               chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
        else
-               chip->ecc.write_page(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+       if (status < 0)
+               return status;
 
        /*
         * Cached progamming disabled for now, Not sure if its worth the
index 0650aafa0dd2238b2af08a1328970e5efb38d24e..e706a237170f503142089cb5644fe2957cafae07 100644 (file)
@@ -1028,7 +1028,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
 
 /* writes a page. user specifies type, and this function handles the
  * configuration details. */
-static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
                        const uint8_t *buf, bool raw_xfer)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
@@ -1078,6 +1078,8 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        denali_enable_dma(denali, false);
        dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE);
+
+       return 0;
 }
 
 /* NAND core entry points */
@@ -1086,24 +1088,24 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
  * writing a page with ECC or without is similar, all the work is done
  * by write_page above.
  * */
-static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
        /* for regular page writes, we let HW handle all the ECC
         * data written to the device. */
-       write_page(mtd, chip, buf, false);
+       return write_page(mtd, chip, buf, false);
 }
 
 /* This is the callback that the NAND core calls to write a page without ECC.
  * raw access is similar to ECC page writes, so all the work is done in the
  * write_page() function above.
  */
-static void denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
                                        const uint8_t *buf, int oob_required)
 {
        /* for raw page writes, we want to disable ECC and simply write
           whatever data is in the buffer. */
-       write_page(mtd, chip, buf, true);
+       return write_page(mtd, chip, buf, true);
 }
 
 static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
index a225e49a56235763b35cfd5118f30f7c20c4fb55..0f2ffd7b6c822c55d0309338f2f4d3f834fbf4a6 100644 (file)
@@ -898,7 +898,7 @@ static void docg4_erase_block(struct mtd_info *mtd, int page)
        write_nop(docptr);
 }
 
-static void write_page(struct mtd_info *mtd, struct nand_chip *nand,
+static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
                       const uint8_t *buf, bool use_ecc)
 {
        struct docg4_priv *doc = nand->priv;
@@ -950,15 +950,17 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand,
        write_nop(docptr);
        writew(0, docptr + DOC_DATAEND);
        write_nop(docptr);
+
+       return 0;
 }
 
-static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
                                 const uint8_t *buf, int oob_required)
 {
        return write_page(mtd, nand, buf, false);
 }
 
-static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
+static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
                             const uint8_t *buf, int oob_required)
 {
        return write_page(mtd, nand, buf, true);
index 22bb5e6ddaca3ec5684d80806a8c1061375ed908..8143873d17a5c2bebc19c140445a5ad30fac8dee 100644 (file)
@@ -766,11 +766,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 /* ECC will be calculated automatically, and errors will be detected in
  * waitfunc.
  */
-static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
        fsl_elbc_write_buf(mtd, buf, mtd->writesize);
        fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
index c5d7f382759d5753b7f62690f9059b218bd2aced..1f71b545062aa0e548b7cca6de6a0d763a357826 100644 (file)
@@ -721,11 +721,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 /* ECC will be calculated automatically, and errors will be detected in
  * waitfunc.
  */
-static void fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                               const uint8_t *buf, int oob_required)
 {
        fsl_ifc_write_buf(mtd, buf, mtd->writesize);
        fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
index 6574c6f51b8b4b1fd516c3126da32f5ae2c9e1bf..d6fa8f4779ce62148ce5224fa36f9533d9c064ef 100644 (file)
@@ -930,7 +930,7 @@ exit_nfc:
        return ret;
 }
 
-static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
        struct gpmi_nand_data *this = chip->priv;
@@ -972,7 +972,7 @@ static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                &payload_virt, &payload_phys);
                if (ret) {
                        pr_err("Inadequate payload DMA buffer\n");
-                       return;
+                       return 0;
                }
 
                ret = send_page_prepare(this,
@@ -1002,6 +1002,8 @@ exit_auxiliary:
                                nfc_geo->payload_size,
                                payload_virt, payload_phys);
        }
+
+       return 0;
 }
 
 /*
index 0a8724e657d7d8529351b42419a5f40968225b39..98ba46ecd5d85e082f80bf92c26ce2f2351c9717 100644 (file)
@@ -1911,12 +1911,14 @@ out:
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        if (oob_required)
                chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 /**
@@ -1928,7 +1930,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
  *
  * We need a special oob layout and handling even when ECC isn't checked.
  */
-static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
+static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
                                        struct nand_chip *chip,
                                        const uint8_t *buf, int oob_required)
 {
@@ -1958,6 +1960,8 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
        size = mtd->oobsize - (oob - chip->oob_poi);
        if (size)
                chip->write_buf(mtd, oob, size);
+
+       return 0;
 }
 /**
  * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
@@ -1966,7 +1970,7 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
  */
-static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
                                  const uint8_t *buf, int oob_required)
 {
        int i, eccsize = chip->ecc.size;
@@ -1983,7 +1987,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0; i < chip->ecc.total; i++)
                chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
-       chip->ecc.write_page_raw(mtd, chip, buf, 1);
+       return chip->ecc.write_page_raw(mtd, chip, buf, 1);
 }
 
 /**
@@ -1993,7 +1997,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
  */
-static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                                  const uint8_t *buf, int oob_required)
 {
        int i, eccsize = chip->ecc.size;
@@ -2013,6 +2017,8 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 /**
@@ -2025,7 +2031,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * The hw generator calculates the error syndrome automatically. Therefore we
  * need a special oob layout and handling.
  */
-static void nand_write_page_syndrome(struct mtd_info *mtd,
+static int nand_write_page_syndrome(struct mtd_info *mtd,
                                    struct nand_chip *chip,
                                    const uint8_t *buf, int oob_required)
 {
@@ -2059,6 +2065,8 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
        i = mtd->oobsize - (oob - chip->oob_poi);
        if (i)
                chip->write_buf(mtd, oob, i);
+
+       return 0;
 }
 
 /**
@@ -2080,9 +2088,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
        if (unlikely(raw))
-               chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
        else
-               chip->ecc.write_page(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+       if (status < 0)
+               return status;
 
        /*
         * Cached progamming disabled for now. Not sure if it's worth the
index afc4681f44d71ac30ebac525d44b17b3cc5c3ab3..e8a1ae97a95293bb91516096d76e8fe61e1c6144 100644 (file)
@@ -681,11 +681,13 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
        info->state = STATE_IDLE;
 }
 
-static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
+static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
                struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
index 2eb15418c2274def800076d02ddc26dd5bd6f831..ed03ed2355de2e60b5d1eb87234e3b62591c9ca4 100644 (file)
@@ -399,11 +399,12 @@ static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
        return 0;
 }
 
-static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                                   const uint8_t *buf, int oob_required)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       return 0;
 }
 
 static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
index a81ac89a69508da3ba9579f46fd43a100ee339fc..6dce5a7154bbd95bea5498371cb60b18b3185a4b 100644 (file)
@@ -355,13 +355,13 @@ struct nand_ecc_ctrl {
                        uint8_t *calc_ecc);
        int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint8_t *buf, int oob_required, int page);
-       void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+       int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
                        const uint8_t *buf, int oob_required);
        int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint8_t *buf, int oob_required, int page);
        int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint32_t offs, uint32_t len, uint8_t *buf);
-       void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+       int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
                        const uint8_t *buf, int oob_required);
        int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
                        int page);