diff options
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 2 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0020.c | 2 | ||||
-rw-r--r-- | drivers/mtd/maps/dilnetpc.c | 4 | ||||
-rw-r--r-- | drivers/mtd/maps/esb2rom.c | 11 | ||||
-rw-r--r-- | drivers/mtd/mtdconcat.c | 1 | ||||
-rw-r--r-- | drivers/mtd/mtdpart.c | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/diskonchip.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 1 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 77 | ||||
-rw-r--r-- | fs/jffs2/background.c | 8 | ||||
-rw-r--r-- | fs/jffs2/readinode.c | 16 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 9 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 7 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 1 | ||||
-rw-r--r-- | include/linux/mtd/onenand.h | 5 |
15 files changed, 115 insertions, 38 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index e3acd398fb..1f64458404 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -359,6 +359,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
359 | cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; | 359 | cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; |
360 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; | 360 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; |
361 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; | 361 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; |
362 | cfi->chips[i].ref_point_counter = 0; | ||
363 | init_waitqueue_head(&(cfi->chips[i].wq)); | ||
362 | } | 364 | } |
363 | 365 | ||
364 | map->fldrv = &cfi_amdstd_chipdrv; | 366 | map->fldrv = &cfi_amdstd_chipdrv; |
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 69d49e0250..b344ff858b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
@@ -158,6 +158,8 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) | |||
158 | cfi->chips[i].word_write_time = 128; | 158 | cfi->chips[i].word_write_time = 128; |
159 | cfi->chips[i].buffer_write_time = 128; | 159 | cfi->chips[i].buffer_write_time = 128; |
160 | cfi->chips[i].erase_time = 1024; | 160 | cfi->chips[i].erase_time = 1024; |
161 | cfi->chips[i].ref_point_counter = 0; | ||
162 | init_waitqueue_head(&(cfi->chips[i].wq)); | ||
161 | } | 163 | } |
162 | 164 | ||
163 | return cfi_staa_setup(map); | 165 | return cfi_staa_setup(map); |
diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index b1104fe1f2..1c3b34ad73 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c | |||
@@ -402,8 +402,8 @@ static int __init init_dnpc(void) | |||
402 | ++higlvl_partition_info[i].name; | 402 | ++higlvl_partition_info[i].name; |
403 | } | 403 | } |
404 | 404 | ||
405 | printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", | 405 | printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%llx\n", |
406 | is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); | 406 | is_dnp ? "DNPC" : "ADNP", dnpc_map.size, (unsigned long long)dnpc_map.phys); |
407 | 407 | ||
408 | dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); | 408 | dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); |
409 | 409 | ||
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index 0bc013fd66..aa64a47527 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c | |||
@@ -30,7 +30,7 @@ | |||
30 | 30 | ||
31 | #define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */ | 31 | #define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */ |
32 | 32 | ||
33 | #define BIOS_CNTL 0xDC | 33 | #define BIOS_CNTL 0xDC |
34 | #define BIOS_LOCK_ENABLE 0x02 | 34 | #define BIOS_LOCK_ENABLE 0x02 |
35 | #define BIOS_WRITE_ENABLE 0x01 | 35 | #define BIOS_WRITE_ENABLE 0x01 |
36 | 36 | ||
@@ -145,7 +145,7 @@ static void esb2rom_cleanup(struct esb2rom_window *window) | |||
145 | } | 145 | } |
146 | 146 | ||
147 | static int __devinit esb2rom_init_one(struct pci_dev *pdev, | 147 | static int __devinit esb2rom_init_one(struct pci_dev *pdev, |
148 | const struct pci_device_id *ent) | 148 | const struct pci_device_id *ent) |
149 | { | 149 | { |
150 | static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; | 150 | static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; |
151 | struct esb2rom_window *window = &esb2rom_window; | 151 | struct esb2rom_window *window = &esb2rom_window; |
@@ -185,7 +185,7 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, | |||
185 | /* Find a region continuous to the end of the ROM window */ | 185 | /* Find a region continuous to the end of the ROM window */ |
186 | window->phys = 0; | 186 | window->phys = 0; |
187 | pci_read_config_word(pdev, FWH_DEC_EN1, &word); | 187 | pci_read_config_word(pdev, FWH_DEC_EN1, &word); |
188 | printk(KERN_DEBUG "pci_read_config_byte : %x\n", word); | 188 | printk(KERN_DEBUG "pci_read_config_word : %x\n", word); |
189 | 189 | ||
190 | if ((word & FWH_8MiB) == FWH_8MiB) | 190 | if ((word & FWH_8MiB) == FWH_8MiB) |
191 | window->phys = 0xff400000; | 191 | window->phys = 0xff400000; |
@@ -212,6 +212,11 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, | |||
212 | else if ((word & FWH_0_5MiB) == FWH_0_5MiB) | 212 | else if ((word & FWH_0_5MiB) == FWH_0_5MiB) |
213 | window->phys = 0xfff80000; | 213 | window->phys = 0xfff80000; |
214 | 214 | ||
215 | if (window->phys == 0) { | ||
216 | printk(KERN_ERR MOD_NAME ": Rom window is closed\n"); | ||
217 | goto out; | ||
218 | } | ||
219 | |||
215 | /* reserved 0x0020 and 0x0010 */ | 220 | /* reserved 0x0020 and 0x0010 */ |
216 | window->phys -= 0x400000UL; | 221 | window->phys -= 0x400000UL; |
217 | window->size = (0xffffffffUL - window->phys) + 1UL; | 222 | window->size = (0xffffffffUL - window->phys) + 1UL; |
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 880580c44e..41844ea024 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
@@ -727,6 +727,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c | |||
727 | concat->mtd.erasesize = subdev[0]->erasesize; | 727 | concat->mtd.erasesize = subdev[0]->erasesize; |
728 | concat->mtd.writesize = subdev[0]->writesize; | 728 | concat->mtd.writesize = subdev[0]->writesize; |
729 | concat->mtd.oobsize = subdev[0]->oobsize; | 729 | concat->mtd.oobsize = subdev[0]->oobsize; |
730 | concat->mtd.oobavail = subdev[0]->oobavail; | ||
730 | if (subdev[0]->writev) | 731 | if (subdev[0]->writev) |
731 | concat->mtd.writev = concat_writev; | 732 | concat->mtd.writev = concat_writev; |
732 | if (subdev[0]->read_oob) | 733 | if (subdev[0]->read_oob) |
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 633def3fb0..1af989023c 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -200,6 +200,11 @@ static int part_erase (struct mtd_info *mtd, struct erase_info *instr) | |||
200 | return -EINVAL; | 200 | return -EINVAL; |
201 | instr->addr += part->offset; | 201 | instr->addr += part->offset; |
202 | ret = part->master->erase(part->master, instr); | 202 | ret = part->master->erase(part->master, instr); |
203 | if (ret) { | ||
204 | if (instr->fail_addr != 0xffffffff) | ||
205 | instr->fail_addr -= part->offset; | ||
206 | instr->addr -= part->offset; | ||
207 | } | ||
203 | return ret; | 208 | return ret; |
204 | } | 209 | } |
205 | 210 | ||
@@ -338,6 +343,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
338 | slave->mtd.size = parts[i].size; | 343 | slave->mtd.size = parts[i].size; |
339 | slave->mtd.writesize = master->writesize; | 344 | slave->mtd.writesize = master->writesize; |
340 | slave->mtd.oobsize = master->oobsize; | 345 | slave->mtd.oobsize = master->oobsize; |
346 | slave->mtd.oobavail = master->oobavail; | ||
341 | slave->mtd.subpage_sft = master->subpage_sft; | 347 | slave->mtd.subpage_sft = master->subpage_sft; |
342 | 348 | ||
343 | slave->mtd.name = parts[i].name; | 349 | slave->mtd.name = parts[i].name; |
@@ -559,4 +565,3 @@ EXPORT_SYMBOL_GPL(deregister_mtd_parser); | |||
559 | MODULE_LICENSE("GPL"); | 565 | MODULE_LICENSE("GPL"); |
560 | MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); | 566 | MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); |
561 | MODULE_DESCRIPTION("Generic support for partitioning of MTD devices"); | 567 | MODULE_DESCRIPTION("Generic support for partitioning of MTD devices"); |
562 | |||
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 12608c13cc..595208f965 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -114,7 +114,7 @@ module_param(no_autopart, int, 0); | |||
114 | static int show_firmware_partition = 0; | 114 | static int show_firmware_partition = 0; |
115 | module_param(show_firmware_partition, int, 0); | 115 | module_param(show_firmware_partition, int, 0); |
116 | 116 | ||
117 | #ifdef MTD_NAND_DISKONCHIP_BBTWRITE | 117 | #ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE |
118 | static int inftl_bbt_write = 1; | 118 | static int inftl_bbt_write = 1; |
119 | #else | 119 | #else |
120 | static int inftl_bbt_write = 0; | 120 | static int inftl_bbt_write = 0; |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index acaf97bc80..6af37b8cff 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -2524,6 +2524,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
2524 | for (i = 0; chip->ecc.layout->oobfree[i].length; i++) | 2524 | for (i = 0; chip->ecc.layout->oobfree[i].length; i++) |
2525 | chip->ecc.layout->oobavail += | 2525 | chip->ecc.layout->oobavail += |
2526 | chip->ecc.layout->oobfree[i].length; | 2526 | chip->ecc.layout->oobfree[i].length; |
2527 | mtd->oobavail = chip->ecc.layout->oobavail; | ||
2527 | 2528 | ||
2528 | /* | 2529 | /* |
2529 | * Set the number of read / write steps for one page depending on ECC | 2530 | * Set the number of read / write steps for one page depending on ECC |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7f1cb6e5dc..9e14a26ca4 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -4,6 +4,11 @@ | |||
4 | * Copyright (C) 2005-2007 Samsung Electronics | 4 | * Copyright (C) 2005-2007 Samsung Electronics |
5 | * Kyungmin Park <kyungmin.park@samsung.com> | 5 | * Kyungmin Park <kyungmin.park@samsung.com> |
6 | * | 6 | * |
7 | * Credits: | ||
8 | * Adrian Hunter <ext-adrian.hunter@nokia.com>: | ||
9 | * auto-placement support, read-while load support, various fixes | ||
10 | * Copyright (C) Nokia Corporation, 2007 | ||
11 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
@@ -831,7 +836,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col | |||
831 | int readcol = column; | 836 | int readcol = column; |
832 | int readend = column + thislen; | 837 | int readend = column + thislen; |
833 | int lastgap = 0; | 838 | int lastgap = 0; |
834 | uint8_t *oob_buf = this->page_buf + mtd->writesize; | 839 | uint8_t *oob_buf = this->oob_buf; |
835 | 840 | ||
836 | for (free = this->ecclayout->oobfree; free->length; ++free) { | 841 | for (free = this->ecclayout->oobfree; free->length; ++free) { |
837 | if (readcol >= lastgap) | 842 | if (readcol >= lastgap) |
@@ -849,7 +854,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col | |||
849 | int n = ed - st; | 854 | int n = ed - st; |
850 | memcpy(buf, oob_buf + st, n); | 855 | memcpy(buf, oob_buf + st, n); |
851 | buf += n; | 856 | buf += n; |
852 | } | 857 | } else |
858 | break; | ||
853 | } | 859 | } |
854 | return 0; | 860 | return 0; |
855 | } | 861 | } |
@@ -947,9 +953,9 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
947 | 953 | ||
948 | /** | 954 | /** |
949 | * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band | 955 | * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band |
950 | * @mtd: MTD device structure | 956 | * @param mtd: MTD device structure |
951 | * @from: offset to read from | 957 | * @param from: offset to read from |
952 | * @ops: oob operation description structure | 958 | * @param ops: oob operation description structure |
953 | */ | 959 | */ |
954 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | 960 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, |
955 | struct mtd_oob_ops *ops) | 961 | struct mtd_oob_ops *ops) |
@@ -1017,7 +1023,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
1017 | * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan | 1023 | * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan |
1018 | * @param mtd MTD device structure | 1024 | * @param mtd MTD device structure |
1019 | * @param from offset to read from | 1025 | * @param from offset to read from |
1020 | * @param @ops oob operation description structure | 1026 | * @param ops oob operation description structure |
1021 | * | 1027 | * |
1022 | * OneNAND read out-of-band data from the spare area for bbt scan | 1028 | * OneNAND read out-of-band data from the spare area for bbt scan |
1023 | */ | 1029 | */ |
@@ -1093,7 +1099,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | |||
1093 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) | 1099 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) |
1094 | { | 1100 | { |
1095 | struct onenand_chip *this = mtd->priv; | 1101 | struct onenand_chip *this = mtd->priv; |
1096 | char *readp = this->page_buf + mtd->writesize; | 1102 | char oobbuf[64]; |
1097 | int status, i; | 1103 | int status, i; |
1098 | 1104 | ||
1099 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); | 1105 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); |
@@ -1102,9 +1108,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to | |||
1102 | if (status) | 1108 | if (status) |
1103 | return status; | 1109 | return status; |
1104 | 1110 | ||
1105 | this->read_bufferram(mtd, ONENAND_SPARERAM, readp, 0, mtd->oobsize); | 1111 | this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); |
1106 | for(i = 0; i < mtd->oobsize; i++) | 1112 | for (i = 0; i < mtd->oobsize; i++) |
1107 | if (buf[i] != 0xFF && buf[i] != readp[i]) | 1113 | if (buf[i] != 0xFF && buf[i] != oobbuf[i]) |
1108 | return -EBADMSG; | 1114 | return -EBADMSG; |
1109 | 1115 | ||
1110 | return 0; | 1116 | return 0; |
@@ -1290,7 +1296,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, | |||
1290 | int n = ed - st; | 1296 | int n = ed - st; |
1291 | memcpy(oob_buf + st, buf, n); | 1297 | memcpy(oob_buf + st, buf, n); |
1292 | buf += n; | 1298 | buf += n; |
1293 | } | 1299 | } else |
1300 | break; | ||
1294 | } | 1301 | } |
1295 | return 0; | 1302 | return 0; |
1296 | } | 1303 | } |
@@ -1312,6 +1319,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1312 | struct onenand_chip *this = mtd->priv; | 1319 | struct onenand_chip *this = mtd->priv; |
1313 | int column, ret = 0, oobsize; | 1320 | int column, ret = 0, oobsize; |
1314 | int written = 0; | 1321 | int written = 0; |
1322 | u_char *oobbuf; | ||
1315 | 1323 | ||
1316 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 1324 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
1317 | 1325 | ||
@@ -1331,7 +1339,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1331 | } | 1339 | } |
1332 | 1340 | ||
1333 | /* For compatibility with NAND: Do not allow write past end of page */ | 1341 | /* For compatibility with NAND: Do not allow write past end of page */ |
1334 | if (column + len > oobsize) { | 1342 | if (unlikely(column + len > oobsize)) { |
1335 | printk(KERN_ERR "onenand_write_oob: " | 1343 | printk(KERN_ERR "onenand_write_oob: " |
1336 | "Attempt to write past end of page\n"); | 1344 | "Attempt to write past end of page\n"); |
1337 | return -EINVAL; | 1345 | return -EINVAL; |
@@ -1348,6 +1356,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1348 | /* Grab the lock and see if the device is available */ | 1356 | /* Grab the lock and see if the device is available */ |
1349 | onenand_get_device(mtd, FL_WRITING); | 1357 | onenand_get_device(mtd, FL_WRITING); |
1350 | 1358 | ||
1359 | oobbuf = this->oob_buf; | ||
1360 | |||
1351 | /* Loop until all data write */ | 1361 | /* Loop until all data write */ |
1352 | while (written < len) { | 1362 | while (written < len) { |
1353 | int thislen = min_t(int, oobsize, len - written); | 1363 | int thislen = min_t(int, oobsize, len - written); |
@@ -1358,12 +1368,12 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1358 | 1368 | ||
1359 | /* We send data to spare ram with oobsize | 1369 | /* We send data to spare ram with oobsize |
1360 | * to prevent byte access */ | 1370 | * to prevent byte access */ |
1361 | memset(this->page_buf, 0xff, mtd->oobsize); | 1371 | memset(oobbuf, 0xff, mtd->oobsize); |
1362 | if (mode == MTD_OOB_AUTO) | 1372 | if (mode == MTD_OOB_AUTO) |
1363 | onenand_fill_auto_oob(mtd, this->page_buf, buf, column, thislen); | 1373 | onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen); |
1364 | else | 1374 | else |
1365 | memcpy(this->page_buf + column, buf, thislen); | 1375 | memcpy(oobbuf + column, buf, thislen); |
1366 | this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); | 1376 | this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); |
1367 | 1377 | ||
1368 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); | 1378 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); |
1369 | 1379 | ||
@@ -1375,7 +1385,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1375 | break; | 1385 | break; |
1376 | } | 1386 | } |
1377 | 1387 | ||
1378 | ret = onenand_verify_oob(mtd, this->page_buf, to); | 1388 | ret = onenand_verify_oob(mtd, oobbuf, to); |
1379 | if (ret) { | 1389 | if (ret) { |
1380 | printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret); | 1390 | printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret); |
1381 | break; | 1391 | break; |
@@ -1400,9 +1410,9 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1400 | 1410 | ||
1401 | /** | 1411 | /** |
1402 | * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band | 1412 | * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band |
1403 | * @mtd: MTD device structure | 1413 | * @param mtd: MTD device structure |
1404 | * @from: offset to read from | 1414 | * @param to: offset to write |
1405 | * @ops: oob operation description structure | 1415 | * @param ops: oob operation description structure |
1406 | */ | 1416 | */ |
1407 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, | 1417 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, |
1408 | struct mtd_oob_ops *ops) | 1418 | struct mtd_oob_ops *ops) |
@@ -1616,6 +1626,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1616 | * @param mtd MTD device structure | 1626 | * @param mtd MTD device structure |
1617 | * @param ofs offset relative to mtd start | 1627 | * @param ofs offset relative to mtd start |
1618 | * @param len number of bytes to lock or unlock | 1628 | * @param len number of bytes to lock or unlock |
1629 | * @param cmd lock or unlock command | ||
1619 | * | 1630 | * |
1620 | * Lock or unlock one or more blocks | 1631 | * Lock or unlock one or more blocks |
1621 | */ | 1632 | */ |
@@ -2117,10 +2128,11 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
2117 | } | 2128 | } |
2118 | 2129 | ||
2119 | /** | 2130 | /** |
2120 | * onenand_print_device_info - Print device ID | 2131 | * onenand_print_device_info - Print device & version ID |
2121 | * @param device device ID | 2132 | * @param device device ID |
2133 | * @param version version ID | ||
2122 | * | 2134 | * |
2123 | * Print device ID | 2135 | * Print device & version ID |
2124 | */ | 2136 | */ |
2125 | static void onenand_print_device_info(int device, int version) | 2137 | static void onenand_print_device_info(int device, int version) |
2126 | { | 2138 | { |
@@ -2320,15 +2332,25 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
2320 | 2332 | ||
2321 | /* Allocate buffers, if necessary */ | 2333 | /* Allocate buffers, if necessary */ |
2322 | if (!this->page_buf) { | 2334 | if (!this->page_buf) { |
2323 | size_t len; | 2335 | this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL); |
2324 | len = mtd->writesize + mtd->oobsize; | ||
2325 | this->page_buf = kmalloc(len, GFP_KERNEL); | ||
2326 | if (!this->page_buf) { | 2336 | if (!this->page_buf) { |
2327 | printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n"); | 2337 | printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n"); |
2328 | return -ENOMEM; | 2338 | return -ENOMEM; |
2329 | } | 2339 | } |
2330 | this->options |= ONENAND_PAGEBUF_ALLOC; | 2340 | this->options |= ONENAND_PAGEBUF_ALLOC; |
2331 | } | 2341 | } |
2342 | if (!this->oob_buf) { | ||
2343 | this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL); | ||
2344 | if (!this->oob_buf) { | ||
2345 | printk(KERN_ERR "onenand_scan(): Can't allocate oob_buf\n"); | ||
2346 | if (this->options & ONENAND_PAGEBUF_ALLOC) { | ||
2347 | this->options &= ~ONENAND_PAGEBUF_ALLOC; | ||
2348 | kfree(this->page_buf); | ||
2349 | } | ||
2350 | return -ENOMEM; | ||
2351 | } | ||
2352 | this->options |= ONENAND_OOBBUF_ALLOC; | ||
2353 | } | ||
2332 | 2354 | ||
2333 | this->state = FL_READY; | 2355 | this->state = FL_READY; |
2334 | init_waitqueue_head(&this->wq); | 2356 | init_waitqueue_head(&this->wq); |
@@ -2367,6 +2389,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
2367 | for (i = 0; this->ecclayout->oobfree[i].length; i++) | 2389 | for (i = 0; this->ecclayout->oobfree[i].length; i++) |
2368 | this->ecclayout->oobavail += | 2390 | this->ecclayout->oobavail += |
2369 | this->ecclayout->oobfree[i].length; | 2391 | this->ecclayout->oobfree[i].length; |
2392 | mtd->oobavail = this->ecclayout->oobavail; | ||
2370 | 2393 | ||
2371 | mtd->ecclayout = this->ecclayout; | 2394 | mtd->ecclayout = this->ecclayout; |
2372 | 2395 | ||
@@ -2424,9 +2447,11 @@ void onenand_release(struct mtd_info *mtd) | |||
2424 | kfree(bbm->bbt); | 2447 | kfree(bbm->bbt); |
2425 | kfree(this->bbm); | 2448 | kfree(this->bbm); |
2426 | } | 2449 | } |
2427 | /* Buffer allocated by onenand_scan */ | 2450 | /* Buffers allocated by onenand_scan */ |
2428 | if (this->options & ONENAND_PAGEBUF_ALLOC) | 2451 | if (this->options & ONENAND_PAGEBUF_ALLOC) |
2429 | kfree(this->page_buf); | 2452 | kfree(this->page_buf); |
2453 | if (this->options & ONENAND_OOBBUF_ALLOC) | ||
2454 | kfree(this->oob_buf); | ||
2430 | } | 2455 | } |
2431 | 2456 | ||
2432 | EXPORT_SYMBOL_GPL(onenand_scan); | 2457 | EXPORT_SYMBOL_GPL(onenand_scan); |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 6eb3daebd5..888f236e54 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
@@ -99,7 +99,13 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
99 | if (try_to_freeze()) | 99 | if (try_to_freeze()) |
100 | continue; | 100 | continue; |
101 | 101 | ||
102 | cond_resched(); | 102 | /* This thread is purely an optimisation. But if it runs when |
103 | other things could be running, it actually makes things a | ||
104 | lot worse. Use yield() and put it at the back of the runqueue | ||
105 | every time. Especially during boot, pulling an inode in | ||
106 | with read_inode() is much preferable to having the GC thread | ||
107 | get there first. */ | ||
108 | yield(); | ||
103 | 109 | ||
104 | /* Put_super will send a SIGKILL and then wait on the sem. | 110 | /* Put_super will send a SIGKILL and then wait on the sem. |
105 | */ | 111 | */ |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 58a0b912e9..717a48cf7d 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -373,7 +373,14 @@ free_out: | |||
373 | static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un) | 373 | static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un) |
374 | { | 374 | { |
375 | /* We don't mark unknown nodes as REF_UNCHECKED */ | 375 | /* We don't mark unknown nodes as REF_UNCHECKED */ |
376 | BUG_ON(ref_flags(ref) == REF_UNCHECKED); | 376 | if (ref_flags(ref) == REF_UNCHECKED) { |
377 | JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n", | ||
378 | ref_offset(ref)); | ||
379 | JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n", | ||
380 | je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), | ||
381 | je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); | ||
382 | return 1; | ||
383 | } | ||
377 | 384 | ||
378 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); | 385 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); |
379 | 386 | ||
@@ -576,6 +583,13 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
576 | jffs2_mark_node_obsolete(c, ref); | 583 | jffs2_mark_node_obsolete(c, ref); |
577 | goto cont; | 584 | goto cont; |
578 | } | 585 | } |
586 | /* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */ | ||
587 | if (!je32_to_cpu(node->u.hdr_crc) && !je16_to_cpu(node->u.nodetype) && | ||
588 | !je16_to_cpu(node->u.magic) && !je32_to_cpu(node->u.totlen)) { | ||
589 | JFFS2_NOTICE("All zero node header at %#08x.\n", ref_offset(ref)); | ||
590 | jffs2_mark_node_obsolete(c, ref); | ||
591 | goto cont; | ||
592 | } | ||
579 | 593 | ||
580 | switch (je16_to_cpu(node->u.nodetype)) { | 594 | switch (je16_to_cpu(node->u.nodetype)) { |
581 | 595 | ||
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 31c1475d92..7fb45bd491 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -734,6 +734,15 @@ scan_more: | |||
734 | ofs += 4; | 734 | ofs += 4; |
735 | continue; | 735 | continue; |
736 | } | 736 | } |
737 | /* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */ | ||
738 | if (!je32_to_cpu(node->hdr_crc) && !je16_to_cpu(node->nodetype) && | ||
739 | !je16_to_cpu(node->magic) && !je32_to_cpu(node->totlen)) { | ||
740 | noisy_printk(&noise, "jffs2_scan_eraseblock(): All zero node header at 0x%08x.\n", ofs); | ||
741 | if ((err = jffs2_scan_dirty_space(c, jeb, 4))) | ||
742 | return err; | ||
743 | ofs += 4; | ||
744 | continue; | ||
745 | } | ||
737 | 746 | ||
738 | if (ofs + je32_to_cpu(node->totlen) > | 747 | if (ofs + je32_to_cpu(node->totlen) > |
739 | jeb->offset + c->sector_size) { | 748 | jeb->offset + c->sector_size) { |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index de718e3a16..4fac6dd539 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -238,7 +238,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
238 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | 238 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
239 | 239 | ||
240 | spin_lock(&c->erase_completion_lock); | 240 | spin_lock(&c->erase_completion_lock); |
241 | jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); | 241 | if (c->wbuf_ofs % c->mtd->erasesize) |
242 | jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); | ||
243 | else | ||
244 | jffs2_block_refile(c, jeb, REFILE_ANYWAY); | ||
242 | spin_unlock(&c->erase_completion_lock); | 245 | spin_unlock(&c->erase_completion_lock); |
243 | 246 | ||
244 | BUG_ON(!ref_obsolete(jeb->last_node)); | 247 | BUG_ON(!ref_obsolete(jeb->last_node)); |
@@ -1087,7 +1090,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock * | |||
1087 | if (!c->mtd->block_markbad) | 1090 | if (!c->mtd->block_markbad) |
1088 | return 1; // What else can we do? | 1091 | return 1; // What else can we do? |
1089 | 1092 | ||
1090 | D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset)); | 1093 | printk(KERN_WARNING "JFFS2: marking eraseblock at %08x\n as bad", bad_offset); |
1091 | ret = c->mtd->block_markbad(c->mtd, bad_offset); | 1094 | ret = c->mtd->block_markbad(c->mtd, bad_offset); |
1092 | 1095 | ||
1093 | if (ret) { | 1096 | if (ret) { |
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 6a8570be33..3d956c3abb 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -121,6 +121,7 @@ struct mtd_info { | |||
121 | u_int32_t writesize; | 121 | u_int32_t writesize; |
122 | 122 | ||
123 | u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) | 123 | u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) |
124 | u_int32_t oobavail; // Available OOB bytes per block | ||
124 | 125 | ||
125 | // Kernel-only stuff starts here. | 126 | // Kernel-only stuff starts here. |
126 | char *name; | 127 | char *name; |
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index d8af8a95e5..a56d24ada5 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h | |||
@@ -82,7 +82,8 @@ struct onenand_bufferram { | |||
82 | * @wq: [INTERN] wait queue to sleep on if a OneNAND | 82 | * @wq: [INTERN] wait queue to sleep on if a OneNAND |
83 | * operation is in progress | 83 | * operation is in progress |
84 | * @state: [INTERN] the current state of the OneNAND device | 84 | * @state: [INTERN] the current state of the OneNAND device |
85 | * @page_buf: data buffer | 85 | * @page_buf: [INTERN] page main data buffer |
86 | * @oob_buf: [INTERN] page oob data buffer | ||
86 | * @subpagesize: [INTERN] holds the subpagesize | 87 | * @subpagesize: [INTERN] holds the subpagesize |
87 | * @ecclayout: [REPLACEABLE] the default ecc placement scheme | 88 | * @ecclayout: [REPLACEABLE] the default ecc placement scheme |
88 | * @bbm: [REPLACEABLE] pointer to Bad Block Management | 89 | * @bbm: [REPLACEABLE] pointer to Bad Block Management |
@@ -122,6 +123,7 @@ struct onenand_chip { | |||
122 | wait_queue_head_t wq; | 123 | wait_queue_head_t wq; |
123 | onenand_state_t state; | 124 | onenand_state_t state; |
124 | unsigned char *page_buf; | 125 | unsigned char *page_buf; |
126 | unsigned char *oob_buf; | ||
125 | 127 | ||
126 | int subpagesize; | 128 | int subpagesize; |
127 | struct nand_ecclayout *ecclayout; | 129 | struct nand_ecclayout *ecclayout; |
@@ -156,6 +158,7 @@ struct onenand_chip { | |||
156 | #define ONENAND_HAS_CONT_LOCK (0x0001) | 158 | #define ONENAND_HAS_CONT_LOCK (0x0001) |
157 | #define ONENAND_HAS_UNLOCK_ALL (0x0002) | 159 | #define ONENAND_HAS_UNLOCK_ALL (0x0002) |
158 | #define ONENAND_PAGEBUF_ALLOC (0x1000) | 160 | #define ONENAND_PAGEBUF_ALLOC (0x1000) |
161 | #define ONENAND_OOBBUF_ALLOC (0x2000) | ||
159 | 162 | ||
160 | /* | 163 | /* |
161 | * OneNAND Flash Manufacturer ID Codes | 164 | * OneNAND Flash Manufacturer ID Codes |