diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 10:24:08 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 10:24:08 -0800 |
commit | b3ce1debe2685383a9ad6ace9c49869c3968c013 (patch) | |
tree | dcb606fac467d6ce78a9c608a1e0d2323af44f2b /drivers/mtd/nand/nand_base.c | |
parent | 5b2f7ffcb734d3046144dfbd5ac6d76254a9e522 (diff) | |
parent | c2965f1129ee54afcc4ef293ff0f25fa3a7e7392 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6
Some manual fixups for clashing kfree() cleanups etc.
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 529 |
1 files changed, 282 insertions, 247 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8e78d7b96a5..5d222460b42 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -5,14 +5,14 @@ * This is the generic MTD driver for NAND flash devices. It should be * capable of working with almost all NAND chips currently available. * Basic support for AG-AND chips is provided. - * + * * Additional technical information is available on * http://www.linux-mtd.infradead.org/tech/nand.html - * + * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * 2002 Thomas Gleixner (tglx@linutronix.de) * - * 02-08-2004 tglx: support for strange chips, which cannot auto increment + * 02-08-2004 tglx: support for strange chips, which cannot auto increment * pages on read / read_oob * * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes @@ -21,7 +21,7 @@ * Make reads over block boundaries work too * * 04-14-2004 tglx: first working version for 2k page size chips - * + * * 05-19-2004 tglx: Basic support for Renesas AG-AND chips * * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared @@ -30,25 +30,27 @@ * * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. * Basically, any block not rewritten may lose data when surrounding blocks - * are rewritten many times. JFFS2 ensures this doesn't happen for blocks + * are rewritten many times. JFFS2 ensures this doesn't happen for blocks * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they * do not lose data, force them to be rewritten when some of the surrounding - * blocks are erased. Rather than tracking a specific nearby block (which - * could itself go bad), use a page address 'mask' to select several blocks + * blocks are erased. Rather than tracking a specific nearby block (which + * could itself go bad), use a page address 'mask' to select several blocks * in the same area, and rewrite the BBT when any of them are erased. * - * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas + * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas * AG-AND chips. If there was a sudden loss of power during an erase operation, * a "device recovery" operation must be performed when power is restored * to ensure correct operation. * - * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to + * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to * perform extra error status checks on erase and write failures. This required * adding a wrapper function for nand_read_ecc. * + * 08-20-2005 vwool: suspend/resume added + * * Credits: - * David Woodhouse for adding multichip support - * + * David Woodhouse for adding multichip support + * * Aleph One Ltd. and Toby Churchill Ltd. for supporting the * rework for 2K page size chips * @@ -59,7 +61,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.147 2005/07/15 07:18:06 gleixner Exp $ + * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -103,8 +105,8 @@ static struct nand_oobinfo nand_oob_64 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 24, .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, .oobfree = { {2, 38} } }; @@ -147,19 +149,19 @@ static void nand_sync (struct mtd_info *mtd); static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int mode); #ifdef CONFIG_MTD_NAND_VERIFY_WRITE -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); #else #define nand_verify_pages(...) (0) #endif - -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); + +static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); /** * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure - * - * Deselect, release chip lock and wake up anyone waiting on the device + * + * Deselect, release chip lock and wake up anyone waiting on the device */ static void nand_release_device (struct mtd_info *mtd) { @@ -213,7 +215,7 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte) * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith with + * Default read function for 16bit buswith with * endianess conversion */ static u_char nand_read_byte16(struct mtd_info *mtd) @@ -240,7 +242,7 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte) * nand_read_word - [DEFAULT] read one word from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith without + * Default read function for 16bit buswith without * endianess conversion */ static u16 nand_read_word(struct mtd_info *mtd) @@ -254,7 +256,7 @@ static u16 nand_read_word(struct mtd_info *mtd) * @mtd: MTD device structure * @word: data word to write * - * Default write function for 16bit buswith without + * Default write function for 16bit buswith without * endianess conversion */ static void nand_write_word(struct mtd_info *mtd, u16 word) @@ -275,7 +277,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) struct nand_chip *this = mtd->priv; switch(chip) { case -1: - this->hwcontrol(mtd, NAND_CTL_CLRNCE); + this->hwcontrol(mtd, NAND_CTL_CLRNCE); break; case 0: this->hwcontrol(mtd, NAND_CTL_SETNCE); @@ -304,7 +306,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) } /** - * nand_read_buf - [DEFAULT] read chip data into buffer + * nand_read_buf - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -321,7 +323,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) } /** - * nand_verify_buf - [DEFAULT] Verify chip data against buffer + * nand_verify_buf - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -354,14 +356,14 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; - + for (i=0; i<len; i++) writew(p[i], this->IO_ADDR_W); - + } /** - * nand_read_buf16 - [DEFAULT] read chip data into buffer + * nand_read_buf16 - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -380,7 +382,7 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) } /** - * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer + * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -407,7 +409,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) * @ofs: offset from device start * @getchip: 0, if the chip is already selected * - * Check, if the block is bad. + * Check, if the block is bad. */ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) { @@ -424,14 +426,14 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /* Select the NAND device */ this->select_chip(mtd, chipnr); - } else - page = (int) ofs; + } else + page = (int) ofs; if (this->options & NAND_BUSWIDTH_16) { this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); bad = cpu_to_le16(this->read_word(mtd)); if (this->badblockpos & 0x1) - bad >>= 1; + bad >>= 8; if ((bad & 0xFF) != 0xff) res = 1; } else { @@ -439,12 +441,12 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) if (this->read_byte(mtd) != 0xff) res = 1; } - + if (getchip) { /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); - } - + } + return res; } @@ -462,7 +464,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) u_char buf[2] = {0, 0}; size_t retlen; int block; - + /* Get block number */ block = ((int) ofs) >> this->bbt_erase_shift; if (this->bbt) @@ -471,25 +473,25 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) return nand_update_bbt (mtd, ofs); - + /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (this->badblockpos & ~0x01); return nand_write_oob (mtd, ofs , 2, &retlen, buf); } -/** +/** * nand_check_wp - [GENERIC] check if the chip is write protected * @mtd: MTD device structure - * Check, if the device is write protected + * Check, if the device is write protected * - * The function expects, that the device is already selected + * The function expects, that the device is already selected */ static int nand_check_wp (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; + return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; } /** @@ -505,15 +507,15 @@ static int nand_check_wp (struct mtd_info *mtd) static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) { struct nand_chip *this = mtd->priv; - + if (!this->bbt) return this->block_bad(mtd, ofs, getchip); - + /* Return info from the table */ return nand_isbad_bbt (mtd, ofs, allowbbt); } -/* +/* * Wait for the ready pin, after a command * The timeout is catched later. */ @@ -527,7 +529,7 @@ static void nand_wait_ready(struct mtd_info *mtd) if (this->dev_ready(mtd)) return; touch_softlockup_watchdog(); - } while (time_before(jiffies, timeo)); + } while (time_before(jiffies, timeo)); } /** @@ -590,13 +592,13 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } - - /* - * program and erase have their own busy handlers + + /* + * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { - + case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: @@ -605,7 +607,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in return; case NAND_CMD_RESET: - if (this->dev_ready) + if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); @@ -614,16 +616,16 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); return; - /* This applies to read commands */ + /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; - } + } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ @@ -653,8 +655,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, column += mtd->oobblock; command = NAND_CMD_READ0; } - - + + /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the command to the device. */ @@ -672,7 +674,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, column >>= 1; this->write_byte(mtd, column & 0xff); this->write_byte(mtd, column >> 8); - } + } if (page_addr != -1) { this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); @@ -683,13 +685,13 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } - - /* - * program and erase have their own busy handlers + + /* + * program and erase have their own busy handlers * status, sequential in, and deplete1 need no delay */ switch (command) { - + case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: @@ -699,7 +701,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, case NAND_CMD_DEPLETE1: return; - /* + /* * read error status commands require only a short delay */ case NAND_CMD_STATUS_ERROR: @@ -711,7 +713,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, return; case NAND_CMD_RESET: - if (this->dev_ready) + if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); @@ -728,17 +730,17 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); /* Fall through into ready check */ - - /* This applies to read commands */ + + /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; - } + } } /* Apply this short delay always to ensure that we do wait tWB in @@ -752,11 +754,11 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, * nand_get_device - [GENERIC] Get chip for selected access * @this: the nand chip descriptor * @mtd: MTD device structure - * @new_state: the state which is requested + * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) +static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) { struct nand_chip *active; spinlock_t *lock; @@ -779,7 +781,11 @@ retry: if (active == this && this->state == FL_READY) { this->state = new_state; spin_unlock(lock); - return; + return 0; + } + if (new_state == FL_PM_SUSPENDED) { + spin_unlock(lock); + return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; } set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(wq, &wait); @@ -796,7 +802,7 @@ retry: * @state: state to select the max. timeout value * * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to + * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs * */ @@ -805,7 +811,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) unsigned long timeo = jiffies; int status; - + if (state == FL_ERASING) timeo += (HZ * 400) / 1000; else @@ -817,17 +823,17 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); - else + else this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - while (time_before(jiffies, timeo)) { + while (time_before(jiffies, timeo)) { /* Check, if we were interrupted */ if (this->state != state) return 0; if (this->dev_ready) { if (this->dev_ready(mtd)) - break; + break; } else { if (this->read_byte(mtd) & NAND_STATUS_READY) break; @@ -853,7 +859,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) * * Cached programming is not supported yet. */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, +static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { int i, status; @@ -862,10 +868,10 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa int *oob_config = oobsel->eccpos; int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; int eccbytes = 0; - + /* FIXME: Enable cached programming */ cached = 0; - + /* Send command to begin auto page programming */ this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); @@ -876,7 +882,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); this->write_buf(mtd, this->data_poi, mtd->oobblock); break; - + /* Software ecc 3/256, write all */ case NAND_ECC_SOFT: for (; eccsteps; eccsteps--) { @@ -905,11 +911,11 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa } break; } - + /* Write out OOB data */ if (this->options & NAND_HWECC_SYNDROME) this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); - else + else this->write_buf(mtd, oob_buf, mtd->oobsize); /* Send command to actually program the data */ @@ -934,7 +940,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa /* wait until cache is ready*/ // status = this->waitfunc (mtd, this, FL_CACHEDRPG); } - return 0; + return 0; } #ifdef CONFIG_MTD_NAND_VERIFY_WRITE @@ -950,19 +956,19 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa * @oobmode: 1 = full buffer verify, 0 = ecc only * * The NAND device assumes that it is always writing to a cleanly erased page. - * Hence, it performs its internal write verification only on bits that + * Hence, it performs its internal write verification only on bits that * transitioned from 1 to 0. The device does NOT verify the whole page on a - * byte by byte basis. It is possible that the page was not completely erased - * or the page is becoming unusable due to wear. The read with ECC would catch - * the error later when the ECC page check fails, but we would rather catch + * byte by byte basis. It is possible that the page was not completely erased + * or the page is becoming unusable due to wear. The read with ECC would catch + * the error later when the ECC page check fails, but we would rather catch * it early in the page write stage. Better to write no data than invalid data. */ -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) { int i, j, datidx = 0, oobofs = 0, res = -EIO; int eccsteps = this->eccsteps; - int hweccbytes; + int hweccbytes; u_char oobdata[64]; hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; @@ -1002,7 +1008,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { int ecccnt = oobsel->eccbytes; - + for (i = 0; i < ecccnt; i++) { int idx = oobsel->eccpos[i]; if (oobdata[idx] != oob_buf[oobofs + idx] ) { @@ -1012,20 +1018,20 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int goto out; } } - } + } } oobofs += mtd->oobsize - hweccbytes * eccsteps; page++; numpages--; - /* Apply delay or wait for ready/busy pin + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. * Do this also before returning, so the chip is * ready for the next command. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else nand_wait_ready(mtd); @@ -1033,17 +1039,17 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int /* All done, return happy */ if (!numpages) return 0; - - - /* Check, if the chip supports auto page increment */ + + + /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this)) this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); } - /* + /* * Terminate the read command. We come here in case of an error * So we must issue a reset command. */ -out: +out: this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); return res; } @@ -1105,7 +1111,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * NAND read with ECC */ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf, u_char * oob_buf, + size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel, int flags) { @@ -1139,7 +1145,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) oobsel = this->autooob; - + eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; oob_config = oobsel->eccpos; @@ -1157,28 +1163,28 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, end = mtd->oobblock; ecc = this->eccsize; eccbytes = this->eccbytes; - + if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) compareecc = 0; oobreadlen = mtd->oobsize; - if (this->options & NAND_HWECC_SYNDROME) + if (this->options & NAND_HWECC_SYNDROME) oobreadlen -= oobsel->eccbytes; /* Loop until all data read */ while (read < len) { - + int aligned = (!col && (len - read) >= end); - /* + /* * If the read is not page aligned, we have to read into data buffer * due to ecc, else we read into return buffer direct */ if (aligned) data_poi = &buf[read]; - else + else data_poi = this->data_buf; - - /* Check, if we have this page in the buffer + + /* Check, if we have this page in the buffer * * FIXME: Make it work when we must provide oob data too, * check the usage of data_buf oob field @@ -1194,7 +1200,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, if (sndcmd) { this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); sndcmd = 0; - } + } /* get oob area, if we have no oob buffer from fs-driver */ if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || @@ -1202,7 +1208,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, oob_data = &this->data_buf[end]; eccsteps = this->eccsteps; - + switch (eccmode) { case NAND_ECC_NONE: { /* No ECC, Read in a page */ static unsigned long lastwhinge = 0; @@ -1213,12 +1219,12 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, this->read_buf(mtd, data_poi, end); break; } - + case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ this->read_buf(mtd, data_poi, end); - for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) + for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); - break; + break; default: for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { @@ -1237,15 +1243,15 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * does the error correction on the fly */ ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; } } else { this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); - } + } } - break; + break; } /* read oobdata */ @@ -1253,8 +1259,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ if (!compareecc) - goto readoob; - + goto readoob; + /* Pick the ECC bytes out of the oob data */ for (j = 0; j < oobsel->eccbytes; j++) ecc_code[j] = oob_data[oob_config[j]]; @@ -1262,24 +1268,24 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* correct data, if neccecary */ for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); - + /* Get next chunk of ecc bytes */ j += eccbytes; - - /* Check, if we have a fs supplied oob-buffer, + + /* Check, if we have a fs supplied oob-buffer, * This is the legacy mode. Used by YAFFS1 * Should go away some day */ - if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { + if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { int *p = (int *)(&oob_data[mtd->oobsize]); p[i] = ecc_status; } - - if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { + + if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } - } + } readoob: /* check, if we have a fs supplied oob-buffer */ @@ -1305,25 +1311,25 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } readdata: /* Partial page read, transfer data into fs buffer */ - if (!aligned) { + if (!aligned) { for (j = col; j < end && read < len; j++) buf[read++] = data_poi[j]; - this->pagebuf = realpage; - } else + this->pagebuf = realpage; + } else read += mtd->oobblock; - /* Apply delay or wait for ready/busy pin + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else nand_wait_ready(mtd); - + if (read == len) - break; + break; /* For subsequent reads align to page boundary. */ col = 0; @@ -1337,11 +1343,11 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) - sndcmd = 1; + sndcmd = 1; } /* Deselect and wake up anyone waiting on the device */ @@ -1378,7 +1384,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Shift to get page */ page = (int)(from >> this->page_shift); chipnr = (int)(from >> this->chip_shift); - + /* Mask to get column */ col = from & (mtd->oobsize - 1); @@ -1400,7 +1406,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Send the read command */ this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); - /* + /* * Read the data, if we read more than one page * oob data, let the device transfer the data ! */ @@ -1422,20 +1428,20 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); } - - /* Apply delay or wait for ready/busy pin + + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else nand_wait_ready(mtd); - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { /* For subsequent page reads set offset to 0 */ this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); @@ -1481,27 +1487,27 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, nand_get_device (this, mtd , FL_READING); this->select_chip (mtd, chip); - + /* Add requested oob length */ len += ooblen; - + while (len) { if (sndcmd) this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); - sndcmd = 0; + sndcmd = 0; this->read_buf (mtd, &buf[cnt], pagesize); len -= pagesize; cnt += pagesize; page++; - - if (!this->dev_ready) + + if (!this->dev_ready) udelay (this->chip_delay); else nand_wait_ready(mtd); - - /* Check, if the chip supports auto page increment */ + + /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) sndcmd = 1; } @@ -1512,8 +1518,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, } -/** - * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer +/** + * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer * @mtd: MTD device structure * @fsbuf: buffer given by fs driver * @oobsel: out of band selection structre @@ -1542,20 +1548,20 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct int i, len, ofs; /* Zero copy fs supplied buffer */ - if (fsbuf && !autoplace) + if (fsbuf && !autoplace) return fsbuf; /* Check, if the buffer must be filled with ff again */ - if (this->oobdirty) { - memset (this->oob_buf, 0xff, + if (this->oobdirty) { + memset (this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); this->oobdirty = 0; - } - + } + /* If we have no autoplacement or no fs buffer use the internal one */ if (!autoplace || !fsbuf) return this->oob_buf; - + /* Walk through the pages and place the data */ this->oobdirty = 1; ofs = 0; @@ -1589,7 +1595,7 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret { return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); } - + /** * nand_write_ecc - [MTD Interface] NAND write with ECC * @mtd: MTD device structure @@ -1622,7 +1628,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; } - /* reject writes, which are not page aligned */ + /* reject writes, which are not page aligned */ if (NOTALIGNED (to) || NOTALIGNED(len)) { printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; @@ -1641,14 +1647,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, goto out; /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { oobsel = this->autooob; autoplace = 1; - } + } if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) autoplace = 1; @@ -1656,9 +1662,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, totalpages = len >> this->page_shift; page = (int) (to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) + if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) this->pagebuf = -1; - + /* Set it relative to chip */ page &= this->pagemask; startpage = page; @@ -1680,14 +1686,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); goto out; - } + } /* Next oob page */ oob += mtd->oobsize; /* Update written bytes count */ written += mtd->oobblock; - if (written == len) + if (written == len) goto cmp; - + /* Increment page address */ page++; @@ -1698,13 +1704,13 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (!(page & (ppblock - 1))){ int ofs; this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, + ret = nand_verify_pages (mtd, this, startpage, page - startpage, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); goto out; - } + } *retlen = written; ofs = autoplace ? mtd->oobavail : mtd->oobsize; @@ -1714,8 +1720,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, numpages = min (totalpages, ppblock); page &= this->pagemask; startpage = page; - oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, + oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages); + oob = 0; |