diff --git a/[refs] b/[refs] index 749c9e47056c..2aaaf5bb33b3 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 6dfc6d250d0b7ebaa6423c44dcd09fcfe68deabd +refs/heads/master: fcb7578719529898aef9edce8e409e457a1c2d15 diff --git a/trunk/drivers/mtd/nand/Kconfig b/trunk/drivers/mtd/nand/Kconfig index c2cb87fc4cb8..2d0ebad55a49 100644 --- a/trunk/drivers/mtd/nand/Kconfig +++ b/trunk/drivers/mtd/nand/Kconfig @@ -23,14 +23,6 @@ config MTD_NAND_VERIFY_WRITE device thinks the write was successful, a bit could have been flipped accidentaly due to device wear or something else. -config MTD_NAND_ECC_SMC - bool "NAND ECC Smart Media byte order" - depends on MTD_NAND - default n - help - Software ECC according to the Smart Media Specification. - The original Linux implementation had byte 0 and 1 swapped. - config MTD_NAND_AUTCPU12 tristate "SmartMediaCard on autronix autcpu12 board" depends on MTD_NAND && ARCH_AUTCPU12 @@ -129,12 +121,6 @@ config MTD_NAND_S3C2410_HWECC currently not be able to switch to software, as there is no implementation for ECC method used by the S3C2410 -config MTD_NAND_NDFC - tristate "NDFC NanD Flash Controller" - depends on MTD_NAND && 44x - help - NDFC Nand Flash Controllers are integrated in EP44x SoCs - config MTD_NAND_DISKONCHIP tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" depends on MTD_NAND && EXPERIMENTAL diff --git a/trunk/drivers/mtd/nand/Makefile b/trunk/drivers/mtd/nand/Makefile index f74759351c91..33475087dbff 100644 --- a/trunk/drivers/mtd/nand/Makefile +++ b/trunk/drivers/mtd/nand/Makefile @@ -21,6 +21,5 @@ obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o -obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o nand-objs = nand_base.o nand_bbt.o diff --git a/trunk/drivers/mtd/nand/ams-delta.c b/trunk/drivers/mtd/nand/ams-delta.c index aeaf2dece095..5a349eb316f5 100644 --- a/trunk/drivers/mtd/nand/ams-delta.c +++ b/trunk/drivers/mtd/nand/ams-delta.c @@ -192,7 +192,7 @@ static int __init ams_delta_init(void) } /* 25 us command delay time */ this->chip_delay = 30; - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; /* Set chip enabled, but */ ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE | diff --git a/trunk/drivers/mtd/nand/au1550nd.c b/trunk/drivers/mtd/nand/au1550nd.c index d7f04abfe18e..d9a0143e1d3a 100644 --- a/trunk/drivers/mtd/nand/au1550nd.c +++ b/trunk/drivers/mtd/nand/au1550nd.c @@ -578,7 +578,7 @@ static int __init au1xxx_nand_init(void) /* 30 us command delay time */ this->chip_delay = 30; - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; this->options = NAND_NO_AUTOINCR; diff --git a/trunk/drivers/mtd/nand/autcpu12.c b/trunk/drivers/mtd/nand/autcpu12.c index dbb1b6267ade..43b296040d7f 100644 --- a/trunk/drivers/mtd/nand/autcpu12.c +++ b/trunk/drivers/mtd/nand/autcpu12.c @@ -163,7 +163,7 @@ static int __init autcpu12_init(void) this->dev_ready = autcpu12_device_ready; /* 20 us command delay time */ this->chip_delay = 20; - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ /* diff --git a/trunk/drivers/mtd/nand/cs553x_nand.c b/trunk/drivers/mtd/nand/cs553x_nand.c index 064f3feadf53..bf251253ea1f 100644 --- a/trunk/drivers/mtd/nand/cs553x_nand.c +++ b/trunk/drivers/mtd/nand/cs553x_nand.c @@ -242,13 +242,11 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this->chip_delay = 0; - this->ecc.mode = NAND_ECC_HW; - this->ecc.size = 256; - this->ecc.bytes = 3; - this->ecc.hwctl = cs_enable_hwecc; - this->ecc.calculate = cs_calculate_ecc; - this->ecc.correct = nand_correct_data; - + this->eccmode = NAND_ECC_HW3_256; + this->enable_hwecc = cs_enable_hwecc; + this->calculate_ecc = cs_calculate_ecc; + this->correct_data = nand_correct_data; + /* Enable the following for a flash based bad block table */ this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; diff --git a/trunk/drivers/mtd/nand/diskonchip.c b/trunk/drivers/mtd/nand/diskonchip.c index 128c937af32f..a2391c66a63f 100644 --- a/trunk/drivers/mtd/nand/diskonchip.c +++ b/trunk/drivers/mtd/nand/diskonchip.c @@ -1674,14 +1674,12 @@ static int __init doc_probe(unsigned long physadr) nand->dev_ready = doc200x_dev_ready; nand->waitfunc = doc200x_wait; nand->block_bad = doc200x_block_bad; - nand->ecc.hwctl = doc200x_enable_hwecc; - nand->ecc.calculate = doc200x_calculate_ecc; - nand->ecc.correct = doc200x_correct_data; + nand->enable_hwecc = doc200x_enable_hwecc; + nand->calculate_ecc = doc200x_calculate_ecc; + nand->correct_data = doc200x_correct_data; nand->autooob = &doc200x_oobinfo; - nand->ecc.mode = NAND_ECC_HW_SYNDROME; - nand->ecc.size = 512; - nand->ecc.bytes = 6; + nand->eccmode = NAND_ECC_HW6_512; nand->options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME; doc->physadr = physadr; diff --git a/trunk/drivers/mtd/nand/h1910.c b/trunk/drivers/mtd/nand/h1910.c index 06e91fa11b34..9848eb09b884 100644 --- a/trunk/drivers/mtd/nand/h1910.c +++ b/trunk/drivers/mtd/nand/h1910.c @@ -149,7 +149,7 @@ static int __init h1910_init(void) this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */ /* 15 us command delay time */ this->chip_delay = 50; - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; this->options = NAND_NO_AUTOINCR; /* Scan to find existence of the device */ diff --git a/trunk/drivers/mtd/nand/nand_base.c b/trunk/drivers/mtd/nand/nand_base.c index 98792ec4c2dc..08dffb7a9389 100644 --- a/trunk/drivers/mtd/nand/nand_base.c +++ b/trunk/drivers/mtd/nand/nand_base.c @@ -10,7 +10,7 @@ * http://www.linux-mtd.infradead.org/tech/nand.html * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * 2002 Thomas Gleixner (tglx@linutronix.de) + * 2002 Thomas Gleixner (tglx@linutronix.de) * * 02-08-2004 tglx: support for strange chips, which cannot auto increment * pages on read / read_oob @@ -25,30 +25,26 @@ * 05-19-2004 tglx: Basic support for Renesas AG-AND chips * * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared - * among multiple independend devices. Suggestions and initial - * patch from Ben Dooks - * - * 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 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 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 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 perform extra error status checks on erase and write - * failures. This required adding a wrapper function for - * nand_read_ecc. + * among multiple independend devices. Suggestions and initial patch + * from Ben Dooks + * + * 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 + * 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 + * 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 + * 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 + * 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 * @@ -76,7 +72,6 @@ #include #include #include -#include #include #include #include @@ -119,7 +114,7 @@ static struct nand_oobinfo nand_oob_64 = { }; /* This is used for padding purposes in nand_write_oob */ -static uint8_t ffchars[] = { +static u_char ffchars[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -133,47 +128,36 @@ static uint8_t ffchars[] = { /* * NAND low-level MTD interface functions */ -static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len); -static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len); -static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len); +static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); +static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); +static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); -static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf); +static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf, uint8_t *eccbuf, - struct nand_oobinfo *oobsel); -static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf); -static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf); + size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); +static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); +static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf, uint8_t *eccbuf, - struct nand_oobinfo *oobsel); -static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf); -static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen); + size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); +static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); +static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen, - uint8_t *eccbuf, struct nand_oobinfo *oobsel); + unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf, + struct nand_oobinfo *oobsel); static int nand_erase(struct mtd_info *mtd, struct erase_info *instr); static void nand_sync(struct mtd_info *mtd); /* Some internal functions */ -static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, - int page, uint8_t * oob_buf, +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, uint8_t *oob_buf, - struct nand_oobinfo *oobsel, int chipnr, - int oobmode); +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 int 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 @@ -188,12 +172,20 @@ static void nand_release_device(struct mtd_info *mtd) /* De-select the NAND device */ this->select_chip(mtd, -1); - /* Release the controller and the chip */ - spin_lock(&this->controller->lock); - this->controller->active = NULL; - this->state = FL_READY; - wake_up(&this->controller->wq); - spin_unlock(&this->controller->lock); + if (this->controller) { + /* Release the controller and the chip */ + spin_lock(&this->controller->lock); + this->controller->active = NULL; + this->state = FL_READY; + wake_up(&this->controller->wq); + spin_unlock(&this->controller->lock); + } else { + /* Release the chip */ + spin_lock(&this->chip_lock); + this->state = FL_READY; + wake_up(&this->wq); + spin_unlock(&this->chip_lock); + } } /** @@ -202,7 +194,7 @@ static void nand_release_device(struct mtd_info *mtd) * * Default read function for 8bit buswith */ -static uint8_t nand_read_byte(struct mtd_info *mtd) +static u_char nand_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; return readb(this->IO_ADDR_R); @@ -215,7 +207,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) * * Default write function for 8it buswith */ -static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) +static void nand_write_byte(struct mtd_info *mtd, u_char byte) { struct nand_chip *this = mtd->priv; writeb(byte, this->IO_ADDR_W); @@ -228,10 +220,10 @@ static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) * Default read function for 16bit buswith with * endianess conversion */ -static uint8_t nand_read_byte16(struct mtd_info *mtd) +static u_char nand_read_byte16(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - return (uint8_t) cpu_to_le16(readw(this->IO_ADDR_R)); + return (u_char) cpu_to_le16(readw(this->IO_ADDR_R)); } /** @@ -242,7 +234,7 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) * Default write function for 16bit buswith with * endianess conversion */ -static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) +static void nand_write_byte16(struct mtd_info *mtd, u_char byte) { struct nand_chip *this = mtd->priv; writew(le16_to_cpu((u16) byte), this->IO_ADDR_W); @@ -306,7 +298,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) * * Default write function for 8bit buswith */ -static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; @@ -323,7 +315,7 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) * * Default read function for 8bit buswith */ -static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; @@ -340,7 +332,7 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) * * Default verify function for 8bit buswith */ -static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; @@ -360,7 +352,7 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) * * Default write function for 16bit buswith */ -static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) +static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; @@ -380,7 +372,7 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) * * Default read function for 16bit buswith */ -static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) +static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; @@ -399,7 +391,7 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) * * Default verify function for 16bit buswith */ -static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) +static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) { int i; struct nand_chip *this = mtd->priv; @@ -440,16 +432,14 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) page = (int)ofs; if (this->options & NAND_BUSWIDTH_16) { - this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, - page & this->pagemask); + 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 >>= 8; if ((bad & 0xFF) != 0xff) res = 1; } else { - this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos, - page & this->pagemask); + this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask); if (this->read_byte(mtd) != 0xff) res = 1; } @@ -473,7 +463,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *this = mtd->priv; - uint8_t buf[2] = { 0, 0 }; + u_char buf[2] = { 0, 0 }; size_t retlen; int block; @@ -516,8 +506,7 @@ static int nand_check_wp(struct mtd_info *mtd) * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */ -static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, - int allowbbt) +static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) { struct nand_chip *this = mtd->priv; @@ -559,8 +548,7 @@ static void nand_wait_ready(struct mtd_info *mtd) * Send command to NAND device. This function is used for small page * devices (256/512 Bytes per page) */ -static void nand_command(struct mtd_info *mtd, unsigned command, int column, - int page_addr) +static void nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) { register struct nand_chip *this = mtd->priv; @@ -601,11 +589,11 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, this->write_byte(mtd, column); } if (page_addr != -1) { - this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); - this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); + this->write_byte(mtd, (unsigned char)(page_addr & 0xff)); + this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff)); /* One more address cycle for devices > 32MiB */ if (this->chipsize > (32 << 20)) - this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0x0f)); + this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0x0f)); } /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); @@ -693,11 +681,11 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, this->write_byte(mtd, column >> 8); } if (page_addr != -1) { - this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); - this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); + this->write_byte(mtd, (unsigned char)(page_addr & 0xff)); + this->write_byte(mtd, (unsigned char)((page_addr >> 8) & 0xff)); /* One more address cycle for devices > 128MiB */ if (this->chipsize > (128 << 20)) - this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0xff)); + this->write_byte(mtd, (unsigned char)((page_addr >> 16) & 0xff)); } /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); @@ -775,21 +763,27 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, * * Get the device and lock it for exclusive access */ -static int -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) { - spinlock_t *lock = &this->controller->lock; - wait_queue_head_t *wq = &this->controller->wq; + struct nand_chip *active; + spinlock_t *lock; + wait_queue_head_t *wq; DECLARE_WAITQUEUE(wait, current); + + lock = (this->controller) ? &this->controller->lock : &this->chip_lock; + wq = (this->controller) ? &this->controller->wq : &this->wq; retry: + active = this; spin_lock(lock); /* Hardware controller shared among independend devices */ - /* Hardware controller shared among independend devices */ - if (!this->controller->active) - this->controller->active = this; - - if (this->controller->active == this && this->state == FL_READY) { + if (this->controller) { + if (this->controller->active) + active = this->controller->active; + else + this->controller->active = this; + } + if (active == this && this->state == FL_READY) { this->state = new_state; spin_unlock(lock); return 0; @@ -875,13 +869,13 @@ 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, - uint8_t *oob_buf, struct nand_oobinfo *oobsel, int cached) + u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { int i, status; - uint8_t ecc_code[32]; - int eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE; + u_char ecc_code[32]; + int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; int *oob_config = oobsel->eccpos; - int datidx = 0, eccidx = 0, eccsteps = this->ecc.steps; + int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; int eccbytes = 0; /* FIXME: Enable cached programming */ @@ -901,20 +895,20 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag /* Software ecc 3/256, write all */ case NAND_ECC_SOFT: for (; eccsteps; eccsteps--) { - this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code); + this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); for (i = 0; i < 3; i++, eccidx++) oob_buf[oob_config[eccidx]] = ecc_code[i]; - datidx += this->ecc.size; + datidx += this->eccsize; } this->write_buf(mtd, this->data_poi, mtd->oobblock); break; default: - eccbytes = this->ecc.bytes; + eccbytes = this->eccbytes; for (; eccsteps; eccsteps--) { /* enable hardware ecc logic for write */ - this->ecc.hwctl(mtd, NAND_ECC_WRITE); - this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size); - this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code); + this->enable_hwecc(mtd, NAND_ECC_WRITE); + this->write_buf(mtd, &this->data_poi[datidx], this->eccsize); + this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code); for (i = 0; i < eccbytes; i++, eccidx++) oob_buf[oob_config[eccidx]] = ecc_code[i]; /* If the hardware ecc provides syndromes then @@ -922,7 +916,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag * the data bytes (words) */ if (this->options & NAND_HWECC_SYNDROME) this->write_buf(mtd, ecc_code, eccbytes); - datidx += this->ecc.size; + datidx += this->eccsize; } break; } @@ -963,7 +957,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag * nand_verify_pages - [GENERIC] verify the chip contents after a write * @mtd: MTD device structure * @this: NAND chip structure - * @page: startpage inside the chip, must be called with (page & this->pagemask) + * @page: startpage inside the chip, must be called with (page & this->pagemask) * @numpages: number of pages to verify * @oob_buf: out of band data buffer * @oobsel: out of band selecttion structre @@ -979,12 +973,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag * 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, - uint8_t *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) + 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; - uint8_t oobdata[64]; + u_char oobdata[64]; hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; @@ -1079,7 +1073,7 @@ static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, int p * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL * and flags = 0xff */ -static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) +static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff); } @@ -1097,7 +1091,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retl * This function simply calls nand_do_read_ecc with flags = 0xff */ static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel) + size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel) { /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) @@ -1122,15 +1116,15 @@ 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, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel, int flags) + size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *oobsel, int flags) { int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; - uint8_t *data_poi, *oob_data = oob_buf; - uint8_t ecc_calc[32]; - uint8_t ecc_code[32]; + u_char *data_poi, *oob_data = oob_buf; + u_char ecc_calc[32]; + u_char ecc_code[32]; int eccmode, eccsteps; int *oob_config, datidx; int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; @@ -1155,7 +1149,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) oobsel = this->autooob; - eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE; + eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; oob_config = oobsel->eccpos; /* Select the NAND device */ @@ -1170,8 +1164,8 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, col = from & (mtd->oobblock - 1); end = mtd->oobblock; - ecc = this->ecc.size; - eccbytes = this->ecc.bytes; + ecc = this->eccsize; + eccbytes = this->eccbytes; if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) compareecc = 0; @@ -1216,7 +1210,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, oobsel->useecc == MTD_NANDECC_AUTOPL_USR) oob_data = &this->data_buf[end]; - eccsteps = this->ecc.steps; + eccsteps = this->eccsteps; switch (eccmode) { case NAND_ECC_NONE:{ @@ -1234,12 +1228,12 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, 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) - this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]); + this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); break; default: for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) { - this->ecc.hwctl(mtd, NAND_ECC_READ); + this->enable_hwecc(mtd, NAND_ECC_READ); this->read_buf(mtd, &data_poi[datidx], ecc); /* HW ecc with syndrome calculation must read the @@ -1247,19 +1241,19 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, if (!compareecc) { /* Some hw ecc generators need to know when the * syndrome is read from flash */ - this->ecc.hwctl(mtd, NAND_ECC_READSYN); + this->enable_hwecc(mtd, NAND_ECC_READSYN); this->read_buf(mtd, &oob_data[i], eccbytes); /* We calc error correction directly, it checks the hw * generator for an error, reads back the syndrome and * does the error correction on the fly */ - ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); + 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: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; } } else { - this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]); + this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); } } break; @@ -1277,8 +1271,8 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, ecc_code[j] = oob_data[oob_config[j]]; /* correct data, if necessary */ - for (i = 0, j = 0, datidx = 0; i < this->ecc.steps; i++, datidx += ecc) { - ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); + 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; @@ -1315,7 +1309,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, break; case MTD_NANDECC_PLACE: /* YAFFS1 legacy mode */ - oob_data += this->ecc.steps * sizeof(int); + oob_data += this->eccsteps * sizeof(int); default: oob_data += mtd->oobsize; } @@ -1384,7 +1378,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, * * NAND read out-of-band data from the spare area */ -static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) +static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { int i, col, page, chipnr; struct nand_chip *this = mtd->priv; @@ -1551,7 +1545,7 @@ int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, s * forces the 0xff fill before using the buffer again. * */ -static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct nand_oobinfo *oobsel, +static u_char *nand_prepare_oobbuf(struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel, int autoplace, int numpages) { struct nand_chip *this = mtd->priv; @@ -1600,7 +1594,7 @@ static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL * */ -static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) +static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL)); } @@ -1618,13 +1612,13 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retle * NAND write with ECC */ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf, uint8_t *eccbuf, + size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) { int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr; int autoplace = 0, numpages, totalpages; struct nand_chip *this = mtd->priv; - uint8_t *oobbuf, *bufstart; + u_char *oobbuf, *bufstart; int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); @@ -1681,12 +1675,12 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Calc number of pages we can write in one go */ numpages = min(ppblock - (startpage & (ppblock - 1)), totalpages); oobbuf = nand_prepare_oobbuf(mtd, eccbuf, oobsel, autoplace, numpages); - bufstart = (uint8_t *) buf; + bufstart = (u_char *) buf; /* Loop until all data is written */ while (written < len) { - this->data_poi = (uint8_t *) &buf[written]; + this->data_poi = (u_char *) &buf[written]; /* Write one page. If this is the last page to write * or the last page in this block, then use the * real pageprogram command, else select cached programming @@ -1765,7 +1759,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, * * NAND write out-of-band */ -static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) +static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { int column, page, status, ret = -EIO, chipnr; struct nand_chip *this = mtd->priv; @@ -1885,13 +1879,13 @@ static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned l * NAND write with iovec with ecc */ static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, - loff_t to, size_t *retlen, uint8_t *eccbuf, struct nand_oobinfo *oobsel) + loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) { int i, page, len, total_len, ret = -EIO, written = 0, chipnr; int oob, numpages, autoplace = 0, startpage; struct nand_chip *this = mtd->priv; int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); - uint8_t *oobbuf, *bufstart; + u_char *oobbuf, *bufstart; /* Preset written len for early exit */ *retlen = 0; @@ -1960,7 +1954,7 @@ static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsign /* Do not cross block boundaries */ numpages = min(ppblock - (startpage & (ppblock - 1)), numpages); oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages); - bufstart = (uint8_t *) vecs->iov_base; + bufstart = (u_char *) vecs->iov_base; bufstart += len; this->data_poi = bufstart; oob = 0; @@ -1991,7 +1985,7 @@ static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsign int cnt = 0; while (cnt < mtd->oobblock) { if (vecs->iov_base != NULL && vecs->iov_len) - this->data_buf[cnt++] = ((uint8_t *) vecs->iov_base)[len++]; + this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; /* Check, if we have to switch to the next tuple */ if (len >= (int)vecs->iov_len) { vecs++; @@ -2314,70 +2308,46 @@ static void nand_resume(struct mtd_info *mtd) if (this->state == FL_PM_SUSPENDED) nand_release_device(mtd); else - printk(KERN_ERR "nand_resume() called for a chip which is not " - "in suspended state\n"); -} + printk(KERN_ERR "resume() called for the chip which is not in suspended state\n"); -/* - * Free allocated data structures - */ -static void nand_free_kmem(struct nand_chip *this) -{ - /* Buffer allocated by nand_scan ? */ - if (this->options & NAND_OOBBUF_ALLOC) - kfree(this->oob_buf); - /* Buffer allocated by nand_scan ? */ - if (this->options & NAND_DATABUF_ALLOC) - kfree(this->data_buf); - /* Controller allocated by nand_scan ? */ - if (this->options & NAND_CONTROLLER_ALLOC) - kfree(this->controller); } -/* - * Allocate buffers and data structures +/* module_text_address() isn't exported, and it's mostly a pointless + test if this is a module _anyway_ -- they'd have to try _really_ hard + to call us from in-kernel code if the core NAND support is modular. */ +#ifdef MODULE +#define caller_is_module() (1) +#else +#define caller_is_module() module_text_address((unsigned long)__builtin_return_address(0)) +#endif + +/** + * nand_scan - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for + * + * This fills out all the uninitialized function pointers + * with the defaults. + * The flash ID is read and the mtd/chip structures are + * filled with the appropriate values. Buffers are allocated if + * they are not provided by the board driver + * The mtd->owner field must be set to the module of the caller + * */ -static int nand_allocate_kmem(struct mtd_info *mtd, struct nand_chip *this) +int nand_scan(struct mtd_info *mtd, int maxchips) { - size_t len; - - if (!this->oob_buf) { - len = mtd->oobsize << - (this->phys_erase_shift - this->page_shift); - this->oob_buf = kmalloc(len, GFP_KERNEL); - if (!this->oob_buf) - goto outerr; - this->options |= NAND_OOBBUF_ALLOC; - } - - if (!this->data_buf) { - len = mtd->oobblock + mtd->oobsize; - this->data_buf = kmalloc(len, GFP_KERNEL); - if (!this->data_buf) - goto outerr; - this->options |= NAND_DATABUF_ALLOC; - } + int i, nand_maf_id, nand_dev_id, busw, maf_id; + struct nand_chip *this = mtd->priv; - if (!this->controller) { - this->controller = kzalloc(sizeof(struct nand_hw_control), - GFP_KERNEL); - if (!this->controller) - goto outerr; - this->options |= NAND_CONTROLLER_ALLOC; + /* Many callers got this wrong, so check for it for a while... */ + if (!mtd->owner && caller_is_module()) { + printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); + BUG(); } - return 0; - outerr: - printk(KERN_ERR "nand_scan(): Cannot allocate buffers\n"); - nand_free_kmem(this); - return -ENOMEM; -} + /* Get buswidth to select the correct functions */ + busw = this->options & NAND_BUSWIDTH_16; -/* - * Set default functions - */ -static void nand_set_defaults(struct nand_chip *this, int busw) -{ /* check for proper chip_delay setup, set 20us if not */ if (!this->chip_delay) this->chip_delay = 20; @@ -2412,17 +2382,6 @@ static void nand_set_defaults(struct nand_chip *this, int busw) this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf; if (!this->scan_bbt) this->scan_bbt = nand_default_bbt; -} - -/* - * Get the flash and manufacturer id and lookup if the typ is supported - */ -static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, - struct nand_chip *this, - int busw, int *maf_id) -{ - struct nand_flash_dev *type = NULL; - int i, dev_id, maf_idx; /* Select the device */ this->select_chip(mtd, 0); @@ -2431,194 +2390,159 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ - *maf_id = this->read_byte(mtd); - dev_id = this->read_byte(mtd); + nand_maf_id = this->read_byte(mtd); + nand_dev_id = this->read_byte(mtd); - /* Lookup the flash id */ + /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (dev_id == nand_flash_ids[i].id) { - type = &nand_flash_ids[i]; - break; - } - } - if (!type) - return ERR_PTR(-ENODEV); - - this->chipsize = nand_flash_ids[i].chipsize << 20; - - /* Newer devices have all the information in additional id bytes */ - if (!nand_flash_ids[i].pagesize) { - int extid; - /* The 3rd id byte contains non relevant data ATM */ - extid = this->read_byte(mtd); - /* The 4th id byte is the important one */ - extid = this->read_byte(mtd); - /* Calc pagesize */ - mtd->oobblock = 1024 << (extid & 0x3); - extid >>= 2; - /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9); - extid >>= 2; - /* Calc blocksize. Blocksize is multiples of 64KiB */ - mtd->erasesize = (64 * 1024) << (extid & 0x03); - extid >>= 2; - /* Get buswidth information */ - busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - - } else { - /* - * Old devices have this data hardcoded in the device id table - */ - mtd->erasesize = nand_flash_ids[i].erasesize; - mtd->oobblock = nand_flash_ids[i].pagesize; - mtd->oobsize = mtd->oobblock / 32; - busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; - } - - /* Try to identify manufacturer */ - for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) { - if (nand_manuf_ids[maf_idx].id == *maf_id) - break; - } - - /* - * Check, if buswidth is correct. Hardware drivers should set - * this correct ! - */ - if (busw != (this->options & NAND_BUSWIDTH_16)) { - printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - dev_id, nand_manuf_ids[maf_idx].name, mtd->name); - printk(KERN_WARNING "NAND bus width %d instead %d bit\n", - (this->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); - return ERR_PTR(-EINVAL); - } - - /* Calculate the address shift from the page size */ - this->page_shift = ffs(mtd->oobblock) - 1; - /* Convert chipsize to number of pages per chip -1. */ - this->pagemask = (this->chipsize >> this->page_shift) - 1; - - this->bbt_erase_shift = this->phys_erase_shift = - ffs(mtd->erasesize) - 1; - this->chip_shift = ffs(this->chipsize) - 1; - - /* Set the bad block position */ - this->badblockpos = mtd->oobblock > 512 ? - NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; - - /* Get chip options, preserve non chip based options */ - this->options &= ~NAND_CHIPOPTIONS_MSK; - this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK; - - /* - * Set this as a default. Board drivers can override it, if necessary - */ - this->options |= NAND_NO_AUTOINCR; - - /* Check if this is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. - */ - if (*maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) - this->options &= ~NAND_SAMSUNG_LP_OPTIONS; + if (nand_dev_id != nand_flash_ids[i].id) + continue; + + if (!mtd->name) + mtd->name = nand_flash_ids[i].name; + this->chipsize = nand_flash_ids[i].chipsize << 20; + + /* New devices have all the information in additional id bytes */ + if (!nand_flash_ids[i].pagesize) { + int extid; + /* The 3rd id byte contains non relevant data ATM */ + extid = this->read_byte(mtd); + /* The 4th id byte is the important one */ + extid = this->read_byte(mtd); + /* Calc pagesize */ + mtd->oobblock = 1024 << (extid & 0x3); + extid >>= 2; + /* Calc oobsize */ + mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9); + extid >>= 2; + /* Calc blocksize. Blocksize is multiples of 64KiB */ + mtd->erasesize = (64 * 1024) << (extid & 0x03); + extid >>= 2; + /* Get buswidth information */ + busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - /* Check for AND chips with 4 page planes */ - if (this->options & NAND_4PAGE_ARRAY) - this->erase_cmd = multi_erase_cmd; - else - this->erase_cmd = single_erase_cmd; + } else { + /* Old devices have this data hardcoded in the + * device id table */ + mtd->erasesize = nand_flash_ids[i].erasesize; + mtd->oobblock = nand_flash_ids[i].pagesize; + mtd->oobsize = mtd->oobblock / 32; + busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; + } - /* Do not replace user supplied command function ! */ - if (mtd->oobblock > 512 && this->cmdfunc == nand_command) - this->cmdfunc = nand_command_lp; + /* Try to identify manufacturer */ + for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) { + if (nand_manuf_ids[maf_id].id == nand_maf_id) + break; + } - printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, - nand_manuf_ids[maf_idx].name, type->name); + /* Check, if buswidth is correct. Hardware drivers should set + * this correct ! */ + if (busw != (this->options & NAND_BUSWIDTH_16)) { + printk(KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + nand_manuf_ids[maf_id].name, mtd->name); + printk(KERN_WARNING + "NAND bus width %d instead %d bit\n", + (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); + this->select_chip(mtd, -1); + return 1; + } - return type; -} + /* Calculate the address shift from the page size */ + this->page_shift = ffs(mtd->oobblock) - 1; + this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; + this->chip_shift = ffs(this->chipsize) - 1; + + /* Set the bad block position */ + this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; + + /* Get chip options, preserve non chip based options */ + this->options &= ~NAND_CHIPOPTIONS_MSK; + this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK; + /* Set this as a default. Board drivers can override it, if necessary */ + this->options |= NAND_NO_AUTOINCR; + /* Check if this is a not a samsung device. Do not clear the options + * for chips which are not having an extended id. + */ + if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) + this->options &= ~NAND_SAMSUNG_LP_OPTIONS; -/* module_text_address() isn't exported, and it's mostly a pointless - test if this is a module _anyway_ -- they'd have to try _really_ hard - to call us from in-kernel code if the core NAND support is modular. */ -#ifdef MODULE -#define caller_is_module() (1) -#else -#define caller_is_module() \ - module_text_address((unsigned long)__builtin_return_address(0)) -#endif + /* Check for AND chips with 4 page planes */ + if (this->options & NAND_4PAGE_ARRAY) + this->erase_cmd = multi_erase_cmd; + else + this->erase_cmd = single_erase_cmd; -/** - * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. Buffers are allocated if - * they are not provided by the board driver - * The mtd->owner field must be set to the module of the caller - * - */ -int nand_scan(struct mtd_info *mtd, int maxchips) -{ - int i, busw, nand_maf_id; - struct nand_chip *this = mtd->priv; - struct nand_flash_dev *type; + /* Do not replace user supplied command function ! */ + if (mtd->oobblock > 512 && this->cmdfunc == nand_command) + this->cmdfunc = nand_command_lp; - /* Many callers got this wrong, so check for it for a while... */ - if (!mtd->owner && caller_is_module()) { - printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n"); - BUG(); + printk(KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + nand_manuf_ids[maf_id].name, nand_flash_ids[i].name); + break; } - /* Get buswidth to select the correct functions */ - busw = this->options & NAND_BUSWIDTH_16; - /* Set the default functions */ - nand_set_defaults(this, busw); - - /* Read the flash type */ - type = nand_get_flash_type(mtd, this, busw, &nand_maf_id); - - if (IS_ERR(type)) { + if (!nand_flash_ids[i].name) { printk(KERN_WARNING "No NAND device found!!!\n"); this->select_chip(mtd, -1); - return PTR_ERR(type); + return 1; } - /* Check for a chip array */ for (i = 1; i < maxchips; i++) { this->select_chip(mtd, i); + /* Send the command for reading device ID */ this->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + /* Read manufacturer and device IDs */ if (nand_maf_id != this->read_byte(mtd) || - type->id != this->read_byte(mtd)) + nand_dev_id != this->read_byte(mtd)) break; } if (i > 1) printk(KERN_INFO "%d NAND chips detected\n", i); + /* Allocate buffers, if necessary */ + if (!this->oob_buf) { + size_t len; + len = mtd->oobsize << (this->phys_erase_shift - this->page_shift); + this->oob_buf = kmalloc(len, GFP_KERNEL); + if (!this->oob_buf) { + printk(KERN_ERR "nand_scan(): Cannot allocate oob_buf\n"); + return -ENOMEM; + } + this->options |= NAND_OOBBUF_ALLOC; + } + + if (!this->data_buf) { + size_t len; + len = mtd->oobblock + mtd->oobsize; + this->data_buf = kmalloc(len, GFP_KERNEL); + if (!this->data_buf) { + if (this->options & NAND_OOBBUF_ALLOC) + kfree(this->oob_buf); + printk(KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); + return -ENOMEM; + } + this->options |= NAND_DATABUF_ALLOC; + } + /* Store the number of chips and calc total size for mtd */ this->numchips = i; mtd->size = i * this->chipsize; - - /* Allocate buffers and data structures */ - if (nand_allocate_kmem(mtd, this)) - return -ENOMEM; - + /* Convert chipsize to number of pages per chip -1. */ + this->pagemask = (this->chipsize >> this->page_shift) - 1; /* Preset the internal oob buffer */ - memset(this->oob_buf, 0xff, - mtd->oobsize << (this->phys_erase_shift - this->page_shift)); + memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); - /* - * If no default placement scheme is given, select an appropriate one - */ + /* If no default placement scheme is given, select an + * appropriate one */ if (!this->autooob) { + /* Select the appropriate default oob placement scheme for + * placement agnostic filesystems */ switch (mtd->oobsize) { case 8: this->autooob = &nand_oob_8; @@ -2630,73 +2554,111 @@ int nand_scan(struct mtd_info *mtd, int maxchips) this->autooob = &nand_oob_64; break; default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + printk(KERN_WARNING "No oob scheme defined for oobsize %d\n", mtd->oobsize); BUG(); } } - /* - * The number of bytes available for the filesystem to place fs - * dependend oob data - */ + /* The number of bytes available for the filesystem to place fs dependend + * oob data */ mtd->oobavail = 0; for (i = 0; this->autooob->oobfree[i][1]; i++) mtd->oobavail += this->autooob->oobfree[i][1]; /* - * check ECC mode, default to software if 3byte/512byte hardware ECC is - * selected and we have 256 byte pagesize fallback to software ECC + * check ECC mode, default to software + * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize + * fallback to software ECC */ - switch (this->ecc.mode) { - case NAND_ECC_HW: - case NAND_ECC_HW_SYNDROME: - if (!this->ecc.calculate || !this->ecc.correct || - !this->ecc.hwctl) { - printk(KERN_WARNING "No ECC functions supplied, " - "Hardware ECC not possible\n"); - BUG(); - } - if (mtd->oobblock >= this->ecc.size) - break; - printk(KERN_WARNING "%d byte HW ECC not possible on " - "%d byte page size, fallback to SW ECC\n", - this->ecc.size, mtd->oobblock); - this->ecc.mode = NAND_ECC_SOFT; + this->eccsize = 256; /* set default eccsize */ + this->eccbytes = 3; + + switch (this->eccmode) { + case NAND_ECC_HW12_2048: + if (mtd->oobblock < 2048) { + printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", + mtd->oobblock); + this->eccmode = NAND_ECC_SOFT; + this->calculate_ecc = nand_calculate_ecc; + this->correct_data = nand_correct_data; + } else + this->eccsize = 2048; + break; - case NAND_ECC_SOFT: - this->ecc.calculate = nand_calculate_ecc; - this->ecc.correct = nand_correct_data; - this->ecc.size = 256; - this->ecc.bytes = 3; + case NAND_ECC_HW3_512: + case NAND_ECC_HW6_512: + case NAND_ECC_HW8_512: + if (mtd->oobblock == 256) { + printk(KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); + this->eccmode = NAND_ECC_SOFT; + this->calculate_ecc = nand_calculate_ecc; + this->correct_data = nand_correct_data; + } else + this->eccsize = 512; /* set eccsize to 512 */ + break; + + case NAND_ECC_HW3_256: break; case NAND_ECC_NONE: - printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " - "This is not recommended !!\n"); - this->ecc.size = mtd->oobblock; - this->ecc.bytes = 0; + printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); + this->eccmode = NAND_ECC_NONE; + break; + + case NAND_ECC_SOFT: + this->calculate_ecc = nand_calculate_ecc; + this->correct_data = nand_correct_data; break; + default: - printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", - this->ecc.mode); + printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); BUG(); } - /* - * Set the number of read / write steps for one page depending on ECC - * mode + /* Check hardware ecc function availability and adjust number of ecc bytes per + * calculation step */ - this->ecc.steps = mtd->oobblock / this->ecc.size; - if(this->ecc.steps * this->ecc.size != mtd->oobblock) { - printk(KERN_WARNING "Invalid ecc parameters\n"); + switch (this->eccmode) { + case NAND_ECC_HW12_2048: + this->eccbytes += 4; + case NAND_ECC_HW8_512: + this->eccbytes += 2; + case NAND_ECC_HW6_512: + this->eccbytes += 3; + case NAND_ECC_HW3_512: + case NAND_ECC_HW3_256: + if (this->calculate_ecc && this->correct_data && this->enable_hwecc) + break; + printk(KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); BUG(); } + mtd->eccsize = this->eccsize; + + /* Set the number of read / write steps for one page to ensure ECC generation */ + switch (this->eccmode) { + case NAND_ECC_HW12_2048: + this->eccsteps = mtd->oobblock / 2048; + break; + case NAND_ECC_HW3_512: + case NAND_ECC_HW6_512: + case NAND_ECC_HW8_512: + this->eccsteps = mtd->oobblock / 512; + break; + case NAND_ECC_HW3_256: + case NAND_ECC_SOFT: + this->eccsteps = mtd->oobblock / 256; + break; + + case NAND_ECC_NONE: + this->eccsteps = 1; + break; + } + /* Initialize state, waitqueue and spinlock */ this->state = FL_READY; - init_waitqueue_head(&this->controller->wq); - spin_lock_init(&this->controller->lock); + init_waitqueue_head(&this->wq); + spin_lock_init(&this->chip_lock); /* De-select the device */ this->select_chip(mtd, -1); @@ -2756,8 +2718,12 @@ void nand_release(struct mtd_info *mtd) /* Free bad block table memory */ kfree(this->bbt); - /* Free buffers */ - nand_free_kmem(this); + /* Buffer allocated by nand_scan ? */ + if (this->options & NAND_OOBBUF_ALLOC) + kfree(this->oob_buf); + /* Buffer allocated by nand_scan ? */ + if (this->options & NAND_DATABUF_ALLOC) + kfree(this->data_buf); } EXPORT_SYMBOL_GPL(nand_scan); diff --git a/trunk/drivers/mtd/nand/nand_ecc.c b/trunk/drivers/mtd/nand/nand_ecc.c index 2a163e4084df..101892985b02 100644 --- a/trunk/drivers/mtd/nand/nand_ecc.c +++ b/trunk/drivers/mtd/nand/nand_ecc.c @@ -7,8 +7,6 @@ * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) * Toshiba America Electronics Components, Inc. * - * Copyright (C) 2006 Thomas Gleixner - * * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ * * This file is free software; you can redistribute it and/or modify it @@ -65,75 +63,87 @@ static const u_char nand_ecc_precalc_table[] = { }; /** - * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code - * for 256 byte block + * nand_trans_result - [GENERIC] create non-inverted ECC + * @reg2: line parity reg 2 + * @reg3: line parity reg 3 + * @ecc_code: ecc + * + * Creates non-inverted ECC code from line parity + */ +static void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code) +{ + u_char a, b, i, tmp1, tmp2; + + /* Initialize variables */ + a = b = 0x80; + tmp1 = tmp2 = 0; + + /* Calculate first ECC byte */ + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + a >>= 1; + } + + /* Calculate second ECC byte */ + b = 0x80; + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + a >>= 1; + } + + /* Store two of the ECC bytes */ + ecc_code[0] = tmp1; + ecc_code[1] = tmp2; +} + +/** + * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block * @mtd: MTD block structure * @dat: raw data * @ecc_code: buffer for ECC */ -int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { - uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; - int i; + u_char idx, reg1, reg2, reg3; + int j; /* Initialize variables */ reg1 = reg2 = reg3 = 0; + ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; /* Build up column parity */ - for(i = 0; i < 256; i++) { + for (j = 0; j < 256; j++) { + /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[*dat++]; + idx = nand_ecc_precalc_table[dat[j]]; reg1 ^= (idx & 0x3f); /* All bit XOR = 1 ? */ if (idx & 0x40) { - reg3 ^= (uint8_t) i; - reg2 ^= ~((uint8_t) i); + reg3 ^= (u_char) j; + reg2 ^= ~((u_char) j); } } /* Create non-inverted ECC code from line parity */ - tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ - tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ - tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ - tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ - tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ - tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ - tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ - tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ - - tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ - tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ - tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ - tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ - tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ - tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ - tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ - tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ + nand_trans_result(reg2, reg3, ecc_code); /* Calculate final ECC code */ -#ifdef CONFIG_NAND_ECC_SMC - ecc_code[0] = ~tmp2; - ecc_code[1] = ~tmp1; -#else - ecc_code[0] = ~tmp1; - ecc_code[1] = ~tmp2; -#endif + ecc_code[0] = ~ecc_code[0]; + ecc_code[1] = ~ecc_code[1]; ecc_code[2] = ((~reg1) << 2) | 0x03; - return 0; } -EXPORT_SYMBOL(nand_calculate_ecc); - -static inline int countbits(uint32_t byte) -{ - int res = 0; - - for (;byte; byte >>= 1) - res += byte & 0x01; - return res; -} /** * nand_correct_data - [NAND Interface] Detect and correct bit error(s) @@ -144,54 +154,90 @@ static inline int countbits(uint32_t byte) * * Detect and correct a 1 bit error for 256 byte block */ -int nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) +int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { - uint8_t s0, s1, s2; - -#ifdef CONFIG_NAND_ECC_SMC - s0 = calc_ecc[0] ^ read_ecc[0]; - s1 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#else - s1 = calc_ecc[0] ^ read_ecc[0]; - s0 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#endif - if ((s0 | s1 | s2) == 0) - return 0; - - /* Check for a single bit error */ - if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && - ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && - ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { - - uint32_t byteoffs, bitnum; - - byteoffs = (s1 << 0) & 0x80; - byteoffs |= (s1 << 1) & 0x40; - byteoffs |= (s1 << 2) & 0x20; - byteoffs |= (s1 << 3) & 0x10; + u_char a, b, c, d1, d2, d3, add, bit, i; - byteoffs |= (s0 >> 4) & 0x08; - byteoffs |= (s0 >> 3) & 0x04; - byteoffs |= (s0 >> 2) & 0x02; - byteoffs |= (s0 >> 1) & 0x01; + /* Do error detection */ + d1 = calc_ecc[0] ^ read_ecc[0]; + d2 = calc_ecc[1] ^ read_ecc[1]; + d3 = calc_ecc[2] ^ read_ecc[2]; - bitnum = (s2 >> 5) & 0x04; - bitnum |= (s2 >> 4) & 0x02; - bitnum |= (s2 >> 3) & 0x01; - - dat[byteoffs] ^= (1 << bitnum); - - return 1; + if ((d1 | d2 | d3) == 0) { + /* No errors */ + return 0; + } else { + a = (d1 ^ (d1 >> 1)) & 0x55; + b = (d2 ^ (d2 >> 1)) & 0x55; + c = (d3 ^ (d3 >> 1)) & 0x54; + + /* Found and will correct single bit error in the data */ + if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { + c = 0x80; + add = 0; + a = 0x80; + for (i = 0; i < 4; i++) { + if (d1 & c) + add |= a; + c >>= 2; + a >>= 1; + } + c = 0x80; + for (i = 0; i < 4; i++) { + if (d2 & c) + add |= a; + c >>= 2; + a >>= 1; + } + bit = 0; + b = 0x04; + c = 0x80; + for (i = 0; i < 3; i++) { + if (d3 & c) + bit |= b; + c >>= 2; + b >>= 1; + } + b = 0x01; + a = dat[add]; + a ^= (b << bit); + dat[add] = a; + return 1; + } else { + i = 0; + while (d1) { + if (d1 & 0x01) + ++i; + d1 >>= 1; + } + while (d2) { + if (d2 & 0x01) + ++i; + d2 >>= 1; + } + while (d3) { + if (d3 & 0x01) + ++i; + d3 >>= 1; + } + if (i == 1) { + /* ECC Code Error Correction */ + read_ecc[0] = calc_ecc[0]; + read_ecc[1] = calc_ecc[1]; + read_ecc[2] = calc_ecc[2]; + return 2; + } else { + /* Uncorrectable Error */ + return -1; + } + } } - if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) - return 1; - + /* Should never happen */ return -1; } + +EXPORT_SYMBOL(nand_calculate_ecc); EXPORT_SYMBOL(nand_correct_data); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/mtd/nand/nandsim.c b/trunk/drivers/mtd/nand/nandsim.c index 9008bc5493fb..6903f5b903c6 100644 --- a/trunk/drivers/mtd/nand/nandsim.c +++ b/trunk/drivers/mtd/nand/nandsim.c @@ -1523,7 +1523,7 @@ static int __init ns_init_module(void) chip->verify_buf = ns_nand_verify_buf; chip->write_word = ns_nand_write_word; chip->read_word = ns_nand_read_word; - chip->ecc.mode = NAND_ECC_SOFT; + chip->eccmode = NAND_ECC_SOFT; chip->options |= NAND_SKIP_BBTSCAN; /* diff --git a/trunk/drivers/mtd/nand/ndfc.c b/trunk/drivers/mtd/nand/ndfc.c deleted file mode 100644 index e2dc81de106a..000000000000 --- a/trunk/drivers/mtd/nand/ndfc.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * drivers/mtd/ndfc.c - * - * Overview: - * Platform independend driver for NDFC (NanD Flash Controller) - * integrated into EP440 cores - * - * Author: Thomas Gleixner - * - * Copyright 2006 IBM - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -struct ndfc_nand_mtd { - struct mtd_info mtd; - struct nand_chip chip; - struct platform_nand_chip *pl_chip; -}; - -static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS]; - -struct ndfc_controller { - void __iomem *ndfcbase; - struct nand_hw_control ndfc_control; - atomic_t childs_active; -}; - -static struct ndfc_controller ndfc_ctrl; - -static void ndfc_select_chip(struct mtd_info *mtd, int chip) -{ - uint32_t ccr; - struct ndfc_controller *ndfc = &ndfc_ctrl; - struct nand_chip *nandchip = mtd->priv; - struct ndfc_nand_mtd *nandmtd = nandchip->priv; - struct platform_nand_chip *pchip = nandmtd->pl_chip; - - ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); - if (chip >= 0) { - ccr &= ~NDFC_CCR_BS_MASK; - ccr |= NDFC_CCR_BS(chip + pchip->chip_offset); - } else - ccr |= NDFC_CCR_RESET_CE; - writel(ccr, ndfc->ndfcbase + NDFC_CCR); -} - -static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd) -{ - struct ndfc_controller *ndfc = &ndfc_ctrl; - struct nand_chip *chip = mtd->priv; - - switch (cmd) { - case NAND_CTL_SETCLE: - chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_CMD; - break; - case NAND_CTL_SETALE: - chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_ALE; - break; - default: - chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; - break; - } -} - -static int ndfc_ready(struct mtd_info *mtd) -{ - struct ndfc_controller *ndfc = &ndfc_ctrl; - - return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; -} - -static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) -{ - uint32_t ccr; - struct ndfc_controller *ndfc = &ndfc_ctrl; - - ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); - ccr |= NDFC_CCR_RESET_ECC; - __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); - wmb(); -} - -static int ndfc_calculate_ecc(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_code) -{ - struct ndfc_controller *ndfc = &ndfc_ctrl; - uint32_t ecc; - uint8_t *p = (uint8_t *)&ecc; - - wmb(); - ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC); - ecc_code[0] = p[1]; - ecc_code[1] = p[2]; - ecc_code[2] = p[3]; - - return 0; -} - -/* - * Speedups for buffer read/write/verify - * - * NDFC allows 32bit read/write of data. So we can speed up the buffer - * functions. No further checking, as nand_base will always read/write - * page aligned. - */ -static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct ndfc_controller *ndfc = &ndfc_ctrl; - uint32_t *p = (uint32_t *) buf; - - for(;len > 0; len -= 4) - *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA); -} - -static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - struct ndfc_controller *ndfc = &ndfc_ctrl; - uint32_t *p = (uint32_t *) buf; - - for(;len > 0; len -= 4) - __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA); -} - -static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - struct ndfc_controller *ndfc = &ndfc_ctrl; - uint32_t *p = (uint32_t *) buf; - - for(;len > 0; len -= 4) - if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA)) - return -EFAULT; - return 0; -} - -/* - * Initialize chip structure - */ -static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) -{ - struct ndfc_controller *ndfc = &ndfc_ctrl; - struct nand_chip *chip = &mtd->chip; - - chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; - chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; - chip->hwcontrol = ndfc_hwcontrol; - chip->dev_ready = ndfc_ready; - chip->select_chip = ndfc_select_chip; - chip->chip_delay = 50; - chip->priv = mtd; - chip->options = mtd->pl_chip->options; - chip->controller = &ndfc->ndfc_control; - chip->read_buf = ndfc_read_buf; - chip->write_buf = ndfc_write_buf; - chip->verify_buf = ndfc_verify_buf; - chip->ecc.correct = nand_correct_data; - chip->ecc.hwctl = ndfc_enable_hwecc; - chip->ecc.calculate = ndfc_calculate_ecc; - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = 256; - chip->ecc.bytes = 3; - chip->autooob = mtd->pl_chip->autooob; - mtd->mtd.priv = chip; - mtd->mtd.owner = THIS_MODULE; -} - -static int ndfc_chip_probe(struct platform_device *pdev) -{ - int rc; - struct platform_nand_chip *nc = pdev->dev.platform_data; - struct ndfc_chip_settings *settings = nc->priv; - struct ndfc_controller *ndfc = &ndfc_ctrl; - struct ndfc_nand_mtd *nandmtd; - - if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS) - return -EINVAL; - - /* Set the bank settings */ - __raw_writel(settings->bank_settings, - ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2)); - - nandmtd = &ndfc_mtd[pdev->id]; - if (nandmtd->pl_chip) - return -EBUSY; - - nandmtd->pl_chip = nc; - ndfc_chip_init(nandmtd); - - /* Scan for chips */ - if (nand_scan(&nandmtd->mtd, nc->nr_chips)) { - nandmtd->pl_chip = NULL; - return -ENODEV; - } - -#ifdef CONFIG_MTD_PARTITIONS - printk("Number of partitions %d\n", nc->nr_partitions); - if (nc->nr_partitions) { - struct mtd_info *mtd_ubi; - nc->partitions[NAND_PARTS_CONTENT_IDX].mtdp = &mtd_ubi; - - add_mtd_device(&nandmtd->mtd); /* for testing */ - add_mtd_partitions(&nandmtd->mtd, - nc->partitions, - nc->nr_partitions); - - add_mtd_device(mtd_ubi); - - } else -#else - add_mtd_device(&nandmtd->mtd); -#endif - - atomic_inc(&ndfc->childs_active); - return 0; -} - -static int ndfc_chip_remove(struct platform_device *pdev) -{ - return 0; -} - -static int ndfc_nand_probe(struct platform_device *pdev) -{ - struct platform_nand_ctrl *nc = pdev->dev.platform_data; - struct ndfc_controller_settings *settings = nc->priv; - struct resource *res = pdev->resource; - struct ndfc_controller *ndfc = &ndfc_ctrl; - unsigned long long phys = NDFC_PHYSADDR_OFFS | res->start; - - ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1); - if (!ndfc->ndfcbase) { - printk(KERN_ERR "NDFC: ioremap failed\n"); - return -EIO; - } - - __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR); - - spin_lock_init(&ndfc->ndfc_control.lock); - init_waitqueue_head(&ndfc->ndfc_control.wq); - - platform_set_drvdata(pdev, ndfc); - - printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n", - __raw_readl(ndfc->ndfcbase + NDFC_REVID)); - - return 0; -} - -static int ndfc_nand_remove(struct platform_device *pdev) -{ - struct ndfc_controller *ndfc = platform_get_drvdata(pdev); - - if (atomic_read(&ndfc->childs_active)) - return -EBUSY; - - if (ndfc) { - platform_set_drvdata(pdev, NULL); - iounmap(ndfc_ctrl.ndfcbase); - ndfc_ctrl.ndfcbase = NULL; - } - return 0; -} - -/* driver device registration */ - -static struct platform_driver ndfc_chip_driver = { - .probe = ndfc_chip_probe, - .remove = ndfc_chip_remove, - .driver = { - .name = "ndfc-chip", - .owner = THIS_MODULE, - }, -}; - -static struct platform_driver ndfc_nand_driver = { - .probe = ndfc_nand_probe, - .remove = ndfc_nand_remove, - .driver = { - .name = "ndfc-nand", - .owner = THIS_MODULE, - }, -}; - -static int __init ndfc_nand_init(void) -{ - int ret = platform_driver_register(&ndfc_nand_driver); - - if (!ret) - ret = platform_driver_register(&ndfc_chip_driver); - return ret; -} - -static void __exit ndfc_nand_exit(void) -{ - platform_driver_unregister(&ndfc_chip_driver); - platform_driver_unregister(&ndfc_nand_driver); -} - -module_init(ndfc_nand_init); -module_exit(ndfc_nand_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Thomas Gleixner "); -MODULE_DESCRIPTION("Platform driver for NDFC"); diff --git a/trunk/drivers/mtd/nand/ppchameleonevb.c b/trunk/drivers/mtd/nand/ppchameleonevb.c index 9fab0998524d..5d4d16fb1df6 100644 --- a/trunk/drivers/mtd/nand/ppchameleonevb.c +++ b/trunk/drivers/mtd/nand/ppchameleonevb.c @@ -257,7 +257,7 @@ static int __init ppchameleonevb_init(void) #endif this->chip_delay = NAND_BIG_DELAY_US; /* ECC mode */ - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; /* Scan to find existence of the device (it could not be mounted) */ if (nand_scan(ppchameleon_mtd, 1)) { @@ -358,7 +358,7 @@ static int __init ppchameleonevb_init(void) this->chip_delay = NAND_SMALL_DELAY_US; /* ECC mode */ - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; /* Scan to find existence of the device */ if (nand_scan(ppchameleonevb_mtd, 1)) { diff --git a/trunk/drivers/mtd/nand/rtc_from4.c b/trunk/drivers/mtd/nand/rtc_from4.c index a2122fe4101a..bc9d849fbd5d 100644 --- a/trunk/drivers/mtd/nand/rtc_from4.c +++ b/trunk/drivers/mtd/nand/rtc_from4.c @@ -570,21 +570,19 @@ static int __init rtc_from4_init(void) #ifdef RTC_FROM4_HWECC printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n"); - this->ecc.mode = NAND_ECC_HW_SYNDROME; - this->ecc.size = 512; - this->ecc.bytes = 8; + this->eccmode = NAND_ECC_HW8_512; this->options |= NAND_HWECC_SYNDROME; /* return the status of extra status and ECC checks */ this->errstat = rtc_from4_errstat; /* set the nand_oobinfo to support FPGA H/W error detection */ this->autooob = &rtc_from4_nand_oobinfo; - this->ecc.hwctl = rtc_from4_enable_hwecc; - this->ecc.calculate = rtc_from4_calculate_ecc; - this->ecc.correct = rtc_from4_correct_data; + this->enable_hwecc = rtc_from4_enable_hwecc; + this->calculate_ecc = rtc_from4_calculate_ecc; + this->correct_data = rtc_from4_correct_data; #else printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n"); - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; #endif /* set the bad block tables to support debugging */ diff --git a/trunk/drivers/mtd/nand/s3c2410.c b/trunk/drivers/mtd/nand/s3c2410.c index 608340a25278..f8002596de8b 100644 --- a/trunk/drivers/mtd/nand/s3c2410.c +++ b/trunk/drivers/mtd/nand/s3c2410.c @@ -520,20 +520,18 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, nmtd->set = set; if (hardware_ecc) { - chip->ecc.correct = s3c2410_nand_correct_data; - chip->ecc.hwctl = s3c2410_nand_enable_hwecc; - chip->ecc.calculate = s3c2410_nand_calculate_ecc; - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = 512; - chip->ecc.bytes = 3; + chip->correct_data = s3c2410_nand_correct_data; + chip->enable_hwecc = s3c2410_nand_enable_hwecc; + chip->calculate_ecc = s3c2410_nand_calculate_ecc; + chip->eccmode = NAND_ECC_HW3_512; chip->autooob = &nand_hw_eccoob; if (info->is_s3c2440) { - chip->ecc.hwctl = s3c2440_nand_enable_hwecc; - chip->ecc.calculate = s3c2440_nand_calculate_ecc; + chip->enable_hwecc = s3c2440_nand_enable_hwecc; + chip->calculate_ecc = s3c2440_nand_calculate_ecc; } } else { - chip->ecc.mode = NAND_ECC_SOFT; + chip->eccmode = NAND_ECC_SOFT; } } diff --git a/trunk/drivers/mtd/nand/sharpsl.c b/trunk/drivers/mtd/nand/sharpsl.c index 5554d0b97c8c..60e10c0d6980 100644 --- a/trunk/drivers/mtd/nand/sharpsl.c +++ b/trunk/drivers/mtd/nand/sharpsl.c @@ -201,17 +201,15 @@ static int __init sharpsl_nand_init(void) /* 15 us command delay time */ this->chip_delay = 15; /* set eccmode using hardware ECC */ - this->ecc.mode = NAND_ECC_HW; - this->ecc.size = 256; - this->ecc.bytes = 3; + this->eccmode = NAND_ECC_HW3_256; this->badblock_pattern = &sharpsl_bbt; if (machine_is_akita() || machine_is_borzoi()) { this->badblock_pattern = &sharpsl_akita_bbt; this->autooob = &akita_oobinfo; } - this->ecc.hwctl = sharpsl_nand_enable_hwecc; - this->ecc.calculate = sharpsl_nand_calculate_ecc; - this->ecc.correct = nand_correct_data; + this->enable_hwecc = sharpsl_nand_enable_hwecc; + this->calculate_ecc = sharpsl_nand_calculate_ecc; + this->correct_data = nand_correct_data; /* Scan to find existence of the device */ err = nand_scan(sharpsl_mtd, 1); diff --git a/trunk/drivers/mtd/nand/toto.c b/trunk/drivers/mtd/nand/toto.c index 50aa6a46911f..c51c89559514 100644 --- a/trunk/drivers/mtd/nand/toto.c +++ b/trunk/drivers/mtd/nand/toto.c @@ -146,7 +146,7 @@ static int __init toto_init(void) this->dev_ready = NULL; /* 25 us command delay time */ this->chip_delay = 30; - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; /* Scan to find existance of the device */ if (nand_scan(toto_mtd, 1)) { diff --git a/trunk/drivers/mtd/nand/ts7250.c b/trunk/drivers/mtd/nand/ts7250.c index 70bce1b0326c..622db3127f7c 100644 --- a/trunk/drivers/mtd/nand/ts7250.c +++ b/trunk/drivers/mtd/nand/ts7250.c @@ -155,7 +155,7 @@ static int __init ts7250_init(void) this->hwcontrol = ts7250_hwcontrol; this->dev_ready = ts7250_device_ready; this->chip_delay = 15; - this->ecc.mode = NAND_ECC_SOFT; + this->eccmode = NAND_ECC_SOFT; printk("Searching for NAND flash...\n"); /* Scan to find existence of the device */ diff --git a/trunk/fs/jffs2/erase.c b/trunk/fs/jffs2/erase.c index f677d6950fd4..0fc19a2fb5d9 100644 --- a/trunk/fs/jffs2/erase.c +++ b/trunk/fs/jffs2/erase.c @@ -410,10 +410,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb /* Everything else got zeroed before the erase */ jeb->free_size = c->sector_size; - marker_ref->next_in_ino = NULL; marker_ref->flash_offset = jeb->offset | REF_NORMAL; - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size); + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); } spin_lock(&c->erase_completion_lock); diff --git a/trunk/fs/jffs2/gc.c b/trunk/fs/jffs2/gc.c index 4773ba24304f..153755bc1d53 100644 --- a/trunk/fs/jffs2/gc.c +++ b/trunk/fs/jffs2/gc.c @@ -634,11 +634,8 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", rawlen, phys_ofs, ret, retlen); if (retlen) { - /* Doesn't belong to any inode */ - nraw->next_in_ino = NULL; - nraw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, nraw, rawlen); + jffs2_add_physical_node_ref(c, nraw, rawlen, NULL); jffs2_mark_node_obsolete(c, nraw); } else { printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset); @@ -678,18 +675,8 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, goto out_node; } nraw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, nraw, rawlen); + jffs2_add_physical_node_ref(c, nraw, rawlen, ic); - if (ic) { - /* Link into per-inode list. This is safe because of the ic - state being INO_STATE_GC. Note that if we're doing this - for an inode which is in-core, the 'nraw' pointer is then - going to be fetched from ic->nodes by our caller. */ - spin_lock(&c->erase_completion_lock); - nraw->next_in_ino = ic->nodes; - ic->nodes = nraw; - spin_unlock(&c->erase_completion_lock); - } jffs2_mark_node_obsolete(c, raw); D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); diff --git a/trunk/fs/jffs2/nodelist.c b/trunk/fs/jffs2/nodelist.c index 7d563f938b1c..d25d4919ca97 100644 --- a/trunk/fs/jffs2/nodelist.c +++ b/trunk/fs/jffs2/nodelist.c @@ -1048,7 +1048,8 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) } void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct jffs2_raw_node_ref *ref, uint32_t len) + struct jffs2_raw_node_ref *ref, uint32_t len, + struct jffs2_inode_cache *ic) { if (!jeb->first_node) jeb->first_node = ref; @@ -1065,6 +1066,13 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, } jeb->last_node = ref; + if (ic) { + ref->next_in_ino = ic->nodes; + ic->nodes = ref; + } else { + ref->next_in_ino = NULL; + } + switch(ref_flags(ref)) { case REF_UNCHECKED: c->unchecked_size += len; @@ -1120,12 +1128,11 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size; ref->flash_offset |= REF_OBSOLETE; - ref->next_in_ino = 0; #ifdef TEST_TOTLEN ref->__totlen = size; #endif - jffs2_link_node_ref(c, jeb, ref, size); + jffs2_link_node_ref(c, jeb, ref, size, NULL); } return 0; diff --git a/trunk/fs/jffs2/nodelist.h b/trunk/fs/jffs2/nodelist.h index 80d1fda2212b..ee5aedcffc12 100644 --- a/trunk/fs/jffs2/nodelist.h +++ b/trunk/fs/jffs2/nodelist.h @@ -307,7 +307,8 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn); void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct jffs2_raw_node_ref *ref, uint32_t len); + struct jffs2_raw_node_ref *ref, uint32_t len, + struct jffs2_inode_cache *ic); extern uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_node_ref *ref); @@ -318,7 +319,10 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs uint32_t *len, int prio, uint32_t sumsize); int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize); -int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, uint32_t len); +int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, + struct jffs2_raw_node_ref *new, + uint32_t len, + struct jffs2_inode_cache *ic); void jffs2_complete_reservation(struct jffs2_sb_info *c); void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); diff --git a/trunk/fs/jffs2/nodemgmt.c b/trunk/fs/jffs2/nodemgmt.c index 9a0f312cfcda..e10e58eab8e5 100644 --- a/trunk/fs/jffs2/nodemgmt.c +++ b/trunk/fs/jffs2/nodemgmt.c @@ -381,7 +381,8 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin * Must be called with the alloc_sem held. */ -int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, uint32_t len) +int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, + uint32_t len, struct jffs2_inode_cache *ic) { struct jffs2_eraseblock *jeb; @@ -403,7 +404,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r #endif spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, new, len); + jffs2_link_node_ref(c, jeb, new, len, ic); if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ diff --git a/trunk/fs/jffs2/scan.c b/trunk/fs/jffs2/scan.c index cffafec01e48..6fce703c0543 100644 --- a/trunk/fs/jffs2/scan.c +++ b/trunk/fs/jffs2/scan.c @@ -361,9 +361,9 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc xd->node = raw; raw->flash_offset = ofs | REF_PRISTINE; - raw->next_in_ino = (void *)xd; - jffs2_link_node_ref(c, jeb, raw, totlen); + jffs2_link_node_ref(c, jeb, raw, totlen, NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; if (jffs2_sum_active()) jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); @@ -425,9 +425,9 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock c->xref_temp = ref; raw->flash_offset = ofs | REF_PRISTINE; - raw->next_in_ino = (void *)ref; - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rr->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rr->totlen)), NULL); + /* FIXME */ raw->next_in_ino = (void *)ref; if (jffs2_sum_active()) jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); @@ -844,10 +844,9 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo printk(KERN_NOTICE "Failed to allocate node ref for clean marker\n"); return -ENOMEM; } - marker_ref->next_in_ino = NULL; marker_ref->flash_offset = ofs | REF_NORMAL; - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size); + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); ofs += PAD(c->cleanmarker_size); } @@ -892,8 +891,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (!ref) return -ENOMEM; ref->flash_offset = ofs | REF_PRISTINE; - ref->next_in_ino = 0; - jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen))); + jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen)), NULL); /* We can't summarise nodes we don't grok */ jffs2_sum_disable_collecting(s); @@ -1004,10 +1002,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc raw->flash_offset = ofs | REF_UNCHECKED; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen)), ic); D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", je32_to_cpu(ri->ino), je32_to_cpu(ri->version), @@ -1082,10 +1077,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo } raw->flash_offset = ofs | REF_PRISTINE; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen)), ic); fd->raw = raw; fd->next = NULL; diff --git a/trunk/fs/jffs2/summary.c b/trunk/fs/jffs2/summary.c index 1451732e1fa7..351ba9f8185e 100644 --- a/trunk/fs/jffs2/summary.c +++ b/trunk/fs/jffs2/summary.c @@ -430,10 +430,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras raw->flash_offset |= REF_UNCHECKED; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen)), ic); *pseudo_random += je32_to_cpu(spi->version); @@ -473,10 +470,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } raw->flash_offset |= REF_PRISTINE; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen)), ic); fd->raw = raw; fd->next = NULL; @@ -525,9 +519,9 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras xd->node = raw; raw->flash_offset |= REF_UNCHECKED; - raw->next_in_ino = (void *)xd; - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen)), NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; *pseudo_random += je32_to_cpu(spx->xid); sp += JFFS2_SUMMARY_XATTR_SIZE; @@ -561,9 +555,9 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras c->xref_temp = ref; raw->flash_offset |= REF_UNCHECKED; - raw->next_in_ino = (void *)ref; - jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref))); + jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref)), NULL); + /* FIXME */ raw->next_in_ino = (void *)ref; *pseudo_random += raw->flash_offset; sp += JFFS2_SUMMARY_XREF_SIZE; @@ -664,9 +658,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb } marker_ref->flash_offset = jeb->offset | REF_NORMAL; - marker_ref->next_in_ino = NULL; - jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr)); + jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr), NULL); } } @@ -686,10 +679,9 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb return -ENOMEM; } - cache_ref->next_in_ino = NULL; cache_ref->flash_offset |= REF_NORMAL; - jffs2_link_node_ref(c, jeb, cache_ref, sumsize); + jffs2_link_node_ref(c, jeb, cache_ref, sumsize, NULL); if (unlikely(jeb->free_size)) { JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", @@ -849,9 +841,8 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size; ref->flash_offset |= REF_OBSOLETE; - ref->next_in_ino = 0; - jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size); + jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size, NULL); } c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; @@ -909,11 +900,10 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) return -ENOMEM; } - summary_ref->next_in_ino = NULL; summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, summary_ref, infosize); + jffs2_link_node_ref(c, jeb, summary_ref, infosize, NULL); return 0; } diff --git a/trunk/fs/jffs2/wbuf.c b/trunk/fs/jffs2/wbuf.c index 0442a5753d33..62f685faeba8 100644 --- a/trunk/fs/jffs2/wbuf.c +++ b/trunk/fs/jffs2/wbuf.c @@ -312,9 +312,8 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) return; raw2->flash_offset = ofs | REF_OBSOLETE; - raw2->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw)); + jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw), NULL); } return; } @@ -507,11 +506,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) return -ENOMEM; ref->flash_offset = c->wbuf_ofs + c->wbuf_len; ref->flash_offset |= REF_OBSOLETE; - ref->next_in_ino = NULL; spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, ref, waste); + jffs2_link_node_ref(c, jeb, ref, waste, NULL); /* FIXME: that made it count as dirty. Convert to wasted */ jeb->dirty_size -= waste; c->dirty_size -= waste; @@ -613,30 +611,20 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) return ret; } - -static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf, - size_t len) +int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) { - if (len && !c->wbuf_len && (len >= c->wbuf_pagesize)) - return 0; - - if (len > (c->wbuf_pagesize - c->wbuf_len)) - len = c->wbuf_pagesize - c->wbuf_len; - memcpy(c->wbuf + c->wbuf_len, buf, len); - c->wbuf_len += (uint32_t) len; - return len; -} - -int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, - unsigned long count, loff_t to, size_t *retlen, - uint32_t ino) -{ - struct jffs2_eraseblock *jeb; - size_t wbuf_retlen, donelen = 0; + struct kvec outvecs[3]; + uint32_t totlen = 0; + uint32_t split_ofs = 0; + uint32_t old_totlen; + int ret, splitvec = -1; + int invec, outvec; + size_t wbuf_retlen; + unsigned char *wbuf_ptr; + size_t donelen = 0; uint32_t outvec_to = to; - int ret, invec; - /* If not writebuffered flash, don't bother */ + /* If not NAND flash, don't bother */ if (!jffs2_is_writebuffered(c)) return jffs2_flash_direct_writev(c, invecs, count, to, retlen); @@ -649,11 +637,9 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, memset(c->wbuf,0xff,c->wbuf_pagesize); } - /* - * Fixup the wbuf if we are moving to a new eraseblock. The - * checks below fail for ECC'd NOR because cleanmarker == 16, - * so a block starts at xxx0010. - */ + /* Fixup the wbuf if we are moving to a new eraseblock. The checks below + fail for ECC'd NOR because cleanmarker == 16, so a block starts at + xxx0010. */ if (jffs2_nor_ecc(c)) { if (((c->wbuf_ofs % c->sector_size) == 0) && !c->wbuf_len) { c->wbuf_ofs = PAGE_DIV(to); @@ -662,22 +648,23 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, } } - /* - * Sanity checks on target address. It's permitted to write - * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to - * write at the beginning of a new erase block. Anything else, - * and you die. New block starts at xxx000c (0-b = block - * header) - */ + /* Sanity checks on target address. + It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), + and it's permitted to write at the beginning of a new + erase block. Anything else, and you die. + New block starts at xxx000c (0-b = block header) + */ if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { /* It's a write to a new block */ if (c->wbuf_len) { - D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx " - "causes flush of wbuf at 0x%08x\n", - (unsigned long)to, c->wbuf_ofs)); + D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); - if (ret) - goto outerr; + if (ret) { + /* the underlying layer has to check wbuf_len to do the cleanup */ + D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret)); + *retlen = 0; + goto exit; + } } /* set pointer to new block */ c->wbuf_ofs = PAGE_DIV(to); @@ -686,70 +673,165 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { /* We're not writing immediately after the writebuffer. Bad. */ - printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write " - "to %08lx\n", (unsigned long)to); + printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lx\n", (unsigned long)to); if (c->wbuf_len) printk(KERN_CRIT "wbuf was previously %08x-%08x\n", - c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len); + c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len); BUG(); } - /* adjust alignment offset */ - if (c->wbuf_len != PAGE_MOD(to)) { - c->wbuf_len = PAGE_MOD(to); - /* take care of alignment to next page */ - if (!c->wbuf_len) { - c->wbuf_len = c->wbuf_pagesize; - ret = __jffs2_flush_wbuf(c, NOPAD); - if (ret) - goto outerr; - } + /* Note outvecs[3] above. We know count is never greater than 2 */ + if (count > 2) { + printk(KERN_CRIT "jffs2_flash_writev(): count is %ld\n", count); + BUG(); } - for (invec = 0; invec < count; invec++) { - int vlen = invecs[invec].iov_len; - uint8_t *v = invecs[invec].iov_base; + invec = 0; + outvec = 0; - wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); + /* Fill writebuffer first, if already in use */ + if (c->wbuf_len) { + uint32_t invec_ofs = 0; - if (c->wbuf_len == c->wbuf_pagesize) { - ret = __jffs2_flush_wbuf(c, NOPAD); - if (ret) - goto outerr; + /* adjust alignment offset */ + if (c->wbuf_len != PAGE_MOD(to)) { + c->wbuf_len = PAGE_MOD(to); + /* take care of alignment to next page */ + if (!c->wbuf_len) + c->wbuf_len = c->wbuf_pagesize; } - vlen -= wbuf_retlen; - outvec_to += wbuf_retlen; - donelen += wbuf_retlen; - v += wbuf_retlen; - - if (vlen >= c->wbuf_pagesize) { - ret = c->mtd->write(c->mtd, outvec_to, PAGE_DIV(vlen), - &wbuf_retlen, v); - if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen)) - goto outfile; - - vlen -= wbuf_retlen; - outvec_to += wbuf_retlen; - c->wbuf_ofs = outvec_to; - donelen += wbuf_retlen; - v += wbuf_retlen; + + while(c->wbuf_len < c->wbuf_pagesize) { + uint32_t thislen; + + if (invec == count) + goto alldone; + + thislen = c->wbuf_pagesize - c->wbuf_len; + + if (thislen >= invecs[invec].iov_len) + thislen = invecs[invec].iov_len; + + invec_ofs = thislen; + + memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen); + c->wbuf_len += thislen; + donelen += thislen; + /* Get next invec, if actual did not fill the buffer */ + if (c->wbuf_len < c->wbuf_pagesize) + invec++; } - wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); - if (c->wbuf_len == c->wbuf_pagesize) { - ret = __jffs2_flush_wbuf(c, NOPAD); - if (ret) - goto outerr; + /* write buffer is full, flush buffer */ + ret = __jffs2_flush_wbuf(c, NOPAD); + if (ret) { + /* the underlying layer has to check wbuf_len to do the cleanup */ + D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret)); + /* Retlen zero to make sure our caller doesn't mark the space dirty. + We've already done everything that's necessary */ + *retlen = 0; + goto exit; + } + outvec_to += donelen; + c->wbuf_ofs = outvec_to; + + /* All invecs done ? */ + if (invec == count) + goto alldone; + + /* Set up the first outvec, containing the remainder of the + invec we partially used */ + if (invecs[invec].iov_len > invec_ofs) { + outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs; + totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs; + if (totlen > c->wbuf_pagesize) { + splitvec = outvec; + split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen); + } + outvec++; + } + invec++; + } + + /* OK, now we've flushed the wbuf and the start of the bits + we have been asked to write, now to write the rest.... */ + + /* totlen holds the amount of data still to be written */ + old_totlen = totlen; + for ( ; invec < count; invec++,outvec++ ) { + outvecs[outvec].iov_base = invecs[invec].iov_base; + totlen += outvecs[outvec].iov_len = invecs[invec].iov_len; + if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) { + splitvec = outvec; + split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen); + old_totlen = totlen; + } + } + + /* Now the outvecs array holds all the remaining data to write */ + /* Up to splitvec,split_ofs is to be written immediately. The rest + goes into the (now-empty) wbuf */ + + if (splitvec != -1) { + uint32_t remainder; + + remainder = outvecs[splitvec].iov_len - split_ofs; + outvecs[splitvec].iov_len = split_ofs; + + /* We did cross a page boundary, so we write some now */ + if (jffs2_cleanmarker_oob(c)) + ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); + else + ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); + + if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { + /* At this point we have no problem, + c->wbuf is empty. However refile nextblock to avoid + writing again to same address. + */ + struct jffs2_eraseblock *jeb; + + spin_lock(&c->erase_completion_lock); + + jeb = &c->blocks[outvec_to / c->sector_size]; + jffs2_block_refile(c, jeb, REFILE_ANYWAY); + + *retlen = 0; + spin_unlock(&c->erase_completion_lock); + goto exit; } - outvec_to += wbuf_retlen; donelen += wbuf_retlen; + c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); + + if (remainder) { + outvecs[splitvec].iov_base += split_ofs; + outvecs[splitvec].iov_len = remainder; + } else { + splitvec++; + } + + } else { + splitvec = 0; } - /* - * If there's a remainder in the wbuf and it's a non-GC write, - * remember that the wbuf affects this ino - */ + /* Now splitvec points to the start of the bits we have to copy + into the wbuf */ + wbuf_ptr = c->wbuf; + + for ( ; splitvec < outvec; splitvec++) { + /* Don't copy the wbuf into itself */ + if (outvecs[splitvec].iov_base == c->wbuf) + continue; + memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len); + wbuf_ptr += outvecs[splitvec].iov_len; + donelen += outvecs[splitvec].iov_len; + } + c->wbuf_len = wbuf_ptr - c->wbuf; + + /* If there's a remainder in the wbuf and it's a non-GC write, + remember that the wbuf affects this ino */ +alldone: *retlen = donelen; if (jffs2_sum_active()) { @@ -762,24 +844,8 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, jffs2_wbuf_dirties_inode(c, ino); ret = 0; - up_write(&c->wbuf_sem); - return ret; -outfile: - /* - * At this point we have no problem, c->wbuf is empty. However - * refile nextblock to avoid writing again to same address. - */ - - spin_lock(&c->erase_completion_lock); - - jeb = &c->blocks[outvec_to / c->sector_size]; - jffs2_block_refile(c, jeb, REFILE_ANYWAY); - - spin_unlock(&c->erase_completion_lock); - -outerr: - *retlen = 0; +exit: up_write(&c->wbuf_sem); return ret; } diff --git a/trunk/fs/jffs2/write.c b/trunk/fs/jffs2/write.c index 4462541d11f8..319a70f531f8 100644 --- a/trunk/fs/jffs2/write.c +++ b/trunk/fs/jffs2/write.c @@ -122,16 +122,13 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 /* Mark the space as dirtied */ if (retlen) { - /* Doesn't belong to any inode */ - raw->next_in_ino = NULL; - /* Don't change raw->size to match retlen. We may have written the node header already, and only the data will seem corrupted, in which case the scan would skip over any node we write before the original intended end of this node */ raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen)); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), NULL); jffs2_mark_node_obsolete(c, raw); } else { printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); @@ -189,13 +186,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 } else { raw->flash_offset |= REF_NORMAL; } - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen)); - - /* Link into per-inode list */ - spin_lock(&c->erase_completion_lock); - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; - spin_unlock(&c->erase_completion_lock); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), f->inocache); D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), @@ -275,9 +266,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff sizeof(*rd)+namelen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { - raw->next_in_ino = NULL; raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen)); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), NULL); jffs2_mark_node_obsolete(c, raw); } else { printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); @@ -323,12 +313,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff } /* Mark the space used */ raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen)); - - spin_lock(&c->erase_completion_lock); - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; - spin_unlock(&c->erase_completion_lock); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), f->inocache); if (retried) { jffs2_dbg_acct_sanity_check(c,NULL); diff --git a/trunk/fs/jffs2/xattr.c b/trunk/fs/jffs2/xattr.c index e16f8460ff04..76d166140381 100644 --- a/trunk/fs/jffs2/xattr.c +++ b/trunk/fs/jffs2/xattr.c @@ -322,7 +322,6 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x if (!raw) return -ENOMEM; raw->flash_offset = phys_ofs; - raw->next_in_ino = (void *)xd; /* Setup raw-xattr */ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -345,8 +344,7 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x rc = rc ? rc : -EIO; if (length) { raw->flash_offset |= REF_OBSOLETE; - raw->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw, PAD(totlen)); + jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); jffs2_mark_node_obsolete(c, raw); } else { jffs2_free_raw_node_ref(raw); @@ -356,7 +354,9 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x /* success */ raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(totlen)); + jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; + if (xd->node) delete_xattr_datum_node(c, xd); xd->node = raw; @@ -566,7 +566,6 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, if (!raw) return -ENOMEM; raw->flash_offset = phys_ofs; - raw->next_in_ino = (void *)ref; rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); @@ -584,8 +583,7 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, ret = ret ? ret : -EIO; if (length) { raw->flash_offset |= REF_OBSOLETE; - raw->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr))); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); jffs2_mark_node_obsolete(c, raw); } else { jffs2_free_raw_node_ref(raw); @@ -594,7 +592,8 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, } raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr))); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); + /* FIXME */ raw->next_in_ino = (void *)ref; if (ref->node) delete_xattr_ref_node(c, ref); ref->node = raw; diff --git a/trunk/include/linux/mtd/nand.h b/trunk/include/linux/mtd/nand.h index 460525841a27..da5e67b3fc70 100644 --- a/trunk/include/linux/mtd/nand.h +++ b/trunk/include/linux/mtd/nand.h @@ -11,11 +11,47 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Info: - * Contains standard defines and IDs for NAND flash devices + * Info: + * Contains standard defines and IDs for NAND flash devices * - * Changelog: - * See git changelog. + * Changelog: + * 01-31-2000 DMW Created + * 09-18-2000 SJH Moved structure out of the Disk-On-Chip drivers + * so it can be used by other NAND flash device + * drivers. I also changed the copyright since none + * of the original contents of this file are specific + * to DoC devices. David can whack me with a baseball + * bat later if I did something naughty. + * 10-11-2000 SJH Added private NAND flash structure for driver + * 10-24-2000 SJH Added prototype for 'nand_scan' function + * 10-29-2001 TG changed nand_chip structure to support + * hardwarespecific function for accessing control lines + * 02-21-2002 TG added support for different read/write adress and + * ready/busy line access function + * 02-26-2002 TG added chip_delay to nand_chip structure to optimize + * command delay times for different chips + * 04-28-2002 TG OOB config defines moved from nand.c to avoid duplicate + * defines in jffs2/wbuf.c + * 08-07-2002 TG forced bad block location to byte 5 of OOB, even if + * CONFIG_MTD_NAND_ECC_JFFS2 is not set + * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC + * + * 08-29-2002 tglx nand_chip structure: data_poi for selecting + * internal / fs-driver buffer + * support for 6byte/512byte hardware ECC + * read_ecc, write_ecc extended for different oob-layout + * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB, + * NAND_YAFFS_OOB + * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL + * Split manufacturer and device ID structures + * + * 02-08-2004 tglx added option field to nand structure for chip anomalities + * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id + * update of nand_chip structure description + * 01-17-2005 dmarlin added extended commands for AG-AND device and added option + * for BBT_AUTO_REFRESH. + * 01-20-2005 dmarlin added optional pointer to hardware specific callback for + * extra error status checks. */ #ifndef __LINUX_MTD_NAND_H #define __LINUX_MTD_NAND_H @@ -32,8 +68,7 @@ extern int nand_scan (struct mtd_info *mtd, int max_chips); extern void nand_release (struct mtd_info *mtd); /* Read raw data from the device without ECC */ -extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, - size_t len, size_t ooblen); +extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen); /* The maximum number of NAND chips in an array */ @@ -49,7 +84,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, * Constants for hardware specific CLE/ALE/NCE function */ /* Select the chip by setting nCE to low */ -#define NAND_CTL_SETNCE 1 +#define NAND_CTL_SETNCE 1 /* Deselect the chip by setting nCE to high */ #define NAND_CTL_CLRNCE 2 /* Select the command latch by setting CLE to high */ @@ -113,12 +148,21 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, /* * Constants for ECC_MODES */ -typedef enum { - NAND_ECC_NONE, - NAND_ECC_SOFT, - NAND_ECC_HW, - NAND_ECC_HW_SYNDROME, -} nand_ecc_modes_t; + +/* No ECC. Usage is not recommended ! */ +#define NAND_ECC_NONE 0 +/* Software ECC 3 byte ECC per 256 Byte data */ +#define NAND_ECC_SOFT 1 +/* Hardware ECC 3 byte ECC per 256 Byte data */ +#define NAND_ECC_HW3_256 2 +/* Hardware ECC 3 byte ECC per 512 Byte data */ +#define NAND_ECC_HW3_512 3 +/* Hardware ECC 3 byte ECC per 512 Byte data */ +#define NAND_ECC_HW6_512 4 +/* Hardware ECC 8 byte ECC per 512 Byte data */ +#define NAND_ECC_HW8_512 6 +/* Hardware ECC 12 byte ECC per 2048 Byte data */ +#define NAND_ECC_HW12_2048 7 /* * Constants for Hardware ECC @@ -183,8 +227,6 @@ typedef enum { #define NAND_SKIP_BBTSCAN 0x00040000 /* Options set by nand scan */ -/* Nand scan has allocated controller struct */ -#define NAND_CONTROLLER_ALLOC 0x20000000 /* Nand scan has allocated oob_buf */ #define NAND_OOBBUF_ALLOC 0x40000000 /* Nand scan has allocated data_buf */ @@ -221,31 +263,6 @@ struct nand_hw_control { wait_queue_head_t wq; }; -/** - * struct nand_ecc_ctrl - Control structure for ecc - * @mode: ecc mode - * @steps: number of ecc steps per page - * @size: data bytes per ecc step - * @bytes: ecc bytes per step - * @hwctl: function to control hardware ecc generator. Must only - * be provided if an hardware ECC is available - * @calculate: function for ecc calculation or readback from ecc hardware - * @correct: function for ecc correction, matching to ecc generator (sw/hw) - */ -struct nand_ecc_ctrl { - nand_ecc_modes_t mode; - int steps; - int size; - int bytes; - int (*hwctl)(struct mtd_info *mtd, int mode); - int (*calculate)(struct mtd_info *mtd, - const uint8_t *dat, - uint8_t *ecc_code); - int (*correct)(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, - uint8_t *calc_ecc); -}; - /** * struct nand_chip - NAND Private Flash Chip Data * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device @@ -266,12 +283,20 @@ struct nand_ecc_ctrl { * is read from the chip status register * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready - * @ecc: [BOARDSPECIFIC] ecc control ctructure + * @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware + * @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw) + * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only + * be provided if a hardware ECC is available * @erase_cmd: [INTERN] erase command write function, selectable due to AND support * @scan_bbt: [REPLACEABLE] function to scan bad block table + * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines + * @eccsize: [INTERN] databytes used per ecc-calculation + * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step + * @eccsteps: [INTERN] number of ecc calculation steps per page * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) + * @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress - * @state: [INTERN] the current state of the NAND device + * @state: [INTERN] the current state of the NAND device * @page_shift: [INTERN] number of address bits in a page (column address bits) * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry @@ -292,8 +317,7 @@ struct nand_ecc_ctrl { * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup * @bbt_md: [REPLACEABLE] bad block table mirror descriptor * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan - * @controller: [REPLACEABLE] a pointer to a hardware controller structure - * which is shared among multiple independend devices + * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices * @priv: [OPTIONAL] pointer to private chip date * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks * (determine if errors are correctable) @@ -301,37 +325,44 @@ struct nand_ecc_ctrl { struct nand_chip { void __iomem *IO_ADDR_R; - void __iomem *IO_ADDR_W; + void __iomem *IO_ADDR_W; - uint8_t (*read_byte)(struct mtd_info *mtd); - void (*write_byte)(struct mtd_info *mtd, uint8_t byte); + u_char (*read_byte)(struct mtd_info *mtd); + void (*write_byte)(struct mtd_info *mtd, u_char byte); u16 (*read_word)(struct mtd_info *mtd); void (*write_word)(struct mtd_info *mtd, u16 word); - void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); - void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); - int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); + void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); + void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); + int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); void (*select_chip)(struct mtd_info *mtd, int chip); int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); - void (*hwcontrol)(struct mtd_info *mtd, int cmd); - int (*dev_ready)(struct mtd_info *mtd); - void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); - int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); + void (*hwcontrol)(struct mtd_info *mtd, int cmd); + int (*dev_ready)(struct mtd_info *mtd); + void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); + int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); + int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); + int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); + void (*enable_hwecc)(struct mtd_info *mtd, int mode); void (*erase_cmd)(struct mtd_info *mtd, int page); int (*scan_bbt)(struct mtd_info *mtd); - struct nand_ecc_ctrl ecc; - int chip_delay; + int eccmode; + int eccsize; + int eccbytes; + int eccsteps; + int chip_delay; + spinlock_t chip_lock; wait_queue_head_t wq; - nand_state_t state; - int page_shift; + nand_state_t state; + int page_shift; int phys_erase_shift; int bbt_erase_shift; int chip_shift; - uint8_t *data_buf; - uint8_t *oob_buf; + u_char *data_buf; + u_char *oob_buf; int oobdirty; - uint8_t *data_poi; + u_char *data_poi; unsigned int options; int badblockpos; int numchips; @@ -357,19 +388,19 @@ struct nand_chip { #define NAND_MFR_NATIONAL 0x8f #define NAND_MFR_RENESAS 0x07 #define NAND_MFR_STMICRO 0x20 -#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_HYNIX 0xad /** * struct nand_flash_dev - NAND Flash Device ID Structure * - * @name: Identify the device type - * @id: device ID code - * @pagesize: Pagesize in bytes. Either 256 or 512 or 0 + * @name: Identify the device type + * @id: device ID code + * @pagesize: Pagesize in bytes. Either 256 or 512 or 0 * If the pagesize is 0, then the real pagesize * and the eraseize are determined from the * extended id bytes in the chip - * @erasesize: Size of an erase block in the flash device. - * @chipsize: Total chipsize in Mega Bytes + * @erasesize: Size of an erase block in the flash device. + * @chipsize: Total chipsize in Mega Bytes * @options: Bitfield to store chip relevant options */ struct nand_flash_dev { @@ -384,7 +415,7 @@ struct nand_flash_dev { /** * struct nand_manufacturers - NAND Flash Manufacturer ID Structure * @name: Manufacturer name - * @id: manufacturer ID code of device. + * @id: manufacturer ID code of device. */ struct nand_manufacturers { int id; @@ -424,7 +455,7 @@ struct nand_bbt_descr { int veroffs; uint8_t version[NAND_MAX_CHIPS]; int len; - int maxblocks; + int maxblocks; int reserved_block_code; uint8_t *pattern; }; @@ -469,8 +500,8 @@ extern int nand_default_bbt (struct mtd_info *mtd); extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, uint8_t * buf, uint8_t * oob_buf, - struct nand_oobinfo *oobsel, int flags); + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags); /* * Constants for oob configuration @@ -478,51 +509,4 @@ extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, #define NAND_SMALL_BADBLOCK_POS 5 #define NAND_LARGE_BADBLOCK_POS 0 -/** - * struct platform_nand_chip - chip level device structure - * - * @nr_chips: max. number of chips to scan for - * @chip_offs: chip number offset - * @nr_partitions: number of partitions pointed to be partitoons (or zero) - * @partitions: mtd partition list - * @chip_delay: R/B delay value in us - * @options: Option flags, e.g. 16bit buswidth - * @priv: hardware controller specific settings - */ -struct platform_nand_chip { - int nr_chips; - int chip_offset; - int nr_partitions; - struct mtd_partition *partitions; - int chip_delay; - unsigned int options; - void *priv; -}; - -/** - * struct platform_nand_ctrl - controller level device structure - * - * @hwcontrol: platform specific hardware control structure - * @dev_ready: platform specific function to read ready/busy pin - * @select_chip: platform specific chip select function - * @priv_data: private data to transport driver specific settings - * - * All fields are optional and depend on the hardware driver requirements - */ -struct platform_nand_ctrl { - void (*hwcontrol)(struct mtd_info *mtd, int cmd); - int (*dev_ready)(struct mtd_info *mtd); - void (*select_chip)(struct mtd_info *mtd, int chip); - void *priv; -}; - -/* Some helpers to access the data structures */ -static inline -struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - return chip->priv; -} - #endif /* __LINUX_MTD_NAND_H */ diff --git a/trunk/include/linux/mtd/ndfc.h b/trunk/include/linux/mtd/ndfc.h deleted file mode 100644 index 31d61f07d768..000000000000 --- a/trunk/include/linux/mtd/ndfc.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * linux/include/linux/mtd/ndfc.h - * - * Copyright (c) 2006 Thomas Gleixner - * - * 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 - * published by the Free Software Foundation. - * - * Info: - * Contains defines, datastructures for ndfc nand controller - * - */ -#ifndef __LINUX_MTD_NDFC_H -#define __LINUX_MTD_NDFC_H - -/* NDFC Register definitions */ -#define NDFC_CMD 0x00 -#define NDFC_ALE 0x04 -#define NDFC_DATA 0x08 -#define NDFC_ECC 0x10 -#define NDFC_BCFG0 0x30 -#define NDFC_BCFG1 0x34 -#define NDFC_BCFG2 0x38 -#define NDFC_BCFG3 0x3c -#define NDFC_CCR 0x40 -#define NDFC_STAT 0x44 -#define NDFC_HWCTL 0x48 -#define NDFC_REVID 0x50 - -#define NDFC_STAT_IS_READY 0x01000000 - -#define NDFC_CCR_RESET_CE 0x80000000 /* CE Reset */ -#define NDFC_CCR_RESET_ECC 0x40000000 /* ECC Reset */ -#define NDFC_CCR_RIE 0x20000000 /* Interrupt Enable on Device Rdy */ -#define NDFC_CCR_REN 0x10000000 /* Enable wait for Rdy in LinearR */ -#define NDFC_CCR_ROMEN 0x08000000 /* Enable ROM In LinearR */ -#define NDFC_CCR_ARE 0x04000000 /* Auto-Read Enable */ -#define NDFC_CCR_BS(x) (((x) & 0x3) << 24) /* Select Bank on CE[x] */ -#define NDFC_CCR_BS_MASK 0x03000000 /* Select Bank */ -#define NDFC_CCR_ARAC0 0x00000000 /* 3 Addr, 1 Col 2 Row 512b page */ -#define NDFC_CCR_ARAC1 0x00001000 /* 4 Addr, 1 Col 3 Row 512b page */ -#define NDFC_CCR_ARAC2 0x00002000 /* 4 Addr, 2 Col 2 Row 2K page */ -#define NDFC_CCR_ARAC3 0x00003000 /* 5 Addr, 2 Col 3 Row 2K page */ -#define NDFC_CCR_ARAC_MASK 0x00003000 /* Auto-Read mode Addr Cycles */ -#define NDFC_CCR_RPG 0x0000C000 /* Auto-Read Page */ -#define NDFC_CCR_EBCC 0x00000004 /* EBC Configuration Completed */ -#define NDFC_CCR_DHC 0x00000002 /* Direct Hardware Control Enable */ - -#define NDFC_BxCFG_EN 0x80000000 /* Bank Enable */ -#define NDFC_BxCFG_CED 0x40000000 /* nCE Style */ -#define NDFC_BxCFG_SZ_MASK 0x08000000 /* Bank Size */ -#define NDFC_BxCFG_SZ_8BIT 0x00000000 /* 8bit */ -#define NDFC_BxCFG_SZ_16BIT 0x08000000 /* 16bit */ - -#define NDFC_MAX_BANKS 4 - -struct ndfc_controller_settings { - uint32_t ccr_settings; -}; - -struct ndfc_chip_settings { - uint32_t bank_settings; -}; - -#endif