diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 13:24:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 13:24:08 -0500 |
commit | b3ce1debe2685383a9ad6ace9c49869c3968c013 (patch) | |
tree | dcb606fac467d6ce78a9c608a1e0d2323af44f2b | |
parent | 5b2f7ffcb734d3046144dfbd5ac6d76254a9e522 (diff) | |
parent | c2965f1129ee54afcc4ef293ff0f25fa3a7e7392 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6
Some manual fixups for clashing kfree() cleanups etc.
192 files changed, 11317 insertions, 4890 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 027054dea032..f6b775e63ac8 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: Kconfig,v 1.7 2004/11/22 11:33:56 ijc Exp $ | 1 | # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ |
2 | 2 | ||
3 | menu "Memory Technology Devices (MTD)" | 3 | menu "Memory Technology Devices (MTD)" |
4 | 4 | ||
@@ -10,7 +10,7 @@ config MTD | |||
10 | will provide the generic support for MTD drivers to register | 10 | will provide the generic support for MTD drivers to register |
11 | themselves with the kernel and for potential users of MTD devices | 11 | themselves with the kernel and for potential users of MTD devices |
12 | to enumerate the devices which are present and obtain a handle on | 12 | to enumerate the devices which are present and obtain a handle on |
13 | them. It will also allow you to select individual drivers for | 13 | them. It will also allow you to select individual drivers for |
14 | particular hardware and users of MTD devices. If unsure, say N. | 14 | particular hardware and users of MTD devices. If unsure, say N. |
15 | 15 | ||
16 | config MTD_DEBUG | 16 | config MTD_DEBUG |
@@ -61,11 +61,11 @@ config MTD_REDBOOT_PARTS | |||
61 | 61 | ||
62 | If you need code which can detect and parse this table, and register | 62 | If you need code which can detect and parse this table, and register |
63 | MTD 'partitions' corresponding to each image in the table, enable | 63 | MTD 'partitions' corresponding to each image in the table, enable |
64 | this option. | 64 | this option. |
65 | 65 | ||
66 | You will still need the parsing functions to be called by the driver | 66 | You will still need the parsing functions to be called by the driver |
67 | for your particular device. It won't happen automatically. The | 67 | for your particular device. It won't happen automatically. The |
68 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for | 68 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for |
69 | example. | 69 | example. |
70 | 70 | ||
71 | config MTD_REDBOOT_DIRECTORY_BLOCK | 71 | config MTD_REDBOOT_DIRECTORY_BLOCK |
@@ -81,10 +81,10 @@ config MTD_REDBOOT_DIRECTORY_BLOCK | |||
81 | partition table. A zero or positive value gives an absolete | 81 | partition table. A zero or positive value gives an absolete |
82 | erase block number. A negative value specifies a number of | 82 | erase block number. A negative value specifies a number of |
83 | sectors before the end of the device. | 83 | sectors before the end of the device. |
84 | 84 | ||
85 | For example "2" means block number 2, "-1" means the last | 85 | For example "2" means block number 2, "-1" means the last |
86 | block and "-2" means the penultimate block. | 86 | block and "-2" means the penultimate block. |
87 | 87 | ||
88 | config MTD_REDBOOT_PARTS_UNALLOCATED | 88 | config MTD_REDBOOT_PARTS_UNALLOCATED |
89 | bool " Include unallocated flash regions" | 89 | bool " Include unallocated flash regions" |
90 | depends on MTD_REDBOOT_PARTS | 90 | depends on MTD_REDBOOT_PARTS |
@@ -105,11 +105,11 @@ config MTD_CMDLINE_PARTS | |||
105 | ---help--- | 105 | ---help--- |
106 | Allow generic configuration of the MTD paritition tables via the kernel | 106 | Allow generic configuration of the MTD paritition tables via the kernel |
107 | command line. Multiple flash resources are supported for hardware where | 107 | command line. Multiple flash resources are supported for hardware where |
108 | different kinds of flash memory are available. | 108 | different kinds of flash memory are available. |
109 | 109 | ||
110 | You will still need the parsing functions to be called by the driver | 110 | You will still need the parsing functions to be called by the driver |
111 | for your particular device. It won't happen automatically. The | 111 | for your particular device. It won't happen automatically. The |
112 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for | 112 | SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for |
113 | example. | 113 | example. |
114 | 114 | ||
115 | The format for the command line is as follows: | 115 | The format for the command line is as follows: |
@@ -118,12 +118,12 @@ config MTD_CMDLINE_PARTS | |||
118 | <mtddef> := <mtd-id>:<partdef>[,<partdef>] | 118 | <mtddef> := <mtd-id>:<partdef>[,<partdef>] |
119 | <partdef> := <size>[@offset][<name>][ro] | 119 | <partdef> := <size>[@offset][<name>][ro] |
120 | <mtd-id> := unique id used in mapping driver/device | 120 | <mtd-id> := unique id used in mapping driver/device |
121 | <size> := standard linux memsize OR "-" to denote all | 121 | <size> := standard linux memsize OR "-" to denote all |
122 | remaining space | 122 | remaining space |
123 | <name> := (NAME) | 123 | <name> := (NAME) |
124 | 124 | ||
125 | Due to the way Linux handles the command line, no spaces are | 125 | Due to the way Linux handles the command line, no spaces are |
126 | allowed in the partition definition, including mtd id's and partition | 126 | allowed in the partition definition, including mtd id's and partition |
127 | names. | 127 | names. |
128 | 128 | ||
129 | Examples: | 129 | Examples: |
@@ -240,7 +240,7 @@ config INFTL | |||
240 | tristate "INFTL (Inverse NAND Flash Translation Layer) support" | 240 | tristate "INFTL (Inverse NAND Flash Translation Layer) support" |
241 | depends on MTD | 241 | depends on MTD |
242 | ---help--- | 242 | ---help--- |
243 | This provides support for the Inverse NAND Flash Translation | 243 | This provides support for the Inverse NAND Flash Translation |
244 | Layer which is used on M-Systems' newer DiskOnChip devices. It | 244 | Layer which is used on M-Systems' newer DiskOnChip devices. It |
245 | uses a kind of pseudo-file system on a flash device to emulate | 245 | uses a kind of pseudo-file system on a flash device to emulate |
246 | a block device with 512-byte sectors, on top of which you put | 246 | a block device with 512-byte sectors, on top of which you put |
@@ -253,6 +253,16 @@ config INFTL | |||
253 | permitted to copy, modify and distribute the code as you wish. Just | 253 | permitted to copy, modify and distribute the code as you wish. Just |
254 | not use it. | 254 | not use it. |
255 | 255 | ||
256 | config RFD_FTL | ||
257 | tristate "Resident Flash Disk (Flash Translation Layer) support" | ||
258 | depends on MTD | ||
259 | ---help--- | ||
260 | This provides support for the flash translation layer known | ||
261 | as the Resident Flash Disk (RFD), as used by the Embedded BIOS | ||
262 | of General Software. There is a blurb at: | ||
263 | |||
264 | http://www.gensw.com/pages/prod/bios/rfd.htm | ||
265 | |||
256 | source "drivers/mtd/chips/Kconfig" | 266 | source "drivers/mtd/chips/Kconfig" |
257 | 267 | ||
258 | source "drivers/mtd/maps/Kconfig" | 268 | source "drivers/mtd/maps/Kconfig" |
@@ -261,5 +271,7 @@ source "drivers/mtd/devices/Kconfig" | |||
261 | 271 | ||
262 | source "drivers/mtd/nand/Kconfig" | 272 | source "drivers/mtd/nand/Kconfig" |
263 | 273 | ||
274 | source "drivers/mtd/onenand/Kconfig" | ||
275 | |||
264 | endmenu | 276 | endmenu |
265 | 277 | ||
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index e4ad588327f7..fc9374407c2b 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the memory technology device drivers. | 2 | # Makefile for the memory technology device drivers. |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.5 2004/08/10 20:51:49 dwmw2 Exp $ | 4 | # $Id: Makefile.common,v 1.7 2005/07/11 10:39:27 gleixner Exp $ |
5 | 5 | ||
6 | # Core functionality. | 6 | # Core functionality. |
7 | mtd-y := mtdcore.o | 7 | mtd-y := mtdcore.o |
@@ -20,8 +20,9 @@ obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o | |||
20 | obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o | 20 | obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o |
21 | obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o | 21 | obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o |
22 | obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o | 22 | obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o |
23 | obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o | ||
23 | 24 | ||
24 | nftl-objs := nftlcore.o nftlmount.o | 25 | nftl-objs := nftlcore.o nftlmount.o |
25 | inftl-objs := inftlcore.o inftlmount.o | 26 | inftl-objs := inftlcore.o inftlmount.o |
26 | 27 | ||
27 | obj-y += chips/ maps/ devices/ nand/ | 28 | obj-y += chips/ maps/ devices/ nand/ onenand/ |
diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 7363e101eb0f..6a45be04564b 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c | |||
@@ -1,27 +1,27 @@ | |||
1 | /*====================================================================== | 1 | /*====================================================================== |
2 | 2 | ||
3 | drivers/mtd/afs.c: ARM Flash Layout/Partitioning | 3 | drivers/mtd/afs.c: ARM Flash Layout/Partitioning |
4 | 4 | ||
5 | Copyright (C) 2000 ARM Limited | 5 | Copyright (C) 2000 ARM Limited |
6 | 6 | ||
7 | This program is free software; you can redistribute it and/or modify | 7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | 8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or | 9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. | 10 | (at your option) any later version. |
11 | 11 | ||
12 | This program is distributed in the hope that it will be useful, | 12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. | 15 | GNU General Public License for more details. |
16 | 16 | ||
17 | You should have received a copy of the GNU General Public License | 17 | You should have received a copy of the GNU General Public License |
18 | along with this program; if not, write to the Free Software | 18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | 20 | ||
21 | This is access code for flashes using ARM's flash partitioning | 21 | This is access code for flashes using ARM's flash partitioning |
22 | standards. | 22 | standards. |
23 | 23 | ||
24 | $Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $ | 24 | $Id: afs.c,v 1.15 2005/11/07 11:14:19 gleixner Exp $ |
25 | 25 | ||
26 | ======================================================================*/ | 26 | ======================================================================*/ |
27 | 27 | ||
@@ -163,7 +163,7 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr) | |||
163 | return ret; | 163 | return ret; |
164 | } | 164 | } |
165 | 165 | ||
166 | static int parse_afs_partitions(struct mtd_info *mtd, | 166 | static int parse_afs_partitions(struct mtd_info *mtd, |
167 | struct mtd_partition **pparts, | 167 | struct mtd_partition **pparts, |
168 | unsigned long origin) | 168 | unsigned long origin) |
169 | { | 169 | { |
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index df95d2158b16..eafa23f5cbd6 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/chips/Kconfig | 1 | # drivers/mtd/chips/Kconfig |
2 | # $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $ | 2 | # $Id: Kconfig,v 1.18 2005/11/07 11:14:22 gleixner Exp $ |
3 | 3 | ||
4 | menu "RAM/ROM/Flash chip drivers" | 4 | menu "RAM/ROM/Flash chip drivers" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -39,7 +39,7 @@ config MTD_CFI_ADV_OPTIONS | |||
39 | If you need to specify a specific endianness for access to flash | 39 | If you need to specify a specific endianness for access to flash |
40 | chips, or if you wish to reduce the size of the kernel by including | 40 | chips, or if you wish to reduce the size of the kernel by including |
41 | support for only specific arrangements of flash chips, say 'Y'. This | 41 | support for only specific arrangements of flash chips, say 'Y'. This |
42 | option does not directly affect the code, but will enable other | 42 | option does not directly affect the code, but will enable other |
43 | configuration options which allow you to do so. | 43 | configuration options which allow you to do so. |
44 | 44 | ||
45 | If unsure, say 'N'. | 45 | If unsure, say 'N'. |
@@ -56,7 +56,7 @@ config MTD_CFI_NOSWAP | |||
56 | data bits when writing the 'magic' commands to the chips. Saying | 56 | data bits when writing the 'magic' commands to the chips. Saying |
57 | 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't | 57 | 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't |
58 | enabled, means that the CPU will not do any swapping; the chips | 58 | enabled, means that the CPU will not do any swapping; the chips |
59 | are expected to be wired to the CPU in 'host-endian' form. | 59 | are expected to be wired to the CPU in 'host-endian' form. |
60 | Specific arrangements are possible with the BIG_ENDIAN_BYTE and | 60 | Specific arrangements are possible with the BIG_ENDIAN_BYTE and |
61 | LITTLE_ENDIAN_BYTE, if the bytes are reversed. | 61 | LITTLE_ENDIAN_BYTE, if the bytes are reversed. |
62 | 62 | ||
@@ -79,10 +79,10 @@ config MTD_CFI_GEOMETRY | |||
79 | bool "Specific CFI Flash geometry selection" | 79 | bool "Specific CFI Flash geometry selection" |
80 | depends on MTD_CFI_ADV_OPTIONS | 80 | depends on MTD_CFI_ADV_OPTIONS |
81 | help | 81 | help |
82 | This option does not affect the code directly, but will enable | 82 | This option does not affect the code directly, but will enable |
83 | some other configuration options which would allow you to reduce | 83 | some other configuration options which would allow you to reduce |
84 | the size of the kernel by including support for only certain | 84 | the size of the kernel by including support for only certain |
85 | arrangements of CFI chips. If unsure, say 'N' and all options | 85 | arrangements of CFI chips. If unsure, say 'N' and all options |
86 | which are supported by the current code will be enabled. | 86 | which are supported by the current code will be enabled. |
87 | 87 | ||
88 | config MTD_MAP_BANK_WIDTH_1 | 88 | config MTD_MAP_BANK_WIDTH_1 |
@@ -197,7 +197,7 @@ config MTD_CFI_AMDSTD | |||
197 | help | 197 | help |
198 | The Common Flash Interface defines a number of different command | 198 | The Common Flash Interface defines a number of different command |
199 | sets which a CFI-compliant chip may claim to implement. This code | 199 | sets which a CFI-compliant chip may claim to implement. This code |
200 | provides support for one of those command sets, used on chips | 200 | provides support for one of those command sets, used on chips |
201 | including the AMD Am29LV320. | 201 | including the AMD Am29LV320. |
202 | 202 | ||
203 | config MTD_CFI_AMDSTD_RETRY | 203 | config MTD_CFI_AMDSTD_RETRY |
@@ -237,14 +237,14 @@ config MTD_RAM | |||
237 | tristate "Support for RAM chips in bus mapping" | 237 | tristate "Support for RAM chips in bus mapping" |
238 | depends on MTD | 238 | depends on MTD |
239 | help | 239 | help |
240 | This option enables basic support for RAM chips accessed through | 240 | This option enables basic support for RAM chips accessed through |
241 | a bus mapping driver. | 241 | a bus mapping driver. |
242 | 242 | ||
243 | config MTD_ROM | 243 | config MTD_ROM |
244 | tristate "Support for ROM chips in bus mapping" | 244 | tristate "Support for ROM chips in bus mapping" |
245 | depends on MTD | 245 | depends on MTD |
246 | help | 246 | help |
247 | This option enables basic support for ROM chips accessed through | 247 | This option enables basic support for ROM chips accessed through |
248 | a bus mapping driver. | 248 | a bus mapping driver. |
249 | 249 | ||
250 | config MTD_ABSENT | 250 | config MTD_ABSENT |
@@ -275,7 +275,7 @@ config MTD_AMDSTD | |||
275 | depends on MTD && MTD_OBSOLETE_CHIPS | 275 | depends on MTD && MTD_OBSOLETE_CHIPS |
276 | help | 276 | help |
277 | This option enables support for flash chips using AMD-compatible | 277 | This option enables support for flash chips using AMD-compatible |
278 | commands, including some which are not CFI-compatible and hence | 278 | commands, including some which are not CFI-compatible and hence |
279 | cannot be used with the CONFIG_MTD_CFI_AMDSTD option. | 279 | cannot be used with the CONFIG_MTD_CFI_AMDSTD option. |
280 | 280 | ||
281 | It also works on AMD compatible chips that do conform to CFI. | 281 | It also works on AMD compatible chips that do conform to CFI. |
@@ -285,7 +285,7 @@ config MTD_SHARP | |||
285 | depends on MTD && MTD_OBSOLETE_CHIPS | 285 | depends on MTD && MTD_OBSOLETE_CHIPS |
286 | help | 286 | help |
287 | This option enables support for flash chips using Sharp-compatible | 287 | This option enables support for flash chips using Sharp-compatible |
288 | commands, including some which are not CFI-compatible and hence | 288 | commands, including some which are not CFI-compatible and hence |
289 | cannot be used with the CONFIG_MTD_CFI_INTELxxx options. | 289 | cannot be used with the CONFIG_MTD_CFI_INTELxxx options. |
290 | 290 | ||
291 | config MTD_JEDEC | 291 | config MTD_JEDEC |
diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile index 6830489828c6..8afe3092c4e3 100644 --- a/drivers/mtd/chips/Makefile +++ b/drivers/mtd/chips/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # linux/drivers/chips/Makefile | 2 | # linux/drivers/chips/Makefile |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.4 2004/07/12 16:07:30 dwmw2 Exp $ | 4 | # $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $ |
5 | 5 | ||
6 | # *** BIG UGLY NOTE *** | 6 | # *** BIG UGLY NOTE *** |
7 | # | 7 | # |
@@ -11,7 +11,7 @@ | |||
11 | # the CFI command set drivers are linked before gen_probe.o | 11 | # the CFI command set drivers are linked before gen_probe.o |
12 | 12 | ||
13 | obj-$(CONFIG_MTD) += chipreg.o | 13 | obj-$(CONFIG_MTD) += chipreg.o |
14 | obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o | 14 | obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o |
15 | obj-$(CONFIG_MTD_CFI) += cfi_probe.o | 15 | obj-$(CONFIG_MTD_CFI) += cfi_probe.o |
16 | obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o | 16 | obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o |
17 | obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o | 17 | obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o |
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c index 2dafeba3f3d5..fdb91b6f1d97 100644 --- a/drivers/mtd/chips/amd_flash.c +++ b/drivers/mtd/chips/amd_flash.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Author: Jonas Holmberg <jonas.holmberg@axis.com> | 4 | * Author: Jonas Holmberg <jonas.holmberg@axis.com> |
5 | * | 5 | * |
6 | * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $ | 6 | * $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $ |
7 | * | 7 | * |
8 | * Copyright (c) 2001 Axis Communications AB | 8 | * Copyright (c) 2001 Axis Communications AB |
9 | * | 9 | * |
@@ -93,9 +93,9 @@ | |||
93 | #define D6_MASK 0x40 | 93 | #define D6_MASK 0x40 |
94 | 94 | ||
95 | struct amd_flash_private { | 95 | struct amd_flash_private { |
96 | int device_type; | 96 | int device_type; |
97 | int interleave; | 97 | int interleave; |
98 | int numchips; | 98 | int numchips; |
99 | unsigned long chipshift; | 99 | unsigned long chipshift; |
100 | // const char *im_name; | 100 | // const char *im_name; |
101 | struct flchip chips[0]; | 101 | struct flchip chips[0]; |
@@ -253,7 +253,7 @@ static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len, | |||
253 | int i; | 253 | int i; |
254 | int retval = 0; | 254 | int retval = 0; |
255 | int lock_status; | 255 | int lock_status; |
256 | 256 | ||
257 | map = mtd->priv; | 257 | map = mtd->priv; |
258 | 258 | ||
259 | /* Pass the whole chip through sector by sector and check for each | 259 | /* Pass the whole chip through sector by sector and check for each |
@@ -273,7 +273,7 @@ static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len, | |||
273 | unlock_sector(map, eraseoffset, is_unlock); | 273 | unlock_sector(map, eraseoffset, is_unlock); |
274 | 274 | ||
275 | lock_status = is_sector_locked(map, eraseoffset); | 275 | lock_status = is_sector_locked(map, eraseoffset); |
276 | 276 | ||
277 | if (is_unlock && lock_status) { | 277 | if (is_unlock && lock_status) { |
278 | printk("Cannot unlock sector at address %x length %xx\n", | 278 | printk("Cannot unlock sector at address %x length %xx\n", |
279 | eraseoffset, merip->erasesize); | 279 | eraseoffset, merip->erasesize); |
@@ -305,7 +305,7 @@ static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
305 | /* | 305 | /* |
306 | * Reads JEDEC manufacturer ID and device ID and returns the index of the first | 306 | * Reads JEDEC manufacturer ID and device ID and returns the index of the first |
307 | * matching table entry (-1 if not found or alias for already found chip). | 307 | * matching table entry (-1 if not found or alias for already found chip). |
308 | */ | 308 | */ |
309 | static int probe_new_chip(struct mtd_info *mtd, __u32 base, | 309 | static int probe_new_chip(struct mtd_info *mtd, __u32 base, |
310 | struct flchip *chips, | 310 | struct flchip *chips, |
311 | struct amd_flash_private *private, | 311 | struct amd_flash_private *private, |
@@ -636,7 +636,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) | |||
636 | { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, | 636 | { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, |
637 | { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } | 637 | { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } |
638 | } | 638 | } |
639 | } | 639 | } |
640 | }; | 640 | }; |
641 | 641 | ||
642 | struct mtd_info *mtd; | 642 | struct mtd_info *mtd; |
@@ -701,7 +701,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) | |||
701 | 701 | ||
702 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * | 702 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * |
703 | mtd->numeraseregions, GFP_KERNEL); | 703 | mtd->numeraseregions, GFP_KERNEL); |
704 | if (!mtd->eraseregions) { | 704 | if (!mtd->eraseregions) { |
705 | printk(KERN_WARNING "%s: Failed to allocate " | 705 | printk(KERN_WARNING "%s: Failed to allocate " |
706 | "memory for MTD erase region info\n", map->name); | 706 | "memory for MTD erase region info\n", map->name); |
707 | kfree(mtd); | 707 | kfree(mtd); |
@@ -739,12 +739,12 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) | |||
739 | mtd->type = MTD_NORFLASH; | 739 | mtd->type = MTD_NORFLASH; |
740 | mtd->flags = MTD_CAP_NORFLASH; | 740 | mtd->flags = MTD_CAP_NORFLASH; |
741 | mtd->name = map->name; | 741 | mtd->name = map->name; |
742 | mtd->erase = amd_flash_erase; | 742 | mtd->erase = amd_flash_erase; |
743 | mtd->read = amd_flash_read; | 743 | mtd->read = amd_flash_read; |
744 | mtd->write = amd_flash_write; | 744 | mtd->write = amd_flash_write; |
745 | mtd->sync = amd_flash_sync; | 745 | mtd->sync = amd_flash_sync; |
746 | mtd->suspend = amd_flash_suspend; | 746 | mtd->suspend = amd_flash_suspend; |
747 | mtd->resume = amd_flash_resume; | 747 | mtd->resume = amd_flash_resume; |
748 | mtd->lock = amd_flash_lock; | 748 | mtd->lock = amd_flash_lock; |
749 | mtd->unlock = amd_flash_unlock; | 749 | mtd->unlock = amd_flash_unlock; |
750 | 750 | ||
@@ -789,7 +789,7 @@ retry: | |||
789 | map->name, chip->state); | 789 | map->name, chip->state); |
790 | set_current_state(TASK_UNINTERRUPTIBLE); | 790 | set_current_state(TASK_UNINTERRUPTIBLE); |
791 | add_wait_queue(&chip->wq, &wait); | 791 | add_wait_queue(&chip->wq, &wait); |
792 | 792 | ||
793 | spin_unlock_bh(chip->mutex); | 793 | spin_unlock_bh(chip->mutex); |
794 | 794 | ||
795 | schedule(); | 795 | schedule(); |
@@ -802,7 +802,7 @@ retry: | |||
802 | timeo = jiffies + HZ; | 802 | timeo = jiffies + HZ; |
803 | 803 | ||
804 | goto retry; | 804 | goto retry; |
805 | } | 805 | } |
806 | 806 | ||
807 | adr += chip->start; | 807 | adr += chip->start; |
808 | 808 | ||
@@ -889,7 +889,7 @@ retry: | |||
889 | map->name, chip->state); | 889 | map->name, chip->state); |
890 | set_current_state(TASK_UNINTERRUPTIBLE); | 890 | set_current_state(TASK_UNINTERRUPTIBLE); |
891 | add_wait_queue(&chip->wq, &wait); | 891 | add_wait_queue(&chip->wq, &wait); |
892 | 892 | ||
893 | spin_unlock_bh(chip->mutex); | 893 | spin_unlock_bh(chip->mutex); |
894 | 894 | ||
895 | schedule(); | 895 | schedule(); |
@@ -901,7 +901,7 @@ retry: | |||
901 | timeo = jiffies + HZ; | 901 | timeo = jiffies + HZ; |
902 | 902 | ||
903 | goto retry; | 903 | goto retry; |
904 | } | 904 | } |
905 | 905 | ||
906 | chip->state = FL_WRITING; | 906 | chip->state = FL_WRITING; |
907 | 907 | ||
@@ -911,7 +911,7 @@ retry: | |||
911 | wide_write(map, datum, adr); | 911 | wide_write(map, datum, adr); |
912 | 912 | ||
913 | times_left = 500000; | 913 | times_left = 500000; |
914 | while (times_left-- && flash_is_busy(map, adr, private->interleave)) { | 914 | while (times_left-- && flash_is_busy(map, adr, private->interleave)) { |
915 | if (need_resched()) { | 915 | if (need_resched()) { |
916 | spin_unlock_bh(chip->mutex); | 916 | spin_unlock_bh(chip->mutex); |
917 | schedule(); | 917 | schedule(); |
@@ -989,7 +989,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, | |||
989 | if (ret) { | 989 | if (ret) { |
990 | return ret; | 990 | return ret; |
991 | } | 991 | } |
992 | 992 | ||
993 | ofs += n; | 993 | ofs += n; |
994 | buf += n; | 994 | buf += n; |
995 | (*retlen) += n; | 995 | (*retlen) += n; |
@@ -1002,7 +1002,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, | |||
1002 | } | 1002 | } |
1003 | } | 1003 | } |
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | /* We are now aligned, write as much as possible. */ | 1006 | /* We are now aligned, write as much as possible. */ |
1007 | while(len >= map->buswidth) { | 1007 | while(len >= map->buswidth) { |
1008 | __u32 datum; | 1008 | __u32 datum; |
@@ -1063,7 +1063,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, | |||
1063 | if (ret) { | 1063 | if (ret) { |
1064 | return ret; | 1064 | return ret; |
1065 | } | 1065 | } |
1066 | 1066 | ||
1067 | (*retlen) += n; | 1067 | (*retlen) += n; |
1068 | } | 1068 | } |
1069 | 1069 | ||
@@ -1085,7 +1085,7 @@ retry: | |||
1085 | if (chip->state != FL_READY){ | 1085 | if (chip->state != FL_READY){ |
1086 | set_current_state(TASK_UNINTERRUPTIBLE); | 1086 | set_current_state(TASK_UNINTERRUPTIBLE); |
1087 | add_wait_queue(&chip->wq, &wait); | 1087 | add_wait_queue(&chip->wq, &wait); |
1088 | 1088 | ||
1089 | spin_unlock_bh(chip->mutex); | 1089 | spin_unlock_bh(chip->mutex); |
1090 | 1090 | ||
1091 | schedule(); | 1091 | schedule(); |
@@ -1098,7 +1098,7 @@ retry: | |||
1098 | timeo = jiffies + HZ; | 1098 | timeo = jiffies + HZ; |
1099 | 1099 | ||
1100 | goto retry; | 1100 | goto retry; |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | chip->state = FL_ERASING; | 1103 | chip->state = FL_ERASING; |
1104 | 1104 | ||
@@ -1106,30 +1106,30 @@ retry: | |||
1106 | ENABLE_VPP(map); | 1106 | ENABLE_VPP(map); |
1107 | send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA); | 1107 | send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA); |
1108 | send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr); | 1108 | send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr); |
1109 | 1109 | ||
1110 | timeo = jiffies + (HZ * 20); | 1110 | timeo = jiffies + (HZ * 20); |
1111 | 1111 | ||
1112 | spin_unlock_bh(chip->mutex); | 1112 | spin_unlock_bh(chip->mutex); |
1113 | msleep(1000); | 1113 | msleep(1000); |
1114 | spin_lock_bh(chip->mutex); | 1114 | spin_lock_bh(chip->mutex); |
1115 | 1115 | ||
1116 | while (flash_is_busy(map, adr, private->interleave)) { | 1116 | while (flash_is_busy(map, adr, private->interleave)) { |
1117 | 1117 | ||
1118 | if (chip->state != FL_ERASING) { | 1118 | if (chip->state != FL_ERASING) { |
1119 | /* Someone's suspended the erase. Sleep */ | 1119 | /* Someone's suspended the erase. Sleep */ |
1120 | set_current_state(TASK_UNINTERRUPTIBLE); | 1120 | set_current_state(TASK_UNINTERRUPTIBLE); |
1121 | add_wait_queue(&chip->wq, &wait); | 1121 | add_wait_queue(&chip->wq, &wait); |
1122 | 1122 | ||
1123 | spin_unlock_bh(chip->mutex); | 1123 | spin_unlock_bh(chip->mutex); |
1124 | printk(KERN_INFO "%s: erase suspended. Sleeping\n", | 1124 | printk(KERN_INFO "%s: erase suspended. Sleeping\n", |
1125 | map->name); | 1125 | map->name); |
1126 | schedule(); | 1126 | schedule(); |
1127 | remove_wait_queue(&chip->wq, &wait); | 1127 | remove_wait_queue(&chip->wq, &wait); |
1128 | 1128 | ||
1129 | if (signal_pending(current)) { | 1129 | if (signal_pending(current)) { |
1130 | return -EINTR; | 1130 | return -EINTR; |
1131 | } | 1131 | } |
1132 | 1132 | ||
1133 | timeo = jiffies + (HZ*2); /* FIXME */ | 1133 | timeo = jiffies + (HZ*2); /* FIXME */ |
1134 | spin_lock_bh(chip->mutex); | 1134 | spin_lock_bh(chip->mutex); |
1135 | continue; | 1135 | continue; |
@@ -1145,7 +1145,7 @@ retry: | |||
1145 | 1145 | ||
1146 | return -EIO; | 1146 | return -EIO; |
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | /* Latency issues. Drop the lock, wait a while and retry */ | 1149 | /* Latency issues. Drop the lock, wait a while and retry */ |
1150 | spin_unlock_bh(chip->mutex); | 1150 | spin_unlock_bh(chip->mutex); |
1151 | 1151 | ||
@@ -1153,7 +1153,7 @@ retry: | |||
1153 | schedule(); | 1153 | schedule(); |
1154 | else | 1154 | else |
1155 | udelay(1); | 1155 | udelay(1); |
1156 | 1156 | ||
1157 | spin_lock_bh(chip->mutex); | 1157 | spin_lock_bh(chip->mutex); |
1158 | } | 1158 | } |
1159 | 1159 | ||
@@ -1180,7 +1180,7 @@ retry: | |||
1180 | return -EIO; | 1180 | return -EIO; |
1181 | } | 1181 | } |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | DISABLE_VPP(map); | 1184 | DISABLE_VPP(map); |
1185 | chip->state = FL_READY; | 1185 | chip->state = FL_READY; |
1186 | wake_up(&chip->wq); | 1186 | wake_up(&chip->wq); |
@@ -1246,7 +1246,7 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1246 | * with the erase region at that address. | 1246 | * with the erase region at that address. |
1247 | */ | 1247 | */ |
1248 | 1248 | ||
1249 | while ((i < mtd->numeraseregions) && | 1249 | while ((i < mtd->numeraseregions) && |
1250 | ((instr->addr + instr->len) >= regions[i].offset)) { | 1250 | ((instr->addr + instr->len) >= regions[i].offset)) { |
1251 | i++; | 1251 | i++; |
1252 | } | 1252 | } |
@@ -1293,10 +1293,10 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1293 | } | 1293 | } |
1294 | } | 1294 | } |
1295 | } | 1295 | } |
1296 | 1296 | ||
1297 | instr->state = MTD_ERASE_DONE; | 1297 | instr->state = MTD_ERASE_DONE; |
1298 | mtd_erase_callback(instr); | 1298 | mtd_erase_callback(instr); |
1299 | 1299 | ||
1300 | return 0; | 1300 | return 0; |
1301 | } | 1301 | } |
1302 | 1302 | ||
@@ -1324,7 +1324,7 @@ static void amd_flash_sync(struct mtd_info *mtd) | |||
1324 | case FL_JEDEC_QUERY: | 1324 | case FL_JEDEC_QUERY: |
1325 | chip->oldstate = chip->state; | 1325 | chip->oldstate = chip->state; |
1326 | chip->state = FL_SYNCING; | 1326 | chip->state = FL_SYNCING; |
1327 | /* No need to wake_up() on this state change - | 1327 | /* No need to wake_up() on this state change - |
1328 | * as the whole point is that nobody can do anything | 1328 | * as the whole point is that nobody can do anything |
1329 | * with the chip now anyway. | 1329 | * with the chip now anyway. |
1330 | */ | 1330 | */ |
@@ -1335,13 +1335,13 @@ static void amd_flash_sync(struct mtd_info *mtd) | |||
1335 | default: | 1335 | default: |
1336 | /* Not an idle state */ | 1336 | /* Not an idle state */ |
1337 | add_wait_queue(&chip->wq, &wait); | 1337 | add_wait_queue(&chip->wq, &wait); |
1338 | 1338 | ||
1339 | spin_unlock_bh(chip->mutex); | 1339 | spin_unlock_bh(chip->mutex); |
1340 | 1340 | ||
1341 | schedule(); | 1341 | schedule(); |
1342 | 1342 | ||
1343 | remove_wait_queue(&chip->wq, &wait); | 1343 | remove_wait_queue(&chip->wq, &wait); |
1344 | 1344 | ||
1345 | goto retry; | 1345 | goto retry; |
1346 | } | 1346 | } |
1347 | } | 1347 | } |
@@ -1351,7 +1351,7 @@ static void amd_flash_sync(struct mtd_info *mtd) | |||
1351 | chip = &private->chips[i]; | 1351 | chip = &private->chips[i]; |
1352 | 1352 | ||
1353 | spin_lock_bh(chip->mutex); | 1353 | spin_lock_bh(chip->mutex); |
1354 | 1354 | ||
1355 | if (chip->state == FL_SYNCING) { | 1355 | if (chip->state == FL_SYNCING) { |
1356 | chip->state = chip->oldstate; | 1356 | chip->state = chip->oldstate; |
1357 | wake_up(&chip->wq); | 1357 | wake_up(&chip->wq); |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c3fc9b2f21fb..143f01a4c170 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -4,9 +4,9 @@ | |||
4 | * | 4 | * |
5 | * (C) 2000 Red Hat. GPL'd | 5 | * (C) 2000 Red Hat. GPL'd |
6 | * | 6 | * |
7 | * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $ | 7 | * $Id: cfi_cmdset_0001.c,v 1.185 2005/11/07 11:14:22 gleixner Exp $ |
8 | * | ||
8 | * | 9 | * |
9 | * | ||
10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> | 10 | * 10/10/2000 Nicolas Pitre <nico@cam.org> |
11 | * - completely revamped method functions so they are aware and | 11 | * - completely revamped method functions so they are aware and |
12 | * independent of the flash geometry (buswidth, interleave, etc.) | 12 | * independent of the flash geometry (buswidth, interleave, etc.) |
@@ -51,6 +51,7 @@ | |||
51 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 51 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
52 | static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 52 | static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
53 | static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 53 | static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
54 | static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *); | ||
54 | static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); | 55 | static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); |
55 | static void cfi_intelext_sync (struct mtd_info *); | 56 | static void cfi_intelext_sync (struct mtd_info *); |
56 | static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); | 57 | static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); |
@@ -105,6 +106,7 @@ static struct mtd_chip_driver cfi_intelext_chipdrv = { | |||
105 | static void cfi_tell_features(struct cfi_pri_intelext *extp) | 106 | static void cfi_tell_features(struct cfi_pri_intelext *extp) |
106 | { | 107 | { |
107 | int i; | 108 | int i; |
109 | printk(" Extended Query version %c.%c\n", extp->MajorVersion, extp->MinorVersion); | ||
108 | printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); | 110 | printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); |
109 | printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); | 111 | printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); |
110 | printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); | 112 | printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); |
@@ -116,36 +118,43 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
116 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); | 118 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); |
117 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); | 119 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); |
118 | printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported"); | 120 | printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported"); |
119 | for (i=10; i<32; i++) { | 121 | printk(" - Extended Flash Array: %s\n", extp->FeatureSupport&1024?"supported":"unsupported"); |
120 | if (extp->FeatureSupport & (1<<i)) | 122 | for (i=11; i<32; i++) { |
123 | if (extp->FeatureSupport & (1<<i)) | ||
121 | printk(" - Unknown Bit %X: supported\n", i); | 124 | printk(" - Unknown Bit %X: supported\n", i); |
122 | } | 125 | } |
123 | 126 | ||
124 | printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); | 127 | printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); |
125 | printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); | 128 | printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); |
126 | for (i=1; i<8; i++) { | 129 | for (i=1; i<8; i++) { |
127 | if (extp->SuspendCmdSupport & (1<<i)) | 130 | if (extp->SuspendCmdSupport & (1<<i)) |
128 | printk(" - Unknown Bit %X: supported\n", i); | 131 | printk(" - Unknown Bit %X: supported\n", i); |
129 | } | 132 | } |
130 | 133 | ||
131 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); | 134 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); |
132 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); | 135 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); |
133 | printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); | 136 | printk(" - Lock-Down Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); |
134 | for (i=2; i<16; i++) { | 137 | for (i=2; i<3; i++) { |
135 | if (extp->BlkStatusRegMask & (1<<i)) | 138 | if (extp->BlkStatusRegMask & (1<<i)) |
136 | printk(" - Unknown Bit %X Active: yes\n",i); | 139 | printk(" - Unknown Bit %X Active: yes\n",i); |
137 | } | 140 | } |
138 | 141 | printk(" - EFA Lock Bit: %s\n", extp->BlkStatusRegMask&16?"yes":"no"); | |
139 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", | 142 | printk(" - EFA Lock-Down Bit: %s\n", extp->BlkStatusRegMask&32?"yes":"no"); |
143 | for (i=6; i<16; i++) { | ||
144 | if (extp->BlkStatusRegMask & (1<<i)) | ||
145 | printk(" - Unknown Bit %X Active: yes\n",i); | ||
146 | } | ||
147 | |||
148 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", | ||
140 | extp->VccOptimal >> 4, extp->VccOptimal & 0xf); | 149 | extp->VccOptimal >> 4, extp->VccOptimal & 0xf); |
141 | if (extp->VppOptimal) | 150 | if (extp->VppOptimal) |
142 | printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", | 151 | printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", |
143 | extp->VppOptimal >> 4, extp->VppOptimal & 0xf); | 152 | extp->VppOptimal >> 4, extp->VppOptimal & 0xf); |
144 | } | 153 | } |
145 | #endif | 154 | #endif |
146 | 155 | ||
147 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 156 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
148 | /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ | 157 | /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ |
149 | static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) | 158 | static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) |
150 | { | 159 | { |
151 | struct map_info *map = mtd->priv; | 160 | struct map_info *map = mtd->priv; |
@@ -176,7 +185,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) | |||
176 | { | 185 | { |
177 | struct map_info *map = mtd->priv; | 186 | struct map_info *map = mtd->priv; |
178 | struct cfi_private *cfi = map->fldrv_priv; | 187 | struct cfi_private *cfi = map->fldrv_priv; |
179 | 188 | ||
180 | cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */ | 189 | cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */ |
181 | cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ | 190 | cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ |
182 | } | 191 | } |
@@ -185,7 +194,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) | |||
185 | { | 194 | { |
186 | struct map_info *map = mtd->priv; | 195 | struct map_info *map = mtd->priv; |
187 | struct cfi_private *cfi = map->fldrv_priv; | 196 | struct cfi_private *cfi = map->fldrv_priv; |
188 | 197 | ||
189 | /* Note this is done after the region info is endian swapped */ | 198 | /* Note this is done after the region info is endian swapped */ |
190 | cfi->cfiq->EraseRegionInfo[1] = | 199 | cfi->cfiq->EraseRegionInfo[1] = |
191 | (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; | 200 | (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; |
@@ -207,12 +216,13 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | |||
207 | if (cfi->cfiq->BufWriteTimeoutTyp) { | 216 | if (cfi->cfiq->BufWriteTimeoutTyp) { |
208 | printk(KERN_INFO "Using buffer write method\n" ); | 217 | printk(KERN_INFO "Using buffer write method\n" ); |
209 | mtd->write = cfi_intelext_write_buffers; | 218 | mtd->write = cfi_intelext_write_buffers; |
219 | mtd->writev = cfi_intelext_writev; | ||
210 | } | 220 | } |
211 | } | 221 | } |
212 | 222 | ||
213 | static struct cfi_fixup cfi_fixup_table[] = { | 223 | static struct cfi_fixup cfi_fixup_table[] = { |
214 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 224 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
215 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, | 225 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, |
216 | #endif | 226 | #endif |
217 | #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND | 227 | #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND |
218 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, | 228 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, |
@@ -252,12 +262,21 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
252 | if (!extp) | 262 | if (!extp) |
253 | return NULL; | 263 | return NULL; |
254 | 264 | ||
265 | if (extp->MajorVersion != '1' || | ||
266 | (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { | ||
267 | printk(KERN_ERR " Unknown Intel/Sharp Extended Query " | ||
268 | "version %c.%c.\n", extp->MajorVersion, | ||
269 | extp->MinorVersion); | ||
270 | kfree(extp); | ||
271 | return NULL; | ||
272 | } | ||
273 | |||
255 | /* Do some byteswapping if necessary */ | 274 | /* Do some byteswapping if necessary */ |
256 | extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); | 275 | extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); |
257 | extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); | 276 | extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); |
258 | extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); | 277 | extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); |
259 | 278 | ||
260 | if (extp->MajorVersion == '1' && extp->MinorVersion == '3') { | 279 | if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') { |
261 | unsigned int extra_size = 0; | 280 | unsigned int extra_size = 0; |
262 | int nb_parts, i; | 281 | int nb_parts, i; |
263 | 282 | ||
@@ -266,7 +285,10 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
266 | sizeof(struct cfi_intelext_otpinfo); | 285 | sizeof(struct cfi_intelext_otpinfo); |
267 | 286 | ||
268 | /* Burst Read info */ | 287 | /* Burst Read info */ |
269 | extra_size += 6; | 288 | extra_size += 2; |
289 | if (extp_size < sizeof(*extp) + extra_size) | ||
290 | goto need_more; | ||
291 | extra_size += extp->extra[extra_size-1]; | ||
270 | 292 | ||
271 | /* Number of hardware-partitions */ | 293 | /* Number of hardware-partitions */ |
272 | extra_size += 1; | 294 | extra_size += 1; |
@@ -274,6 +296,10 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
274 | goto need_more; | 296 | goto need_more; |
275 | nb_parts = extp->extra[extra_size - 1]; | 297 | nb_parts = extp->extra[extra_size - 1]; |
276 | 298 | ||
299 | /* skip the sizeof(partregion) field in CFI 1.4 */ | ||
300 | if (extp->MinorVersion >= '4') | ||
301 | extra_size += 2; | ||
302 | |||
277 | for (i = 0; i < nb_parts; i++) { | 303 | for (i = 0; i < nb_parts; i++) { |
278 | struct cfi_intelext_regioninfo *rinfo; | 304 | struct cfi_intelext_regioninfo *rinfo; |
279 | rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size]; | 305 | rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size]; |
@@ -285,6 +311,9 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
285 | * sizeof(struct cfi_intelext_blockinfo); | 311 | * sizeof(struct cfi_intelext_blockinfo); |
286 | } | 312 | } |
287 | 313 | ||
314 | if (extp->MinorVersion >= '4') | ||
315 | extra_size += sizeof(struct cfi_intelext_programming_regioninfo); | ||
316 | |||
288 | if (extp_size < sizeof(*extp) + extra_size) { | 317 | if (extp_size < sizeof(*extp) + extra_size) { |
289 | need_more: | 318 | need_more: |
290 | extp_size = sizeof(*extp) + extra_size; | 319 | extp_size = sizeof(*extp) + extra_size; |
@@ -298,7 +327,7 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
298 | goto again; | 327 | goto again; |
299 | } | 328 | } |
300 | } | 329 | } |
301 | 330 | ||
302 | return extp; | 331 | return extp; |
303 | } | 332 | } |
304 | 333 | ||
@@ -339,7 +368,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
339 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; | 368 | mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; |
340 | 369 | ||
341 | if (cfi->cfi_mode == CFI_MODE_CFI) { | 370 | if (cfi->cfi_mode == CFI_MODE_CFI) { |
342 | /* | 371 | /* |
343 | * It's a real CFI chip, not one for which the probe | 372 | * It's a real CFI chip, not one for which the probe |
344 | * routine faked a CFI structure. So we read the feature | 373 | * routine faked a CFI structure. So we read the feature |
345 | * table from it. | 374 | * table from it. |
@@ -354,14 +383,14 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
354 | } | 383 | } |
355 | 384 | ||
356 | /* Install our own private info structure */ | 385 | /* Install our own private info structure */ |
357 | cfi->cmdset_priv = extp; | 386 | cfi->cmdset_priv = extp; |
358 | 387 | ||
359 | cfi_fixup(mtd, cfi_fixup_table); | 388 | cfi_fixup(mtd, cfi_fixup_table); |
360 | 389 | ||
361 | #ifdef DEBUG_CFI_FEATURES | 390 | #ifdef DEBUG_CFI_FEATURES |
362 | /* Tell the user about it in lots of lovely detail */ | 391 | /* Tell the user about it in lots of lovely detail */ |
363 | cfi_tell_features(extp); | 392 | cfi_tell_features(extp); |
364 | #endif | 393 | #endif |
365 | 394 | ||
366 | if(extp->SuspendCmdSupport & 1) { | 395 | if(extp->SuspendCmdSupport & 1) { |
367 | printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); | 396 | printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); |
@@ -379,10 +408,10 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
379 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; | 408 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; |
380 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; | 409 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; |
381 | cfi->chips[i].ref_point_counter = 0; | 410 | cfi->chips[i].ref_point_counter = 0; |
382 | } | 411 | } |
383 | 412 | ||
384 | map->fldrv = &cfi_intelext_chipdrv; | 413 | map->fldrv = &cfi_intelext_chipdrv; |
385 | 414 | ||
386 | return cfi_intelext_setup(mtd); | 415 | return cfi_intelext_setup(mtd); |
387 | } | 416 | } |
388 | 417 | ||
@@ -399,13 +428,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) | |||
399 | mtd->size = devsize * cfi->numchips; | 428 | mtd->size = devsize * cfi->numchips; |
400 | 429 | ||
401 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; | 430 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; |
402 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) | 431 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) |
403 | * mtd->numeraseregions, GFP_KERNEL); | 432 | * mtd->numeraseregions, GFP_KERNEL); |
404 | if (!mtd->eraseregions) { | 433 | if (!mtd->eraseregions) { |
405 | printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); | 434 | printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); |
406 | goto setup_err; | 435 | goto setup_err; |
407 | } | 436 | } |
408 | 437 | ||
409 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { | 438 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { |
410 | unsigned long ernum, ersize; | 439 | unsigned long ernum, ersize; |
411 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; | 440 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; |
@@ -429,7 +458,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) | |||
429 | } | 458 | } |
430 | 459 | ||
431 | for (i=0; i<mtd->numeraseregions;i++){ | 460 | for (i=0; i<mtd->numeraseregions;i++){ |
432 | printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", | 461 | printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n", |
433 | i,mtd->eraseregions[i].offset, | 462 | i,mtd->eraseregions[i].offset, |
434 | mtd->eraseregions[i].erasesize, | 463 | mtd->eraseregions[i].erasesize, |
435 | mtd->eraseregions[i].numblocks); | 464 | mtd->eraseregions[i].numblocks); |
@@ -480,7 +509,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
480 | * arrangement at this point. This can be rearranged in the future | 509 | * arrangement at this point. This can be rearranged in the future |
481 | * if someone feels motivated enough. --nico | 510 | * if someone feels motivated enough. --nico |
482 | */ | 511 | */ |
483 | if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3' | 512 | if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3' |
484 | && extp->FeatureSupport & (1 << 9)) { | 513 | && extp->FeatureSupport & (1 << 9)) { |
485 | struct cfi_private *newcfi; | 514 | struct cfi_private *newcfi; |
486 | struct flchip *chip; | 515 | struct flchip *chip; |
@@ -492,12 +521,16 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
492 | sizeof(struct cfi_intelext_otpinfo); | 521 | sizeof(struct cfi_intelext_otpinfo); |
493 | 522 | ||
494 | /* Burst Read info */ | 523 | /* Burst Read info */ |
495 | offs += 6; | 524 | offs += extp->extra[offs+1]+2; |
496 | 525 | ||
497 | /* Number of partition regions */ | 526 | /* Number of partition regions */ |
498 | numregions = extp->extra[offs]; | 527 | numregions = extp->extra[offs]; |
499 | offs += 1; | 528 | offs += 1; |
500 | 529 | ||
530 | /* skip the sizeof(partregion) field in CFI 1.4 */ | ||
531 | if (extp->MinorVersion >= '4') | ||
532 | offs += 2; | ||
533 | |||
501 | /* Number of hardware partitions */ | 534 | /* Number of hardware partitions */ |
502 | numparts = 0; | 535 | numparts = 0; |
503 | for (i = 0; i < numregions; i++) { | 536 | for (i = 0; i < numregions; i++) { |
@@ -509,6 +542,20 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
509 | sizeof(struct cfi_intelext_blockinfo); | 542 | sizeof(struct cfi_intelext_blockinfo); |
510 | } | 543 | } |
511 | 544 | ||
545 | /* Programming Region info */ | ||
546 | if (extp->MinorVersion >= '4') { | ||
547 | struct cfi_intelext_programming_regioninfo *prinfo; | ||
548 | prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs]; | ||
549 | MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift; | ||
550 | MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid; | ||
551 | MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid; | ||
552 | mtd->flags |= MTD_PROGRAM_REGIONS; | ||
553 | printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n", | ||
554 | map->name, MTD_PROGREGION_SIZE(mtd), | ||
555 | MTD_PROGREGION_CTRLMODE_VALID(mtd), | ||
556 | MTD_PROGREGION_CTRLMODE_INVALID(mtd)); | ||
557 | } | ||
558 | |||
512 | /* | 559 | /* |
513 | * All functions below currently rely on all chips having | 560 | * All functions below currently rely on all chips having |
514 | * the same geometry so we'll just assume that all hardware | 561 | * the same geometry so we'll just assume that all hardware |
@@ -653,8 +700,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
653 | break; | 700 | break; |
654 | 701 | ||
655 | if (time_after(jiffies, timeo)) { | 702 | if (time_after(jiffies, timeo)) { |
656 | printk(KERN_ERR "Waiting for chip to be ready timed out. Status %lx\n", | 703 | printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n", |
657 | status.x[0]); | 704 | map->name, status.x[0]); |
658 | return -EIO; | 705 | return -EIO; |
659 | } | 706 | } |
660 | spin_unlock(chip->mutex); | 707 | spin_unlock(chip->mutex); |
@@ -663,7 +710,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
663 | /* Someone else might have been playing with it. */ | 710 | /* Someone else might have been playing with it. */ |
664 | goto retry; | 711 | goto retry; |
665 | } | 712 | } |
666 | 713 | ||
667 | case FL_READY: | 714 | case FL_READY: |
668 | case FL_CFI_QUERY: | 715 | case FL_CFI_QUERY: |
669 | case FL_JEDEC_QUERY: | 716 | case FL_JEDEC_QUERY: |
@@ -701,8 +748,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
701 | map_write(map, CMD(0x70), adr); | 748 | map_write(map, CMD(0x70), adr); |
702 | chip->state = FL_ERASING; | 749 | chip->state = FL_ERASING; |
703 | chip->oldstate = FL_READY; | 750 | chip->oldstate = FL_READY; |
704 | printk(KERN_ERR "Chip not ready after erase " | 751 | printk(KERN_ERR "%s: Chip not ready after erase " |
705 | "suspended: status = 0x%lx\n", status.x[0]); | 752 | "suspended: status = 0x%lx\n", map->name, status.x[0]); |
706 | return -EIO; | 753 | return -EIO; |
707 | } | 754 | } |
708 | 755 | ||
@@ -782,14 +829,14 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad | |||
782 | switch(chip->oldstate) { | 829 | switch(chip->oldstate) { |
783 | case FL_ERASING: | 830 | case FL_ERASING: |
784 | chip->state = chip->oldstate; | 831 | chip->state = chip->oldstate; |
785 | /* What if one interleaved chip has finished and the | 832 | /* What if one interleaved chip has finished and the |
786 | other hasn't? The old code would leave the finished | 833 | other hasn't? The old code would leave the finished |
787 | one in READY mode. That's bad, and caused -EROFS | 834 | one in READY mode. That's bad, and caused -EROFS |
788 | errors to be returned from do_erase_oneblock because | 835 | errors to be returned from do_erase_oneblock because |
789 | that's the only bit it checked for at the time. | 836 | that's the only bit it checked for at the time. |
790 | As the state machine appears to explicitly allow | 837 | As the state machine appears to explicitly allow |
791 | sending the 0x70 (Read Status) command to an erasing | 838 | sending the 0x70 (Read Status) command to an erasing |
792 | chip and expecting it to be ignored, that's what we | 839 | chip and expecting it to be ignored, that's what we |
793 | do. */ | 840 | do. */ |
794 | map_write(map, CMD(0xd0), adr); | 841 | map_write(map, CMD(0xd0), adr); |
795 | map_write(map, CMD(0x70), adr); | 842 | map_write(map, CMD(0x70), adr); |
@@ -809,7 +856,7 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad | |||
809 | DISABLE_VPP(map); | 856 | DISABLE_VPP(map); |
810 | break; | 857 | break; |
811 | default: | 858 | default: |
812 | printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate); | 859 | printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate); |
813 | } | 860 | } |
814 | wake_up(&chip->wq); | 861 | wake_up(&chip->wq); |
815 | } | 862 | } |
@@ -1025,8 +1072,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a | |||
1025 | 1072 | ||
1026 | adr += chip->start; | 1073 | adr += chip->start; |
1027 | 1074 | ||
1028 | /* Ensure cmd read/writes are aligned. */ | 1075 | /* Ensure cmd read/writes are aligned. */ |
1029 | cmd_addr = adr & ~(map_bankwidth(map)-1); | 1076 | cmd_addr = adr & ~(map_bankwidth(map)-1); |
1030 | 1077 | ||
1031 | spin_lock(chip->mutex); | 1078 | spin_lock(chip->mutex); |
1032 | 1079 | ||
@@ -1054,7 +1101,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si | |||
1054 | 1101 | ||
1055 | if (!map->virt || (from + len > mtd->size)) | 1102 | if (!map->virt || (from + len > mtd->size)) |
1056 | return -EINVAL; | 1103 | return -EINVAL; |
1057 | 1104 | ||
1058 | *mtdbuf = (void *)map->virt + from; | 1105 | *mtdbuf = (void *)map->virt + from; |
1059 | *retlen = 0; | 1106 | *retlen = 0; |
1060 | 1107 | ||
@@ -1081,7 +1128,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si | |||
1081 | 1128 | ||
1082 | *retlen += thislen; | 1129 | *retlen += thislen; |
1083 | len -= thislen; | 1130 | len -= thislen; |
1084 | 1131 | ||
1085 | ofs = 0; | 1132 | ofs = 0; |
1086 | chipnum++; | 1133 | chipnum++; |
1087 | } | 1134 | } |
@@ -1120,7 +1167,7 @@ static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t fro | |||
1120 | if(chip->ref_point_counter == 0) | 1167 | if(chip->ref_point_counter == 0) |
1121 | chip->state = FL_READY; | 1168 | chip->state = FL_READY; |
1122 | } else | 1169 | } else |
1123 | printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ | 1170 | printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */ |
1124 | 1171 | ||
1125 | put_chip(map, chip, chip->start); | 1172 | put_chip(map, chip, chip->start); |
1126 | spin_unlock(chip->mutex); | 1173 | spin_unlock(chip->mutex); |
@@ -1139,8 +1186,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
1139 | 1186 | ||
1140 | adr += chip->start; | 1187 | adr += chip->start; |
1141 | 1188 | ||
1142 | /* Ensure cmd read/writes are aligned. */ | 1189 | /* Ensure cmd read/writes are aligned. */ |
1143 | cmd_addr = adr & ~(map_bankwidth(map)-1); | 1190 | cmd_addr = adr & ~(map_bankwidth(map)-1); |
1144 | 1191 | ||
1145 | spin_lock(chip->mutex); | 1192 | spin_lock(chip->mutex); |
1146 | ret = get_chip(map, chip, cmd_addr, FL_READY); | 1193 | ret = get_chip(map, chip, cmd_addr, FL_READY); |
@@ -1195,7 +1242,7 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz | |||
1195 | *retlen += thislen; | 1242 | *retlen += thislen; |
1196 | len -= thislen; | 1243 | len -= thislen; |
1197 | buf += thislen; | 1244 | buf += thislen; |
1198 | 1245 | ||
1199 | ofs = 0; | 1246 | ofs = 0; |
1200 | chipnum++; | 1247 | chipnum++; |
1201 | } | 1248 | } |
@@ -1212,12 +1259,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1212 | 1259 | ||
1213 | adr += chip->start; | 1260 | adr += chip->start; |
1214 | 1261 | ||
1215 | /* Let's determine this according to the interleave only once */ | 1262 | /* Let's determine those according to the interleave only once */ |
1216 | status_OK = CMD(0x80); | 1263 | status_OK = CMD(0x80); |
1217 | switch (mode) { | 1264 | switch (mode) { |
1218 | case FL_WRITING: write_cmd = CMD(0x40); break; | 1265 | case FL_WRITING: |
1219 | case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; | 1266 | write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); |
1220 | default: return -EINVAL; | 1267 | break; |
1268 | case FL_OTP_WRITE: | ||
1269 | write_cmd = CMD(0xc0); | ||
1270 | break; | ||
1271 | default: | ||
1272 | return -EINVAL; | ||
1221 | } | 1273 | } |
1222 | 1274 | ||
1223 | spin_lock(chip->mutex); | 1275 | spin_lock(chip->mutex); |
@@ -1258,12 +1310,13 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1258 | status = map_read(map, adr); | 1310 | status = map_read(map, adr); |
1259 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1311 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1260 | break; | 1312 | break; |
1261 | 1313 | ||
1262 | /* OK Still waiting */ | 1314 | /* OK Still waiting */ |
1263 | if (time_after(jiffies, timeo)) { | 1315 | if (time_after(jiffies, timeo)) { |
1316 | map_write(map, CMD(0x70), adr); | ||
1264 | chip->state = FL_STATUS; | 1317 | chip->state = FL_STATUS; |
1265 | xip_enable(map, chip, adr); | 1318 | xip_enable(map, chip, adr); |
1266 | printk(KERN_ERR "waiting for chip to be ready timed out in word write\n"); | 1319 | printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); |
1267 | ret = -EIO; | 1320 | ret = -EIO; |
1268 | goto out; | 1321 | goto out; |
1269 | } | 1322 | } |
@@ -1275,27 +1328,39 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1275 | if (!z) { | 1328 | if (!z) { |
1276 | chip->word_write_time--; | 1329 | chip->word_write_time--; |
1277 | if (!chip->word_write_time) | 1330 | if (!chip->word_write_time) |
1278 | chip->word_write_time++; | 1331 | chip->word_write_time = 1; |
1279 | } | 1332 | } |
1280 | if (z > 1) | 1333 | if (z > 1) |
1281 | chip->word_write_time++; | 1334 | chip->word_write_time++; |
1282 | 1335 | ||
1283 | /* Done and happy. */ | 1336 | /* Done and happy. */ |
1284 | chip->state = FL_STATUS; | 1337 | chip->state = FL_STATUS; |
1285 | 1338 | ||
1286 | /* check for lock bit */ | 1339 | /* check for errors */ |
1287 | if (map_word_bitsset(map, status, CMD(0x02))) { | 1340 | if (map_word_bitsset(map, status, CMD(0x1a))) { |
1288 | /* clear status */ | 1341 | unsigned long chipstatus = MERGESTATUS(status); |
1342 | |||
1343 | /* reset status */ | ||
1289 | map_write(map, CMD(0x50), adr); | 1344 | map_write(map, CMD(0x50), adr); |
1290 | /* put back into read status register mode */ | ||
1291 | map_write(map, CMD(0x70), adr); | 1345 | map_write(map, CMD(0x70), adr); |
1292 | ret = -EROFS; | 1346 | xip_enable(map, chip, adr); |
1347 | |||
1348 | if (chipstatus & 0x02) { | ||
1349 | ret = -EROFS; | ||
1350 | } else if (chipstatus & 0x08) { | ||
1351 | printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name); | ||
1352 | ret = -EIO; | ||
1353 | } else { | ||
1354 | printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus); | ||
1355 | ret = -EINVAL; | ||
1356 | } | ||
1357 | |||
1358 | goto out; | ||
1293 | } | 1359 | } |
1294 | 1360 | ||
1295 | xip_enable(map, chip, adr); | 1361 | xip_enable(map, chip, adr); |
1296 | out: put_chip(map, chip, adr); | 1362 | out: put_chip(map, chip, adr); |
1297 | spin_unlock(chip->mutex); | 1363 | spin_unlock(chip->mutex); |
1298 | |||
1299 | return ret; | 1364 | return ret; |
1300 | } | 1365 | } |
1301 | 1366 | ||
@@ -1328,7 +1393,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1328 | 1393 | ||
1329 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1394 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1330 | bus_ofs, datum, FL_WRITING); | 1395 | bus_ofs, datum, FL_WRITING); |
1331 | if (ret) | 1396 | if (ret) |
1332 | return ret; | 1397 | return ret; |
1333 | 1398 | ||
1334 | len -= n; | 1399 | len -= n; |
@@ -1337,13 +1402,13 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1337 | (*retlen) += n; | 1402 | (*retlen) += n; |
1338 | 1403 | ||
1339 | if (ofs >> cfi->chipshift) { | 1404 | if (ofs >> cfi->chipshift) { |
1340 | chipnum ++; | 1405 | chipnum ++; |
1341 | ofs = 0; | 1406 | ofs = 0; |
1342 | if (chipnum == cfi->numchips) | 1407 | if (chipnum == cfi->numchips) |
1343 | return 0; | 1408 | return 0; |
1344 | } | 1409 | } |
1345 | } | 1410 | } |
1346 | 1411 | ||
1347 | while(len >= map_bankwidth(map)) { | 1412 | while(len >= map_bankwidth(map)) { |
1348 | map_word datum = map_word_load(map, buf); | 1413 | map_word datum = map_word_load(map, buf); |
1349 | 1414 | ||
@@ -1358,7 +1423,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1358 | len -= map_bankwidth(map); | 1423 | len -= map_bankwidth(map); |
1359 | 1424 | ||
1360 | if (ofs >> cfi->chipshift) { | 1425 | if (ofs >> cfi->chipshift) { |
1361 | chipnum ++; | 1426 | chipnum ++; |
1362 | ofs = 0; | 1427 | ofs = 0; |
1363 | if (chipnum == cfi->numchips) | 1428 | if (chipnum == cfi->numchips) |
1364 | return 0; | 1429 | return 0; |
@@ -1373,9 +1438,9 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1373 | 1438 | ||
1374 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1439 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1375 | ofs, datum, FL_WRITING); | 1440 | ofs, datum, FL_WRITING); |
1376 | if (ret) | 1441 | if (ret) |
1377 | return ret; | 1442 | return ret; |
1378 | 1443 | ||
1379 | (*retlen) += len; | 1444 | (*retlen) += len; |
1380 | } | 1445 | } |
1381 | 1446 | ||
@@ -1383,20 +1448,24 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le | |||
1383 | } | 1448 | } |
1384 | 1449 | ||
1385 | 1450 | ||
1386 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | 1451 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, |
1387 | unsigned long adr, const u_char *buf, int len) | 1452 | unsigned long adr, const struct kvec **pvec, |
1453 | unsigned long *pvec_seek, int len) | ||
1388 | { | 1454 | { |
1389 | struct cfi_private *cfi = map->fldrv_priv; | 1455 | struct cfi_private *cfi = map->fldrv_priv; |
1390 | map_word status, status_OK; | 1456 | map_word status, status_OK, write_cmd, datum; |
1391 | unsigned long cmd_adr, timeo; | 1457 | unsigned long cmd_adr, timeo; |
1392 | int wbufsize, z, ret=0, bytes, words; | 1458 | int wbufsize, z, ret=0, word_gap, words; |
1459 | const struct kvec *vec; | ||
1460 | unsigned long vec_seek; | ||
1393 | 1461 | ||
1394 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; | 1462 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
1395 | adr += chip->start; | 1463 | adr += chip->start; |
1396 | cmd_adr = adr & ~(wbufsize-1); | 1464 | cmd_adr = adr & ~(wbufsize-1); |
1397 | 1465 | ||
1398 | /* Let's determine this according to the interleave only once */ | 1466 | /* Let's determine this according to the interleave only once */ |
1399 | status_OK = CMD(0x80); | 1467 | status_OK = CMD(0x80); |
1468 | write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); | ||
1400 | 1469 | ||
1401 | spin_lock(chip->mutex); | 1470 | spin_lock(chip->mutex); |
1402 | ret = get_chip(map, chip, cmd_adr, FL_WRITING); | 1471 | ret = get_chip(map, chip, cmd_adr, FL_WRITING); |
@@ -1410,7 +1479,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1410 | xip_disable(map, chip, cmd_adr); | 1479 | xip_disable(map, chip, cmd_adr); |
1411 | 1480 | ||
1412 | /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set | 1481 | /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set |
1413 | [...], the device will not accept any more Write to Buffer commands". | 1482 | [...], the device will not accept any more Write to Buffer commands". |
1414 | So we must check here and reset those bits if they're set. Otherwise | 1483 | So we must check here and reset those bits if they're set. Otherwise |
1415 | we're just pissing in the wind */ | 1484 | we're just pissing in the wind */ |
1416 | if (chip->state != FL_STATUS) | 1485 | if (chip->state != FL_STATUS) |
@@ -1428,7 +1497,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1428 | 1497 | ||
1429 | z = 0; | 1498 | z = 0; |
1430 | for (;;) { | 1499 | for (;;) { |
1431 | map_write(map, CMD(0xe8), cmd_adr); | 1500 | map_write(map, write_cmd, cmd_adr); |
1432 | 1501 | ||
1433 | status = map_read(map, cmd_adr); | 1502 | status = map_read(map, cmd_adr); |
1434 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1503 | if (map_word_andequal(map, status, status_OK, status_OK)) |
@@ -1446,41 +1515,66 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1446 | map_write(map, CMD(0x50), cmd_adr); | 1515 | map_write(map, CMD(0x50), cmd_adr); |
1447 | map_write(map, CMD(0x70), cmd_adr); | 1516 | map_write(map, CMD(0x70), cmd_adr); |
1448 | xip_enable(map, chip, cmd_adr); | 1517 | xip_enable(map, chip, cmd_adr); |
1449 | printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", | 1518 | printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", |
1450 | status.x[0], Xstatus.x[0]); | 1519 | map->name, status.x[0], Xstatus.x[0]); |
1451 | ret = -EIO; | 1520 | ret = -EIO; |
1452 | goto out; | 1521 | goto out; |
1453 | } | 1522 | } |
1454 | } | 1523 | } |
1455 | 1524 | ||
1525 | /* Figure out the number of words to write */ | ||
1526 | word_gap = (-adr & (map_bankwidth(map)-1)); | ||
1527 | words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); | ||
1528 | if (!word_gap) { | ||
1529 | words--; | ||
1530 | } else { | ||
1531 | word_gap = map_bankwidth(map) - word_gap; | ||
1532 | adr -= word_gap; | ||
1533 | datum = map_word_ff(map); | ||
1534 | } | ||
1535 | |||
1456 | /* Write length of data to come */ | 1536 | /* Write length of data to come */ |
1457 | bytes = len & (map_bankwidth(map)-1); | 1537 | map_write(map, CMD(words), cmd_adr ); |
1458 | words = len / map_bankwidth(map); | ||
1459 | map_write(map, CMD(words - !bytes), cmd_adr ); | ||
1460 | 1538 | ||
1461 | /* Write data */ | 1539 | /* Write data */ |
1462 | z = 0; | 1540 | vec = *pvec; |
1463 | while(z < words * map_bankwidth(map)) { | 1541 | vec_seek = *pvec_seek; |
1464 | map_word datum = map_word_load(map, buf); | 1542 | do { |
1465 | map_write(map, datum, adr+z); | 1543 | int n = map_bankwidth(map) - word_gap; |
1544 | if (n > vec->iov_len - vec_seek) | ||
1545 | n = vec->iov_len - vec_seek; | ||
1546 | if (n > len) | ||
1547 | n = len; | ||
1466 | 1548 | ||
1467 | z += map_bankwidth(map); | 1549 | if (!word_gap && len < map_bankwidth(map)) |
1468 | buf += map_bankwidth(map); | 1550 | datum = map_word_ff(map); |
1469 | } | ||
1470 | 1551 | ||
1471 | if (bytes) { | 1552 | datum = map_word_load_partial(map, datum, |
1472 | map_word datum; | 1553 | vec->iov_base + vec_seek, |
1554 | word_gap, n); | ||
1473 | 1555 | ||
1474 | datum = map_word_ff(map); | 1556 | len -= n; |
1475 | datum = map_word_load_partial(map, datum, buf, 0, bytes); | 1557 | word_gap += n; |
1476 | map_write(map, datum, adr+z); | 1558 | if (!len || word_gap == map_bankwidth(map)) { |
1477 | } | 1559 | map_write(map, datum, adr); |
1560 | adr += map_bankwidth(map); | ||
1561 | word_gap = 0; | ||
1562 | } | ||
1563 | |||
1564 | vec_seek += n; | ||
1565 | if (vec_seek == vec->iov_len) { | ||
1566 | vec++; | ||
1567 | vec_seek = 0; | ||
1568 | } | ||
1569 | } while (len); | ||
1570 | *pvec = vec; | ||
1571 | *pvec_seek = vec_seek; | ||
1478 | 1572 | ||
1479 | /* GO GO GO */ | 1573 | /* GO GO GO */ |
1480 | map_write(map, CMD(0xd0), cmd_adr); | 1574 | map_write(map, CMD(0xd0), cmd_adr); |
1481 | chip->state = FL_WRITING; | 1575 | chip->state = FL_WRITING; |
1482 | 1576 | ||
1483 | INVALIDATE_CACHE_UDELAY(map, chip, | 1577 | INVALIDATE_CACHE_UDELAY(map, chip, |
1484 | cmd_adr, len, | 1578 | cmd_adr, len, |
1485 | chip->buffer_write_time); | 1579 | chip->buffer_write_time); |
1486 | 1580 | ||
@@ -1506,13 +1600,14 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1506 | 1600 | ||
1507 | /* OK Still waiting */ | 1601 | /* OK Still waiting */ |
1508 | if (time_after(jiffies, timeo)) { | 1602 | if (time_after(jiffies, timeo)) { |
1603 | map_write(map, CMD(0x70), cmd_adr); | ||
1509 | chip->state = FL_STATUS; | 1604 | chip->state = FL_STATUS; |
1510 | xip_enable(map, chip, cmd_adr); | 1605 | xip_enable(map, chip, cmd_adr); |
1511 | printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); | 1606 | printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); |
1512 | ret = -EIO; | 1607 | ret = -EIO; |
1513 | goto out; | 1608 | goto out; |
1514 | } | 1609 | } |
1515 | 1610 | ||
1516 | /* Latency issues. Drop the lock, wait a while and retry */ | 1611 | /* Latency issues. Drop the lock, wait a while and retry */ |
1517 | z++; | 1612 | z++; |
1518 | UDELAY(map, chip, cmd_adr, 1); | 1613 | UDELAY(map, chip, cmd_adr, 1); |
@@ -1520,21 +1615,34 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1520 | if (!z) { | 1615 | if (!z) { |
1521 | chip->buffer_write_time--; | 1616 | chip->buffer_write_time--; |
1522 | if (!chip->buffer_write_time) | 1617 | if (!chip->buffer_write_time) |
1523 | chip->buffer_write_time++; | 1618 | chip->buffer_write_time = 1; |
1524 | } | 1619 | } |
1525 | if (z > 1) | 1620 | if (z > 1) |
1526 | chip->buffer_write_time++; | 1621 | chip->buffer_write_time++; |
1527 | 1622 | ||
1528 | /* Done and happy. */ | 1623 | /* Done and happy. */ |
1529 | chip->state = FL_STATUS; | 1624 | chip->state = FL_STATUS; |
1530 | 1625 | ||
1531 | /* check for lock bit */ | 1626 | /* check for errors */ |
1532 | if (map_word_bitsset(map, status, CMD(0x02))) { | 1627 | if (map_word_bitsset(map, status, CMD(0x1a))) { |
1533 | /* clear status */ | 1628 | unsigned long chipstatus = MERGESTATUS(status); |
1629 | |||
1630 | /* reset status */ | ||
1534 | map_write(map, CMD(0x50), cmd_adr); | 1631 | map_write(map, CMD(0x50), cmd_adr); |
1535 | /* put back into read status register mode */ | 1632 | map_write(map, CMD(0x70), cmd_adr); |
1536 | map_write(map, CMD(0x70), adr); | 1633 | xip_enable(map, chip, cmd_adr); |
1537 | ret = -EROFS; | 1634 | |
1635 | if (chipstatus & 0x02) { | ||
1636 | ret = -EROFS; | ||
1637 | } else if (chipstatus & 0x08) { | ||
1638 | printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name); | ||
1639 | ret = -EIO; | ||
1640 | } else { | ||
1641 | printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus); | ||
1642 | ret = -EINVAL; | ||
1643 | } | ||
1644 | |||
1645 | goto out; | ||
1538 | } | 1646 | } |
1539 | 1647 | ||
1540 | xip_enable(map, chip, cmd_adr); | 1648 | xip_enable(map, chip, cmd_adr); |
@@ -1543,70 +1651,65 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1543 | return ret; | 1651 | return ret; |
1544 | } | 1652 | } |
1545 | 1653 | ||
1546 | static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, | 1654 | static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs, |
1547 | size_t len, size_t *retlen, const u_char *buf) | 1655 | unsigned long count, loff_t to, size_t *retlen) |
1548 | { | 1656 | { |
1549 | struct map_info *map = mtd->priv; | 1657 | struct map_info *map = mtd->priv; |
1550 | struct cfi_private *cfi = map->fldrv_priv; | 1658 | struct cfi_private *cfi = map->fldrv_priv; |
1551 | int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; | 1659 | int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
1552 | int ret = 0; | 1660 | int ret = 0; |
1553 | int chipnum; | 1661 | int chipnum; |
1554 | unsigned long ofs; | 1662 | unsigned long ofs, vec_seek, i; |
1663 | size_t len = 0; | ||
1664 | |||
1665 | for (i = 0; i < count; i++) | ||
1666 | len += vecs[i].iov_len; | ||
1555 | 1667 | ||
1556 | *retlen = 0; | 1668 | *retlen = 0; |
1557 | if (!len) | 1669 | if (!len) |
1558 | return 0; | 1670 | return 0; |
1559 | 1671 | ||
1560 | chipnum = to >> cfi->chipshift; | 1672 | chipnum = to >> cfi->chipshift; |
1561 | ofs = to - (chipnum << cfi->chipshift); | 1673 | ofs = to - (chipnum << cfi->chipshift); |
1562 | 1674 | vec_seek = 0; | |
1563 | /* If it's not bus-aligned, do the first word write */ | ||
1564 | if (ofs & (map_bankwidth(map)-1)) { | ||
1565 | size_t local_len = (-ofs)&(map_bankwidth(map)-1); | ||
1566 | if (local_len > len) | ||
1567 | local_len = len; | ||
1568 | ret = cfi_intelext_write_words(mtd, to, local_len, | ||
1569 | retlen, buf); | ||
1570 | if (ret) | ||
1571 | return ret; | ||
1572 | ofs += local_len; | ||
1573 | buf += local_len; | ||
1574 | len -= local_len; | ||
1575 | |||
1576 | if (ofs >> cfi->chipshift) { | ||
1577 | chipnum ++; | ||
1578 | ofs = 0; | ||
1579 | if (chipnum == cfi->numchips) | ||
1580 | return 0; | ||
1581 | } | ||
1582 | } | ||
1583 | 1675 | ||
1584 | while(len) { | 1676 | do { |
1585 | /* We must not cross write block boundaries */ | 1677 | /* We must not cross write block boundaries */ |
1586 | int size = wbufsize - (ofs & (wbufsize-1)); | 1678 | int size = wbufsize - (ofs & (wbufsize-1)); |
1587 | 1679 | ||
1588 | if (size > len) | 1680 | if (size > len) |
1589 | size = len; | 1681 | size = len; |
1590 | ret = do_write_buffer(map, &cfi->chips[chipnum], | 1682 | ret = do_write_buffer(map, &cfi->chips[chipnum], |
1591 | ofs, buf, size); | 1683 | ofs, &vecs, &vec_seek, size); |
1592 | if (ret) | 1684 | if (ret) |
1593 | return ret; | 1685 | return ret; |
1594 | 1686 | ||
1595 | ofs += size; | 1687 | ofs += size; |
1596 | buf += size; | ||
1597 | (*retlen) += size; | 1688 | (*retlen) += size; |
1598 | len -= size; | 1689 | len -= size; |
1599 | 1690 | ||
1600 | if (ofs >> cfi->chipshift) { | 1691 | if (ofs >> cfi->chipshift) { |
1601 | chipnum ++; | 1692 | chipnum ++; |
1602 | ofs = 0; | 1693 | ofs = 0; |
1603 | if (chipnum == cfi->numchips) | 1694 | if (chipnum == cfi->numchips) |
1604 | return 0; | 1695 | return 0; |
1605 | } | 1696 | } |
1606 | } | 1697 | } while (len); |
1698 | |||
1607 | return 0; | 1699 | return 0; |
1608 | } | 1700 | } |
1609 | 1701 | ||
1702 | static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, | ||
1703 | size_t len, size_t *retlen, const u_char *buf) | ||
1704 | { | ||
1705 | struct kvec vec; | ||
1706 | |||
1707 | vec.iov_base = (void *) buf; | ||
1708 | vec.iov_len = len; | ||
1709 | |||
1710 | return cfi_intelext_writev(mtd, &vec, 1, to, retlen); | ||
1711 | } | ||
1712 | |||
1610 | static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | 1713 | static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, |
1611 | unsigned long adr, int len, void *thunk) | 1714 | unsigned long adr, int len, void *thunk) |
1612 | { | 1715 | { |
@@ -1672,23 +1775,17 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | |||
1672 | status = map_read(map, adr); | 1775 | status = map_read(map, adr); |
1673 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1776 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1674 | break; | 1777 | break; |
1675 | 1778 | ||
1676 | /* OK Still waiting */ | 1779 | /* OK Still waiting */ |
1677 | if (time_after(jiffies, timeo)) { | 1780 | if (time_after(jiffies, timeo)) { |
1678 | map_word Xstatus; | ||
1679 | map_write(map, CMD(0x70), adr); | 1781 | map_write(map, CMD(0x70), adr); |
1680 | chip->state = FL_STATUS; | 1782 | chip->state = FL_STATUS; |
1681 | Xstatus = map_read(map, adr); | ||
1682 | /* Clear status bits */ | ||
1683 | map_write(map, CMD(0x50), adr); | ||
1684 | map_write(map, CMD(0x70), adr); | ||
1685 | xip_enable(map, chip, adr); | 1783 | xip_enable(map, chip, adr); |
1686 | printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n", | 1784 | printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); |
1687 | adr, status.x[0], Xstatus.x[0]); | ||
1688 | ret = -EIO; | 1785 | ret = -EIO; |
1689 | goto out; | 1786 | goto out; |
1690 | } | 1787 | } |
1691 | 1788 | ||
1692 | /* Latency issues. Drop the lock, wait a while and retry */ | 1789 | /* Latency issues. Drop the lock, wait a while and retry */ |
1693 | UDELAY(map, chip, adr, 1000000/HZ); | 1790 | UDELAY(map, chip, adr, 1000000/HZ); |
1694 | } | 1791 | } |
@@ -1698,43 +1795,40 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | |||
1698 | chip->state = FL_STATUS; | 1795 | chip->state = FL_STATUS; |
1699 | status = map_read(map, adr); | 1796 | status = map_read(map, adr); |
1700 | 1797 | ||
1701 | /* check for lock bit */ | 1798 | /* check for errors */ |
1702 | if (map_word_bitsset(map, status, CMD(0x3a))) { | 1799 | if (map_word_bitsset(map, status, CMD(0x3a))) { |
1703 | unsigned long chipstatus; | 1800 | unsigned long chipstatus = MERGESTATUS(status); |
1704 | 1801 | ||
1705 | /* Reset the error bits */ | 1802 | /* Reset the error bits */ |
1706 | map_write(map, CMD(0x50), adr); | 1803 | map_write(map, CMD(0x50), adr); |
1707 | map_write(map, CMD(0x70), adr); | 1804 | map_write(map, CMD(0x70), adr); |
1708 | xip_enable(map, chip, adr); | 1805 | xip_enable(map, chip, adr); |
1709 | 1806 | ||
1710 | chipstatus = MERGESTATUS(status); | ||
1711 | |||
1712 | if ((chipstatus & 0x30) == 0x30) { | 1807 | if ((chipstatus & 0x30) == 0x30) { |
1713 | printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus); | 1808 | printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus); |
1714 | ret = -EIO; | 1809 | ret = -EINVAL; |
1715 | } else if (chipstatus & 0x02) { | 1810 | } else if (chipstatus & 0x02) { |
1716 | /* Protection bit set */ | 1811 | /* Protection bit set */ |
1717 | ret = -EROFS; | 1812 | ret = -EROFS; |
1718 | } else if (chipstatus & 0x8) { | 1813 | } else if (chipstatus & 0x8) { |
1719 | /* Voltage */ | 1814 | /* Voltage */ |
1720 | printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus); | 1815 | printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name); |
1721 | ret = -EIO; | 1816 | ret = -EIO; |
1722 | } else if (chipstatus & 0x20) { | 1817 | } else if (chipstatus & 0x20 && retries--) { |
1723 | if (retries--) { | 1818 | printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); |
1724 | printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); | 1819 | timeo = jiffies + HZ; |
1725 | timeo = jiffies + HZ; | 1820 | put_chip(map, chip, adr); |
1726 | put_chip(map, chip, adr); | 1821 | spin_unlock(chip->mutex); |
1727 | spin_unlock(chip->mutex); | 1822 | goto retry; |
1728 | goto retry; | 1823 | } else { |
1729 | } | 1824 | printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus); |
1730 | printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus); | ||
1731 | ret = -EIO; | 1825 | ret = -EIO; |
1732 | } | 1826 | } |
1733 | } else { | 1827 | |
1734 | xip_enable(map, chip, adr); | 1828 | goto out; |
1735 | ret = 0; | ||
1736 | } | 1829 | } |
1737 | 1830 | ||
1831 | xip_enable(map, chip, adr); | ||
1738 | out: put_chip(map, chip, adr); | 1832 | out: put_chip(map, chip, adr); |
1739 | spin_unlock(chip->mutex); | 1833 | spin_unlock(chip->mutex); |
1740 | return ret; | 1834 | return ret; |
@@ -1754,7 +1848,7 @@ int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
1754 | 1848 | ||
1755 | instr->state = MTD_ERASE_DONE; | 1849 | instr->state = MTD_ERASE_DONE; |
1756 | mtd_erase_callback(instr); | 1850 | mtd_erase_callback(instr); |
1757 | 1851 | ||
1758 | return 0; | 1852 | return 0; |
1759 | } | 1853 | } |
1760 | 1854 | ||
@@ -1775,7 +1869,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) | |||
1775 | if (!ret) { | 1869 | if (!ret) { |
1776 | chip->oldstate = chip->state; | 1870 | chip->oldstate = chip->state; |
1777 | chip->state = FL_SYNCING; | 1871 | chip->state = FL_SYNCING; |
1778 | /* No need to wake_up() on this state change - | 1872 | /* No need to wake_up() on this state change - |
1779 | * as the whole point is that nobody can do anything | 1873 | * as the whole point is that nobody can do anything |
1780 | * with the chip now anyway. | 1874 | * with the chip now anyway. |
1781 | */ | 1875 | */ |
@@ -1789,7 +1883,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) | |||
1789 | chip = &cfi->chips[i]; | 1883 | chip = &cfi->chips[i]; |
1790 | 1884 | ||
1791 | spin_lock(chip->mutex); | 1885 | spin_lock(chip->mutex); |
1792 | 1886 | ||
1793 | if (chip->state == FL_SYNCING) { | 1887 | if (chip->state == FL_SYNCING) { |
1794 | chip->state = chip->oldstate; | 1888 | chip->state = chip->oldstate; |
1795 | chip->oldstate = FL_READY; | 1889 | chip->oldstate = FL_READY; |
@@ -1846,7 +1940,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip | |||
1846 | 1940 | ||
1847 | ENABLE_VPP(map); | 1941 | ENABLE_VPP(map); |
1848 | xip_disable(map, chip, adr); | 1942 | xip_disable(map, chip, adr); |
1849 | 1943 | ||
1850 | map_write(map, CMD(0x60), adr); | 1944 | map_write(map, CMD(0x60), adr); |
1851 | if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { | 1945 | if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { |
1852 | map_write(map, CMD(0x01), adr); | 1946 | map_write(map, CMD(0x01), adr); |
@@ -1874,25 +1968,22 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip | |||
1874 | status = map_read(map, adr); | 1968 | status = map_read(map, adr); |
1875 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1969 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1876 | break; | 1970 | break; |
1877 | 1971 | ||
1878 | /* OK Still waiting */ | 1972 | /* OK Still waiting */ |
1879 | if (time_after(jiffies, timeo)) { | 1973 | if (time_after(jiffies, timeo)) { |
1880 | map_word Xstatus; | ||
1881 | map_write(map, CMD(0x70), adr); | 1974 | map_write(map, CMD(0x70), adr); |
1882 | chip->state = FL_STATUS; | 1975 | chip->state = FL_STATUS; |
1883 | Xstatus = map_read(map, adr); | ||
1884 | xip_enable(map, chip, adr); | 1976 | xip_enable(map, chip, adr); |
1885 | printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n", | 1977 | printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); |
1886 | status.x[0], Xstatus.x[0]); | ||
1887 | put_chip(map, chip, adr); | 1978 | put_chip(map, chip, adr); |
1888 | spin_unlock(chip->mutex); | 1979 | spin_unlock(chip->mutex); |
1889 | return -EIO; | 1980 | return -EIO; |
1890 | } | 1981 | } |
1891 | 1982 | ||
1892 | /* Latency issues. Drop the lock, wait a while and retry */ | 1983 | /* Latency issues. Drop the lock, wait a while and retry */ |
1893 | UDELAY(map, chip, adr, 1); | 1984 | UDELAY(map, chip, adr, 1); |
1894 | } | 1985 | } |
1895 | 1986 | ||
1896 | /* Done and happy. */ | 1987 | /* Done and happy. */ |
1897 | chip->state = FL_STATUS; | 1988 | chip->state = FL_STATUS; |
1898 | xip_enable(map, chip, adr); | 1989 | xip_enable(map, chip, adr); |
@@ -1912,9 +2003,9 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1912 | ofs, len, 0); | 2003 | ofs, len, 0); |
1913 | #endif | 2004 | #endif |
1914 | 2005 | ||
1915 | ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, | 2006 | ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, |
1916 | ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); | 2007 | ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); |
1917 | 2008 | ||
1918 | #ifdef DEBUG_LOCK_BITS | 2009 | #ifdef DEBUG_LOCK_BITS |
1919 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", | 2010 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", |
1920 | __FUNCTION__, ret); | 2011 | __FUNCTION__, ret); |
@@ -1938,20 +2029,20 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1938 | 2029 | ||
1939 | ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, | 2030 | ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, |
1940 | ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK); | 2031 | ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK); |
1941 | 2032 | ||
1942 | #ifdef DEBUG_LOCK_BITS | 2033 | #ifdef DEBUG_LOCK_BITS |
1943 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", | 2034 | printk(KERN_DEBUG "%s: lock status after, ret=%d\n", |
1944 | __FUNCTION__, ret); | 2035 | __FUNCTION__, ret); |
1945 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, | 2036 | cfi_varsize_frob(mtd, do_printlockstatus_oneblock, |
1946 | ofs, len, 0); | 2037 | ofs, len, 0); |
1947 | #endif | 2038 | #endif |
1948 | 2039 | ||
1949 | return ret; | 2040 | return ret; |
1950 | } | 2041 | } |
1951 | 2042 | ||
1952 | #ifdef CONFIG_MTD_OTP | 2043 | #ifdef CONFIG_MTD_OTP |
1953 | 2044 | ||
1954 | typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, | 2045 | typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, |
1955 | u_long data_offset, u_char *buf, u_int size, | 2046 | u_long data_offset, u_char *buf, u_int size, |
1956 | u_long prot_offset, u_int groupno, u_int groupsize); | 2047 | u_long prot_offset, u_int groupno, u_int groupsize); |
1957 | 2048 | ||
@@ -2002,7 +2093,7 @@ do_otp_write(struct map_info *map, struct flchip *chip, u_long offset, | |||
2002 | 2093 | ||
2003 | datum = map_word_load_partial(map, datum, buf, gap, n); | 2094 | datum = map_word_load_partial(map, datum, buf, gap, n); |
2004 | ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); | 2095 | ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); |
2005 | if (ret) | 2096 | if (ret) |
2006 | return ret; | 2097 | return ret; |
2007 | 2098 | ||
2008 | offset += n; | 2099 | offset += n; |
@@ -2195,7 +2286,7 @@ static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd, | |||
2195 | NULL, do_otp_lock, 1); | 2286 | NULL, do_otp_lock, 1); |
2196 | } | 2287 | } |
2197 | 2288 | ||
2198 | static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, | 2289 | static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, |
2199 | struct otp_info *buf, size_t len) | 2290 | struct otp_info *buf, size_t len) |
2200 | { | 2291 | { |
2201 | size_t retlen; | 2292 | size_t retlen; |
@@ -2238,7 +2329,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) | |||
2238 | if (chip->oldstate == FL_READY) { | 2329 | if (chip->oldstate == FL_READY) { |
2239 | chip->oldstate = chip->state; | 2330 | chip->oldstate = chip->state; |
2240 | chip->state = FL_PM_SUSPENDED; | 2331 | chip->state = FL_PM_SUSPENDED; |
2241 | /* No need to wake_up() on this state change - | 2332 | /* No need to wake_up() on this state change - |
2242 | * as the whole point is that nobody can do anything | 2333 | * as the whole point is that nobody can do anything |
2243 | * with the chip now anyway. | 2334 | * with the chip now anyway. |
2244 | */ | 2335 | */ |
@@ -2266,9 +2357,9 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) | |||
2266 | if (ret) { | 2357 | if (ret) { |
2267 | for (i--; i >=0; i--) { | 2358 | for (i--; i >=0; i--) { |
2268 | chip = &cfi->chips[i]; | 2359 | chip = &cfi->chips[i]; |
2269 | 2360 | ||
2270 | spin_lock(chip->mutex); | 2361 | spin_lock(chip->mutex); |
2271 | 2362 | ||
2272 | if (chip->state == FL_PM_SUSPENDED) { | 2363 | if (chip->state == FL_PM_SUSPENDED) { |
2273 | /* No need to force it into a known state here, | 2364 | /* No need to force it into a known state here, |
2274 | because we're returning failure, and it didn't | 2365 | because we're returning failure, and it didn't |
@@ -2279,8 +2370,8 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) | |||
2279 | } | 2370 | } |
2280 | spin_unlock(chip->mutex); | 2371 | spin_unlock(chip->mutex); |
2281 | } | 2372 | } |
2282 | } | 2373 | } |
2283 | 2374 | ||
2284 | return ret; | 2375 | return ret; |
2285 | } | 2376 | } |
2286 | 2377 | ||
@@ -2292,11 +2383,11 @@ static void cfi_intelext_resume(struct mtd_info *mtd) | |||
2292 | struct flchip *chip; | 2383 | struct flchip *chip; |
2293 | 2384 | ||
2294 | for (i=0; i<cfi->numchips; i++) { | 2385 | for (i=0; i<cfi->numchips; i++) { |
2295 | 2386 | ||
2296 | chip = &cfi->chips[i]; | 2387 | chip = &cfi->chips[i]; |
2297 | 2388 | ||
2298 | spin_lock(chip->mutex); | 2389 | spin_lock(chip->mutex); |
2299 | 2390 | ||
2300 | /* Go to known state. Chip may have been power cycled */ | 2391 | /* Go to known state. Chip may have been power cycled */ |
2301 | if (chip->state == FL_PM_SUSPENDED) { | 2392 | if (chip->state == FL_PM_SUSPENDED) { |
2302 | map_write(map, CMD(0xFF), cfi->chips[i].start); | 2393 | map_write(map, CMD(0xFF), cfi->chips[i].start); |
@@ -2318,7 +2409,7 @@ static int cfi_intelext_reset(struct mtd_info *mtd) | |||
2318 | struct flchip *chip = &cfi->chips[i]; | 2409 | struct flchip *chip = &cfi->chips[i]; |
2319 | 2410 | ||
2320 | /* force the completion of any ongoing operation | 2411 | /* force the completion of any ongoing operation |
2321 | and switch to array mode so any bootloader in | 2412 | and switch to array mode so any bootloader in |
2322 | flash is accessible for soft reboot. */ | 2413 | flash is accessible for soft reboot. */ |
2323 | spin_lock(chip->mutex); | 2414 | spin_lock(chip->mutex); |
2324 | ret = get_chip(map, chip, chip->start, FL_SYNCING); | 2415 | ret = get_chip(map, chip, chip->start, FL_SYNCING); |
@@ -2355,20 +2446,23 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) | |||
2355 | kfree(mtd->eraseregions); | 2446 | kfree(mtd->eraseregions); |
2356 | } | 2447 | } |
2357 | 2448 | ||
2358 | static char im_name_1[]="cfi_cmdset_0001"; | 2449 | static char im_name_0001[] = "cfi_cmdset_0001"; |
2359 | static char im_name_3[]="cfi_cmdset_0003"; | 2450 | static char im_name_0003[] = "cfi_cmdset_0003"; |
2451 | static char im_name_0200[] = "cfi_cmdset_0200"; | ||
2360 | 2452 | ||
2361 | static int __init cfi_intelext_init(void) | 2453 | static int __init cfi_intelext_init(void) |
2362 | { | 2454 | { |
2363 | inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001); | 2455 | inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001); |
2364 | inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001); | 2456 | inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001); |
2457 | inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001); | ||
2365 | return 0; | 2458 | return 0; |
2366 | } | 2459 | } |
2367 | 2460 | ||
2368 | static void __exit cfi_intelext_exit(void) | 2461 | static void __exit cfi_intelext_exit(void) |
2369 | { | 2462 | { |
2370 | inter_module_unregister(im_name_1); | 2463 | inter_module_unregister(im_name_0001); |
2371 | inter_module_unregister(im_name_3); | 2464 | inter_module_unregister(im_name_0003); |
2465 | inter_module_unregister(im_name_0200); | ||
2372 | } | 2466 | } |
2373 | 2467 | ||
2374 | module_init(cfi_intelext_init); | 2468 | module_init(cfi_intelext_init); |
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 0e6475050da9..aed10bd5c3c3 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -10,14 +10,14 @@ | |||
10 | * | 10 | * |
11 | * 4_by_16 work by Carolyn J. Smith | 11 | * 4_by_16 work by Carolyn J. Smith |
12 | * | 12 | * |
13 | * XIP support hooks by Vitaly Wool (based on code for Intel flash | 13 | * XIP support hooks by Vitaly Wool (based on code for Intel flash |
14 | * by Nicolas Pitre) | 14 | * by Nicolas Pitre) |
15 | * | 15 | * |
16 | * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com | 16 | * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com |
17 | * | 17 | * |
18 | * This code is GPL | 18 | * This code is GPL |
19 | * | 19 | * |
20 | * $Id: cfi_cmdset_0002.c,v 1.118 2005/07/04 22:34:29 gleixner Exp $ | 20 | * $Id: cfi_cmdset_0002.c,v 1.122 2005/11/07 11:14:22 gleixner Exp $ |
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
@@ -93,7 +93,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) | |||
93 | }; | 93 | }; |
94 | 94 | ||
95 | printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1); | 95 | printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1); |
96 | printk(" Address sensitive unlock: %s\n", | 96 | printk(" Address sensitive unlock: %s\n", |
97 | (extp->SiliconRevision & 1) ? "Not required" : "Required"); | 97 | (extp->SiliconRevision & 1) ? "Not required" : "Required"); |
98 | 98 | ||
99 | if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend)) | 99 | if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend)) |
@@ -118,9 +118,9 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) | |||
118 | else | 118 | else |
119 | printk(" Page mode: %d word page\n", extp->PageMode << 2); | 119 | printk(" Page mode: %d word page\n", extp->PageMode << 2); |
120 | 120 | ||
121 | printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", | 121 | printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", |
122 | extp->VppMin >> 4, extp->VppMin & 0xf); | 122 | extp->VppMin >> 4, extp->VppMin & 0xf); |
123 | printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", | 123 | printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", |
124 | extp->VppMax >> 4, extp->VppMax & 0xf); | 124 | extp->VppMax >> 4, extp->VppMax & 0xf); |
125 | 125 | ||
126 | if (extp->TopBottom < ARRAY_SIZE(top_bottom)) | 126 | if (extp->TopBottom < ARRAY_SIZE(top_bottom)) |
@@ -177,7 +177,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) | |||
177 | ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) { | 177 | ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) { |
178 | mtd->erase = cfi_amdstd_erase_chip; | 178 | mtd->erase = cfi_amdstd_erase_chip; |
179 | } | 179 | } |
180 | 180 | ||
181 | } | 181 | } |
182 | 182 | ||
183 | static struct cfi_fixup cfi_fixup_table[] = { | 183 | static struct cfi_fixup cfi_fixup_table[] = { |
@@ -239,7 +239,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
239 | 239 | ||
240 | if (cfi->cfi_mode==CFI_MODE_CFI){ | 240 | if (cfi->cfi_mode==CFI_MODE_CFI){ |
241 | unsigned char bootloc; | 241 | unsigned char bootloc; |
242 | /* | 242 | /* |
243 | * It's a real CFI chip, not one for which the probe | 243 | * It's a real CFI chip, not one for which the probe |
244 | * routine faked a CFI structure. So we read the feature | 244 | * routine faked a CFI structure. So we read the feature |
245 | * table from it. | 245 | * table from it. |
@@ -253,8 +253,18 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
253 | return NULL; | 253 | return NULL; |
254 | } | 254 | } |
255 | 255 | ||
256 | if (extp->MajorVersion != '1' || | ||
257 | (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { | ||
258 | printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " | ||
259 | "version %c.%c.\n", extp->MajorVersion, | ||
260 | extp->MinorVersion); | ||
261 | kfree(extp); | ||
262 | kfree(mtd); | ||
263 | return NULL; | ||
264 | } | ||
265 | |||
256 | /* Install our own private info structure */ | 266 | /* Install our own private info structure */ |
257 | cfi->cmdset_priv = extp; | 267 | cfi->cmdset_priv = extp; |
258 | 268 | ||
259 | /* Apply cfi device specific fixups */ | 269 | /* Apply cfi device specific fixups */ |
260 | cfi_fixup(mtd, cfi_fixup_table); | 270 | cfi_fixup(mtd, cfi_fixup_table); |
@@ -262,7 +272,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
262 | #ifdef DEBUG_CFI_FEATURES | 272 | #ifdef DEBUG_CFI_FEATURES |
263 | /* Tell the user about it in lots of lovely detail */ | 273 | /* Tell the user about it in lots of lovely detail */ |
264 | cfi_tell_features(extp); | 274 | cfi_tell_features(extp); |
265 | #endif | 275 | #endif |
266 | 276 | ||
267 | bootloc = extp->TopBottom; | 277 | bootloc = extp->TopBottom; |
268 | if ((bootloc != 2) && (bootloc != 3)) { | 278 | if ((bootloc != 2) && (bootloc != 3)) { |
@@ -273,11 +283,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
273 | 283 | ||
274 | if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { | 284 | if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { |
275 | printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); | 285 | printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); |
276 | 286 | ||
277 | for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) { | 287 | for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) { |
278 | int j = (cfi->cfiq->NumEraseRegions-1)-i; | 288 | int j = (cfi->cfiq->NumEraseRegions-1)-i; |
279 | __u32 swap; | 289 | __u32 swap; |
280 | 290 | ||
281 | swap = cfi->cfiq->EraseRegionInfo[i]; | 291 | swap = cfi->cfiq->EraseRegionInfo[i]; |
282 | cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j]; | 292 | cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j]; |
283 | cfi->cfiq->EraseRegionInfo[j] = swap; | 293 | cfi->cfiq->EraseRegionInfo[j] = swap; |
@@ -288,11 +298,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
288 | cfi->addr_unlock2 = 0x2aa; | 298 | cfi->addr_unlock2 = 0x2aa; |
289 | /* Modify the unlock address if we are in compatibility mode */ | 299 | /* Modify the unlock address if we are in compatibility mode */ |
290 | if ( /* x16 in x8 mode */ | 300 | if ( /* x16 in x8 mode */ |
291 | ((cfi->device_type == CFI_DEVICETYPE_X8) && | 301 | ((cfi->device_type == CFI_DEVICETYPE_X8) && |
292 | (cfi->cfiq->InterfaceDesc == 2)) || | 302 | (cfi->cfiq->InterfaceDesc == 2)) || |
293 | /* x32 in x16 mode */ | 303 | /* x32 in x16 mode */ |
294 | ((cfi->device_type == CFI_DEVICETYPE_X16) && | 304 | ((cfi->device_type == CFI_DEVICETYPE_X16) && |
295 | (cfi->cfiq->InterfaceDesc == 4))) | 305 | (cfi->cfiq->InterfaceDesc == 4))) |
296 | { | 306 | { |
297 | cfi->addr_unlock1 = 0xaaa; | 307 | cfi->addr_unlock1 = 0xaaa; |
298 | cfi->addr_unlock2 = 0x555; | 308 | cfi->addr_unlock2 = 0x555; |
@@ -310,10 +320,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
310 | cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; | 320 | cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; |
311 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; | 321 | cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; |
312 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; | 322 | cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; |
313 | } | 323 | } |
314 | 324 | ||
315 | map->fldrv = &cfi_amdstd_chipdrv; | 325 | map->fldrv = &cfi_amdstd_chipdrv; |
316 | 326 | ||
317 | return cfi_amdstd_setup(mtd); | 327 | return cfi_amdstd_setup(mtd); |
318 | } | 328 | } |
319 | 329 | ||
@@ -326,24 +336,24 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) | |||
326 | unsigned long offset = 0; | 336 | unsigned long offset = 0; |
327 | int i,j; | 337 | int i,j; |
328 | 338 | ||
329 | printk(KERN_NOTICE "number of %s chips: %d\n", | 339 | printk(KERN_NOTICE "number of %s chips: %d\n", |
330 | (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); | 340 | (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); |
331 | /* Select the correct geometry setup */ | 341 | /* Select the correct geometry setup */ |
332 | mtd->size = devsize * cfi->numchips; | 342 | mtd->size = devsize * cfi->numchips; |
333 | 343 | ||
334 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; | 344 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; |
335 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) | 345 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) |
336 | * mtd->numeraseregions, GFP_KERNEL); | 346 | * mtd->numeraseregions, GFP_KERNEL); |
337 | if (!mtd->eraseregions) { | 347 | if (!mtd->eraseregions) { |
338 | printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); | 348 | printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); |
339 | goto setup_err; | 349 | goto setup_err; |
340 | } | 350 | } |
341 | 351 | ||
342 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { | 352 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { |
343 | unsigned long ernum, ersize; | 353 | unsigned long ernum, ersize; |
344 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; | 354 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; |
345 | ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; | 355 | ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; |
346 | 356 | ||
347 | if (mtd->erasesize < ersize) { | 357 | if (mtd->erasesize < ersize) { |
348 | mtd->erasesize = ersize; | 358 | mtd->erasesize = ersize; |
349 | } | 359 | } |
@@ -429,7 +439,7 @@ static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word | |||
429 | oldd = map_read(map, addr); | 439 | oldd = map_read(map, addr); |
430 | curd = map_read(map, addr); | 440 | curd = map_read(map, addr); |
431 | 441 | ||
432 | return map_word_equal(map, oldd, curd) && | 442 | return map_word_equal(map, oldd, curd) && |
433 | map_word_equal(map, curd, expected); | 443 | map_word_equal(map, curd, expected); |
434 | } | 444 | } |
435 | 445 | ||
@@ -461,7 +471,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
461 | /* Someone else might have been playing with it. */ | 471 | /* Someone else might have been playing with it. */ |
462 | goto retry; | 472 | goto retry; |
463 | } | 473 | } |
464 | 474 | ||
465 | case FL_READY: | 475 | case FL_READY: |
466 | case FL_CFI_QUERY: | 476 | case FL_CFI_QUERY: |
467 | case FL_JEDEC_QUERY: | 477 | case FL_JEDEC_QUERY: |
@@ -504,7 +514,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
504 | printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); | 514 | printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); |
505 | return -EIO; | 515 | return -EIO; |
506 | } | 516 | } |
507 | 517 | ||
508 | spin_unlock(chip->mutex); | 518 | spin_unlock(chip->mutex); |
509 | cfi_udelay(1); | 519 | cfi_udelay(1); |
510 | spin_lock(chip->mutex); | 520 | spin_lock(chip->mutex); |
@@ -607,7 +617,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, | |||
607 | * When a delay is required for the flash operation to complete, the | 617 | * When a delay is required for the flash operation to complete, the |
608 | * xip_udelay() function is polling for both the given timeout and pending | 618 | * xip_udelay() function is polling for both the given timeout and pending |
609 | * (but still masked) hardware interrupts. Whenever there is an interrupt | 619 | * (but still masked) hardware interrupts. Whenever there is an interrupt |
610 | * pending then the flash erase operation is suspended, array mode restored | 620 | * pending then the flash erase operation is suspended, array mode restored |
611 | * and interrupts unmasked. Task scheduling might also happen at that | 621 | * and interrupts unmasked. Task scheduling might also happen at that |
612 | * point. The CPU eventually returns from the interrupt or the call to | 622 | * point. The CPU eventually returns from the interrupt or the call to |
613 | * schedule() and the suspended flash operation is resumed for the remaining | 623 | * schedule() and the suspended flash operation is resumed for the remaining |
@@ -631,9 +641,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, | |||
631 | ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) && | 641 | ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) && |
632 | (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { | 642 | (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { |
633 | /* | 643 | /* |
634 | * Let's suspend the erase operation when supported. | 644 | * Let's suspend the erase operation when supported. |
635 | * Note that we currently don't try to suspend | 645 | * Note that we currently don't try to suspend |
636 | * interleaved chips if there is already another | 646 | * interleaved chips if there is already another |
637 | * operation suspended (imagine what happens | 647 | * operation suspended (imagine what happens |
638 | * when one chip was already done with the current | 648 | * when one chip was already done with the current |
639 | * operation while another chip suspended it, then | 649 | * operation while another chip suspended it, then |
@@ -769,8 +779,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
769 | 779 | ||
770 | adr += chip->start; | 780 | adr += chip->start; |
771 | 781 | ||
772 | /* Ensure cmd read/writes are aligned. */ | 782 | /* Ensure cmd read/writes are aligned. */ |
773 | cmd_addr = adr & ~(map_bankwidth(map)-1); | 783 | cmd_addr = adr & ~(map_bankwidth(map)-1); |
774 | 784 | ||
775 | spin_lock(chip->mutex); | 785 | spin_lock(chip->mutex); |
776 | ret = get_chip(map, chip, cmd_addr, FL_READY); | 786 | ret = get_chip(map, chip, cmd_addr, FL_READY); |
@@ -850,7 +860,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi | |||
850 | #endif | 860 | #endif |
851 | set_current_state(TASK_UNINTERRUPTIBLE); | 861 | set_current_state(TASK_UNINTERRUPTIBLE); |
852 | add_wait_queue(&chip->wq, &wait); | 862 | add_wait_queue(&chip->wq, &wait); |
853 | 863 | ||
854 | spin_unlock(chip->mutex); | 864 | spin_unlock(chip->mutex); |
855 | 865 | ||
856 | schedule(); | 866 | schedule(); |
@@ -862,7 +872,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi | |||
862 | timeo = jiffies + HZ; | 872 | timeo = jiffies + HZ; |
863 | 873 | ||
864 | goto retry; | 874 | goto retry; |
865 | } | 875 | } |
866 | 876 | ||
867 | adr += chip->start; | 877 | adr += chip->start; |
868 | 878 | ||
@@ -871,14 +881,14 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi | |||
871 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 881 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
872 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 882 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
873 | cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 883 | cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
874 | 884 | ||
875 | map_copy_from(map, buf, adr, len); | 885 | map_copy_from(map, buf, adr, len); |
876 | 886 | ||
877 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 887 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
878 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 888 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
879 | cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 889 | cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
880 | cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 890 | cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
881 | 891 | ||
882 | wake_up(&chip->wq); | 892 | wake_up(&chip->wq); |
883 | spin_unlock(chip->mutex); | 893 | spin_unlock(chip->mutex); |
884 | 894 | ||
@@ -987,7 +997,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
987 | chip->word_write_time); | 997 | chip->word_write_time); |
988 | 998 | ||
989 | /* See comment above for timeout value. */ | 999 | /* See comment above for timeout value. */ |
990 | timeo = jiffies + uWriteTimeout; | 1000 | timeo = jiffies + uWriteTimeout; |
991 | for (;;) { | 1001 | for (;;) { |
992 | if (chip->state != FL_WRITING) { | 1002 | if (chip->state != FL_WRITING) { |
993 | /* Someone's suspended the write. Sleep */ | 1003 | /* Someone's suspended the write. Sleep */ |
@@ -1003,16 +1013,16 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1003 | continue; | 1013 | continue; |
1004 | } | 1014 | } |
1005 | 1015 | ||
1006 | if (chip_ready(map, adr)) | 1016 | if (time_after(jiffies, timeo) && !chip_ready(map, adr)){ |
1007 | break; | ||
1008 | |||
1009 | if (time_after(jiffies, timeo)) { | ||
1010 | xip_enable(map, chip, adr); | 1017 | xip_enable(map, chip, adr); |
1011 | printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); | 1018 | printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); |
1012 | xip_disable(map, chip, adr); | 1019 | xip_disable(map, chip, adr); |
1013 | break; | 1020 | break; |
1014 | } | 1021 | } |
1015 | 1022 | ||
1023 | if (chip_ready(map, adr)) | ||
1024 | break; | ||
1025 | |||
1016 | /* Latency issues. Drop the lock, wait a while and retry */ | 1026 | /* Latency issues. Drop the lock, wait a while and retry */ |
1017 | UDELAY(map, chip, adr, 1); | 1027 | UDELAY(map, chip, adr, 1); |
1018 | } | 1028 | } |
@@ -1022,7 +1032,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1022 | map_write( map, CMD(0xF0), chip->start ); | 1032 | map_write( map, CMD(0xF0), chip->start ); |
1023 | /* FIXME - should have reset delay before continuing */ | 1033 | /* FIXME - should have reset delay before continuing */ |
1024 | 1034 | ||
1025 | if (++retry_cnt <= MAX_WORD_RETRIES) | 1035 | if (++retry_cnt <= MAX_WORD_RETRIES) |
1026 | goto retry; | 1036 | goto retry; |
1027 | 1037 | ||
1028 | ret = -EIO; | 1038 | ret = -EIO; |
@@ -1090,27 +1100,27 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1090 | 1100 | ||
1091 | /* Number of bytes to copy from buffer */ | 1101 | /* Number of bytes to copy from buffer */ |
1092 | n = min_t(int, len, map_bankwidth(map)-i); | 1102 | n = min_t(int, len, map_bankwidth(map)-i); |
1093 | 1103 | ||
1094 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); | 1104 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); |
1095 | 1105 | ||
1096 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1106 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1097 | bus_ofs, tmp_buf); | 1107 | bus_ofs, tmp_buf); |
1098 | if (ret) | 1108 | if (ret) |
1099 | return ret; | 1109 | return ret; |
1100 | 1110 | ||
1101 | ofs += n; | 1111 | ofs += n; |
1102 | buf += n; | 1112 | buf += n; |
1103 | (*retlen) += n; | 1113 | (*retlen) += n; |
1104 | len -= n; | 1114 | len -= n; |
1105 | 1115 | ||
1106 | if (ofs >> cfi->chipshift) { | 1116 | if (ofs >> cfi->chipshift) { |
1107 | chipnum ++; | 1117 | chipnum ++; |
1108 | ofs = 0; | 1118 | ofs = 0; |
1109 | if (chipnum == cfi->numchips) | 1119 | if (chipnum == cfi->numchips) |
1110 | return 0; | 1120 | return 0; |
1111 | } | 1121 | } |
1112 | } | 1122 | } |
1113 | 1123 | ||
1114 | /* We are now aligned, write as much as possible */ | 1124 | /* We are now aligned, write as much as possible */ |
1115 | while(len >= map_bankwidth(map)) { | 1125 | while(len >= map_bankwidth(map)) { |
1116 | map_word datum; | 1126 | map_word datum; |
@@ -1128,7 +1138,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1128 | len -= map_bankwidth(map); | 1138 | len -= map_bankwidth(map); |
1129 | 1139 | ||
1130 | if (ofs >> cfi->chipshift) { | 1140 | if (ofs >> cfi->chipshift) { |
1131 | chipnum ++; | 1141 | chipnum ++; |
1132 | ofs = 0; | 1142 | ofs = 0; |
1133 | if (chipnum == cfi->numchips) | 1143 | if (chipnum == cfi->numchips) |
1134 | return 0; | 1144 | return 0; |
@@ -1166,12 +1176,12 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1166 | spin_unlock(cfi->chips[chipnum].mutex); | 1176 | spin_unlock(cfi->chips[chipnum].mutex); |
1167 | 1177 | ||
1168 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); | 1178 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); |
1169 | 1179 | ||
1170 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1180 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1171 | ofs, tmp_buf); | 1181 | ofs, tmp_buf); |
1172 | if (ret) | 1182 | if (ret) |
1173 | return ret; | 1183 | return ret; |
1174 | 1184 | ||
1175 | (*retlen) += len; | 1185 | (*retlen) += len; |
1176 | } | 1186 | } |
1177 | 1187 | ||
@@ -1183,7 +1193,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1183 | * FIXME: interleaved mode not tested, and probably not supported! | 1193 | * FIXME: interleaved mode not tested, and probably not supported! |
1184 | */ | 1194 | */ |
1185 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | 1195 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, |
1186 | unsigned long adr, const u_char *buf, | 1196 | unsigned long adr, const u_char *buf, |
1187 | int len) | 1197 | int len) |
1188 | { | 1198 | { |
1189 | struct cfi_private *cfi = map->fldrv_priv; | 1199 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -1213,7 +1223,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1213 | XIP_INVAL_CACHED_RANGE(map, adr, len); | 1223 | XIP_INVAL_CACHED_RANGE(map, adr, len); |
1214 | ENABLE_VPP(map); | 1224 | ENABLE_VPP(map); |
1215 | xip_disable(map, chip, cmd_adr); | 1225 | xip_disable(map, chip, cmd_adr); |
1216 | 1226 | ||
1217 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1227 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
1218 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 1228 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
1219 | //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1229 | //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
@@ -1247,8 +1257,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1247 | adr, map_bankwidth(map), | 1257 | adr, map_bankwidth(map), |
1248 | chip->word_write_time); | 1258 | chip->word_write_time); |
1249 | 1259 | ||
1250 | timeo = jiffies + uWriteTimeout; | 1260 | timeo = jiffies + uWriteTimeout; |
1251 | 1261 | ||
1252 | for (;;) { | 1262 | for (;;) { |
1253 | if (chip->state != FL_WRITING) { | 1263 | if (chip->state != FL_WRITING) { |
1254 | /* Someone's suspended the write. Sleep */ | 1264 | /* Someone's suspended the write. Sleep */ |
@@ -1264,13 +1274,13 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1264 | continue; | 1274 | continue; |
1265 | } | 1275 | } |
1266 | 1276 | ||
1277 | if (time_after(jiffies, timeo) && !chip_ready(map, adr)) | ||
1278 | break; | ||
1279 | |||
1267 | if (chip_ready(map, adr)) { | 1280 | if (chip_ready(map, adr)) { |
1268 | xip_enable(map, chip, adr); | 1281 | xip_enable(map, chip, adr); |
1269 | goto op_done; | 1282 | goto op_done; |
1270 | } | 1283 | } |
1271 | |||
1272 | if( time_after(jiffies, timeo)) | ||
1273 | break; | ||
1274 | 1284 | ||
1275 | /* Latency issues. Drop the lock, wait a while and retry */ | 1285 | /* Latency issues. Drop the lock, wait a while and retry */ |
1276 | UDELAY(map, chip, adr, 1); | 1286 | UDELAY(map, chip, adr, 1); |
@@ -1342,7 +1352,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, | |||
1342 | if (size % map_bankwidth(map)) | 1352 | if (size % map_bankwidth(map)) |
1343 | size -= size % map_bankwidth(map); | 1353 | size -= size % map_bankwidth(map); |
1344 | 1354 | ||
1345 | ret = do_write_buffer(map, &cfi->chips[chipnum], | 1355 | ret = do_write_buffer(map, &cfi->chips[chipnum], |
1346 | ofs, buf, size); | 1356 | ofs, buf, size); |
1347 | if (ret) | 1357 | if (ret) |
1348 | return ret; | 1358 | return ret; |
@@ -1353,7 +1363,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, | |||
1353 | len -= size; | 1363 | len -= size; |
1354 | 1364 | ||
1355 | if (ofs >> cfi->chipshift) { | 1365 | if (ofs >> cfi->chipshift) { |
1356 | chipnum ++; | 1366 | chipnum ++; |
1357 | ofs = 0; | 1367 | ofs = 0; |
1358 | if (chipnum == cfi->numchips) | 1368 | if (chipnum == cfi->numchips) |
1359 | return 0; | 1369 | return 0; |
@@ -1570,7 +1580,7 @@ int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
1570 | 1580 | ||
1571 | instr->state = MTD_ERASE_DONE; | 1581 | instr->state = MTD_ERASE_DONE; |
1572 | mtd_erase_callback(instr); | 1582 | mtd_erase_callback(instr); |
1573 | 1583 | ||
1574 | return 0; | 1584 | return 0; |
1575 | } | 1585 | } |
1576 | 1586 | ||
@@ -1593,7 +1603,7 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) | |||
1593 | 1603 | ||
1594 | instr->state = MTD_ERASE_DONE; | 1604 | instr->state = MTD_ERASE_DONE; |
1595 | mtd_erase_callback(instr); | 1605 | mtd_erase_callback(instr); |
1596 | 1606 | ||
1597 | return 0; | 1607 | return 0; |
1598 | } | 1608 | } |
1599 | 1609 | ||
@@ -1620,7 +1630,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) | |||
1620 | case FL_JEDEC_QUERY: | 1630 | case FL_JEDEC_QUERY: |
1621 | chip->oldstate = chip->state; | 1631 | chip->oldstate = chip->state; |
1622 | chip->state = FL_SYNCING; | 1632 | chip->state = FL_SYNCING; |
1623 | /* No need to wake_up() on this state change - | 1633 | /* No need to wake_up() on this state change - |
1624 | * as the whole point is that nobody can do anything | 1634 | * as the whole point is that nobody can do anything |
1625 | * with the chip now anyway. | 1635 | * with the chip now anyway. |
1626 | */ | 1636 | */ |
@@ -1631,13 +1641,13 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) | |||
1631 | default: | 1641 | default: |
1632 | /* Not an idle state */ | 1642 | /* Not an idle state */ |
1633 | add_wait_queue(&chip->wq, &wait); | 1643 | add_wait_queue(&chip->wq, &wait); |
1634 | 1644 | ||
1635 | spin_unlock(chip->mutex); | 1645 | spin_unlock(chip->mutex); |
1636 | 1646 | ||
1637 | schedule(); | 1647 | schedule(); |
1638 | 1648 | ||
1639 | remove_wait_queue(&chip->wq, &wait); | 1649 | remove_wait_queue(&chip->wq, &wait); |
1640 | 1650 | ||
1641 | goto retry; | 1651 | goto retry; |
1642 | } | 1652 | } |
1643 | } | 1653 | } |
@@ -1648,7 +1658,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) | |||
1648 | chip = &cfi->chips[i]; | 1658 | chip = &cfi->chips[i]; |
1649 | 1659 | ||
1650 | spin_lock(chip->mutex); | 1660 | spin_lock(chip->mutex); |
1651 | 1661 | ||
1652 | if (chip->state == FL_SYNCING) { | 1662 | if (chip->state == FL_SYNCING) { |
1653 | chip->state = chip->oldstate; | 1663 | chip->state = chip->oldstate; |
1654 | wake_up(&chip->wq); | 1664 | wake_up(&chip->wq); |
@@ -1678,7 +1688,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) | |||
1678 | case FL_JEDEC_QUERY: | 1688 | case FL_JEDEC_QUERY: |
1679 | chip->oldstate = chip->state; | 1689 | chip->oldstate = chip->state; |
1680 | chip->state = FL_PM_SUSPENDED; | 1690 | chip->state = FL_PM_SUSPENDED; |
1681 | /* No need to wake_up() on this state change - | 1691 | /* No need to wake_up() on this state change - |
1682 | * as the whole point is that nobody can do anything | 1692 | * as the whole point is that nobody can do anything |
1683 | * with the chip now anyway. | 1693 | * with the chip now anyway. |
1684 | */ | 1694 | */ |
@@ -1699,7 +1709,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) | |||
1699 | chip = &cfi->chips[i]; | 1709 | chip = &cfi->chips[i]; |
1700 | 1710 | ||
1701 | spin_lock(chip->mutex); | 1711 | spin_lock(chip->mutex); |
1702 | 1712 | ||
1703 | if (chip->state == FL_PM_SUSPENDED) { | 1713 | if (chip->state == FL_PM_SUSPENDED) { |
1704 | chip->state = chip->oldstate; | 1714 | chip->state = chip->oldstate; |
1705 | wake_up(&chip->wq); | 1715 | wake_up(&chip->wq); |
@@ -1707,7 +1717,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) | |||
1707 | spin_unlock(chip->mutex); | 1717 | spin_unlock(chip->mutex); |
1708 | } | 1718 | } |
1709 | } | 1719 | } |
1710 | 1720 | ||
1711 | return ret; | 1721 | return ret; |
1712 | } | 1722 | } |
1713 | 1723 | ||
@@ -1720,11 +1730,11 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) | |||
1720 | struct flchip *chip; | 1730 | struct flchip *chip; |
1721 | 1731 | ||
1722 | for (i=0; i<cfi->numchips; i++) { | 1732 | for (i=0; i<cfi->numchips; i++) { |
1723 | 1733 | ||
1724 | chip = &cfi->chips[i]; | 1734 | chip = &cfi->chips[i]; |
1725 | 1735 | ||
1726 | spin_lock(chip->mutex); | 1736 | spin_lock(chip->mutex); |
1727 | 1737 | ||
1728 | if (chip->state == FL_PM_SUSPENDED) { | 1738 | if (chip->state == FL_PM_SUSPENDED) { |
1729 | chip->state = FL_READY; | 1739 | chip->state = FL_READY; |
1730 | map_write(map, CMD(0xF0), chip->start); | 1740 | map_write(map, CMD(0xF0), chip->start); |
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index c894f8801578..c4a19d2dc67f 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
@@ -4,8 +4,8 @@ | |||
4 | * | 4 | * |
5 | * (C) 2000 Red Hat. GPL'd | 5 | * (C) 2000 Red Hat. GPL'd |
6 | * | 6 | * |
7 | * $Id: cfi_cmdset_0020.c,v 1.19 2005/07/13 15:52:45 dwmw2 Exp $ | 7 | * $Id: cfi_cmdset_0020.c,v 1.22 2005/11/07 11:14:22 gleixner Exp $ |
8 | * | 8 | * |
9 | * 10/10/2000 Nicolas Pitre <nico@cam.org> | 9 | * 10/10/2000 Nicolas Pitre <nico@cam.org> |
10 | * - completely revamped method functions so they are aware and | 10 | * - completely revamped method functions so they are aware and |
11 | * independent of the flash geometry (buswidth, interleave, etc.) | 11 | * independent of the flash geometry (buswidth, interleave, etc.) |
@@ -81,17 +81,17 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
81 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); | 81 | printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); |
82 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); | 82 | printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); |
83 | for (i=9; i<32; i++) { | 83 | for (i=9; i<32; i++) { |
84 | if (extp->FeatureSupport & (1<<i)) | 84 | if (extp->FeatureSupport & (1<<i)) |
85 | printk(" - Unknown Bit %X: supported\n", i); | 85 | printk(" - Unknown Bit %X: supported\n", i); |
86 | } | 86 | } |
87 | 87 | ||
88 | printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); | 88 | printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); |
89 | printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); | 89 | printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); |
90 | for (i=1; i<8; i++) { | 90 | for (i=1; i<8; i++) { |
91 | if (extp->SuspendCmdSupport & (1<<i)) | 91 | if (extp->SuspendCmdSupport & (1<<i)) |
92 | printk(" - Unknown Bit %X: supported\n", i); | 92 | printk(" - Unknown Bit %X: supported\n", i); |
93 | } | 93 | } |
94 | 94 | ||
95 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); | 95 | printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); |
96 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); | 96 | printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); |
97 | printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); | 97 | printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); |
@@ -99,11 +99,11 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
99 | if (extp->BlkStatusRegMask & (1<<i)) | 99 | if (extp->BlkStatusRegMask & (1<<i)) |
100 | printk(" - Unknown Bit %X Active: yes\n",i); | 100 | printk(" - Unknown Bit %X Active: yes\n",i); |
101 | } | 101 | } |
102 | 102 | ||
103 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", | 103 | printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", |
104 | extp->VccOptimal >> 8, extp->VccOptimal & 0xf); | 104 | extp->VccOptimal >> 8, extp->VccOptimal & 0xf); |
105 | if (extp->VppOptimal) | 105 | if (extp->VppOptimal) |
106 | printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", | 106 | printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", |
107 | extp->VppOptimal >> 8, extp->VppOptimal & 0xf); | 107 | extp->VppOptimal >> 8, extp->VppOptimal & 0xf); |
108 | } | 108 | } |
109 | #endif | 109 | #endif |
@@ -121,7 +121,7 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) | |||
121 | int i; | 121 | int i; |
122 | 122 | ||
123 | if (cfi->cfi_mode) { | 123 | if (cfi->cfi_mode) { |
124 | /* | 124 | /* |
125 | * It's a real CFI chip, not one for which the probe | 125 | * It's a real CFI chip, not one for which the probe |
126 | * routine faked a CFI structure. So we read the feature | 126 | * routine faked a CFI structure. So we read the feature |
127 | * table from it. | 127 | * table from it. |
@@ -133,24 +133,33 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) | |||
133 | if (!extp) | 133 | if (!extp) |
134 | return NULL; | 134 | return NULL; |
135 | 135 | ||
136 | if (extp->MajorVersion != '1' || | ||
137 | (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { | ||
138 | printk(KERN_ERR " Unknown ST Microelectronics" | ||
139 | " Extended Query version %c.%c.\n", | ||
140 | extp->MajorVersion, extp->MinorVersion); | ||
141 | kfree(extp); | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
136 | /* Do some byteswapping if necessary */ | 145 | /* Do some byteswapping if necessary */ |
137 | extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); | 146 | extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); |
138 | extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); | 147 | extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); |
139 | 148 | ||
140 | #ifdef DEBUG_CFI_FEATURES | 149 | #ifdef DEBUG_CFI_FEATURES |
141 | /* Tell the user about it in lots of lovely detail */ | 150 | /* Tell the user about it in lots of lovely detail */ |
142 | cfi_tell_features(extp); | 151 | cfi_tell_features(extp); |
143 | #endif | 152 | #endif |
144 | 153 | ||
145 | /* Install our own private info structure */ | 154 | /* Install our own private info structure */ |
146 | cfi->cmdset_priv = extp; | 155 | cfi->cmdset_priv = extp; |
147 | } | 156 | } |
148 | 157 | ||
149 | for (i=0; i< cfi->numchips; i++) { | 158 | for (i=0; i< cfi->numchips; i++) { |
150 | cfi->chips[i].word_write_time = 128; | 159 | cfi->chips[i].word_write_time = 128; |
151 | cfi->chips[i].buffer_write_time = 128; | 160 | cfi->chips[i].buffer_write_time = 128; |
152 | cfi->chips[i].erase_time = 1024; | 161 | cfi->chips[i].erase_time = 1024; |
153 | } | 162 | } |
154 | 163 | ||
155 | return cfi_staa_setup(map); | 164 | return cfi_staa_setup(map); |
156 | } | 165 | } |
@@ -178,15 +187,15 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) | |||
178 | mtd->size = devsize * cfi->numchips; | 187 | mtd->size = devsize * cfi->numchips; |
179 | 188 | ||
180 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; | 189 | mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; |
181 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) | 190 | mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) |
182 | * mtd->numeraseregions, GFP_KERNEL); | 191 | * mtd->numeraseregions, GFP_KERNEL); |
183 | if (!mtd->eraseregions) { | 192 | if (!mtd->eraseregions) { |
184 | printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); | 193 | printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); |
185 | kfree(cfi->cmdset_priv); | 194 | kfree(cfi->cmdset_priv); |
186 | kfree(mtd); | 195 | kfree(mtd); |
187 | return NULL; | 196 | return NULL; |
188 | } | 197 | } |
189 | 198 | ||
190 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { | 199 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { |
191 | unsigned long ernum, ersize; | 200 | unsigned long ernum, ersize; |
192 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; | 201 | ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; |
@@ -219,7 +228,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) | |||
219 | mtd->eraseregions[i].numblocks); | 228 | mtd->eraseregions[i].numblocks); |
220 | } | 229 | } |
221 | 230 | ||
222 | /* Also select the correct geometry setup too */ | 231 | /* Also select the correct geometry setup too */ |
223 | mtd->erase = cfi_staa_erase_varsize; | 232 | mtd->erase = cfi_staa_erase_varsize; |
224 | mtd->read = cfi_staa_read; | 233 | mtd->read = cfi_staa_read; |
225 | mtd->write = cfi_staa_write_buffers; | 234 | mtd->write = cfi_staa_write_buffers; |
@@ -250,8 +259,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
250 | 259 | ||
251 | adr += chip->start; | 260 | adr += chip->start; |
252 | 261 | ||
253 | /* Ensure cmd read/writes are aligned. */ | 262 | /* Ensure cmd read/writes are aligned. */ |
254 | cmd_addr = adr & ~(map_bankwidth(map)-1); | 263 | cmd_addr = adr & ~(map_bankwidth(map)-1); |
255 | 264 | ||
256 | /* Let's determine this according to the interleave only once */ | 265 | /* Let's determine this according to the interleave only once */ |
257 | status_OK = CMD(0x80); | 266 | status_OK = CMD(0x80); |
@@ -267,7 +276,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
267 | case FL_ERASING: | 276 | case FL_ERASING: |
268 | if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) | 277 | if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) |
269 | goto sleep; /* We don't support erase suspend */ | 278 | goto sleep; /* We don't support erase suspend */ |
270 | 279 | ||
271 | map_write (map, CMD(0xb0), cmd_addr); | 280 | map_write (map, CMD(0xb0), cmd_addr); |
272 | /* If the flash has finished erasing, then 'erase suspend' | 281 | /* If the flash has finished erasing, then 'erase suspend' |
273 | * appears to make some (28F320) flash devices switch to | 282 | * appears to make some (28F320) flash devices switch to |
@@ -282,7 +291,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
282 | status = map_read(map, cmd_addr); | 291 | status = map_read(map, cmd_addr); |
283 | if (map_word_andequal(map, status, status_OK, status_OK)) | 292 | if (map_word_andequal(map, status, status_OK, status_OK)) |
284 | break; | 293 | break; |
285 | 294 | ||
286 | if (time_after(jiffies, timeo)) { | 295 | if (time_after(jiffies, timeo)) { |
287 | /* Urgh */ | 296 | /* Urgh */ |
288 | map_write(map, CMD(0xd0), cmd_addr); | 297 | map_write(map, CMD(0xd0), cmd_addr); |
@@ -294,17 +303,17 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
294 | "suspended: status = 0x%lx\n", status.x[0]); | 303 | "suspended: status = 0x%lx\n", status.x[0]); |
295 | return -EIO; | 304 | return -EIO; |
296 | } | 305 | } |
297 | 306 | ||
298 | spin_unlock_bh(chip->mutex); | 307 | spin_unlock_bh(chip->mutex); |
299 | cfi_udelay(1); | 308 | cfi_udelay(1); |
300 | spin_lock_bh(chip->mutex); | 309 | spin_lock_bh(chip->mutex); |
301 | } | 310 | } |
302 | 311 | ||
303 | suspended = 1; | 312 | suspended = 1; |
304 | map_write(map, CMD(0xff), cmd_addr); | 313 | map_write(map, CMD(0xff), cmd_addr); |
305 | chip->state = FL_READY; | 314 | chip->state = FL_READY; |
306 | break; | 315 | break; |
307 | 316 | ||
308 | #if 0 | 317 | #if 0 |
309 | case FL_WRITING: | 318 | case FL_WRITING: |
310 | /* Not quite yet */ | 319 | /* Not quite yet */ |
@@ -325,7 +334,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
325 | chip->state = FL_READY; | 334 | chip->state = FL_READY; |
326 | break; | 335 | break; |
327 | } | 336 | } |
328 | 337 | ||
329 | /* Urgh. Chip not yet ready to talk to us. */ | 338 | /* Urgh. Chip not yet ready to talk to us. */ |
330 | if (time_after(jiffies, timeo)) { | 339 | if (time_after(jiffies, timeo)) { |
331 | spin_unlock_bh(chip->mutex); | 340 | spin_unlock_bh(chip->mutex); |
@@ -355,17 +364,17 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
355 | 364 | ||
356 | if (suspended) { | 365 | if (suspended) { |
357 | chip->state = chip->oldstate; | 366 | chip->state = chip->oldstate; |
358 | /* What if one interleaved chip has finished and the | 367 | /* What if one interleaved chip has finished and the |
359 | other hasn't? The old code would leave the finished | 368 | other hasn't? The old code would leave the finished |
360 | one in READY mode. That's bad, and caused -EROFS | 369 | one in READY mode. That's bad, and caused -EROFS |
361 | errors to be returned from do_erase_oneblock because | 370 | errors to be returned from do_erase_oneblock because |
362 | that's the only bit it checked for at the time. | 371 | that's the only bit it checked for at the time. |
363 | As the state machine appears to explicitly allow | 372 | As the state machine appears to explicitly allow |
364 | sending the 0x70 (Read Status) command to an erasing | 373 | sending the 0x70 (Read Status) command to an erasing |
365 | chip and expecting it to be ignored, that's what we | 374 | chip and expecting it to be ignored, that's what we |
366 | do. */ | 375 | do. */ |
367 | map_write(map, CMD(0xd0), cmd_addr); | 376 | map_write(map, CMD(0xd0), cmd_addr); |
368 | map_write(map, CMD(0x70), cmd_addr); | 377 | map_write(map, CMD(0x70), cmd_addr); |
369 | } | 378 | } |
370 | 379 | ||
371 | wake_up(&chip->wq); | 380 | wake_up(&chip->wq); |
@@ -405,14 +414,14 @@ static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
405 | *retlen += thislen; | 414 | *retlen += thislen; |
406 | len -= thislen; | 415 | len -= thislen; |
407 | buf += thislen; | 416 | buf += thislen; |
408 | 417 | ||
409 | ofs = 0; | 418 | ofs = 0; |
410 | chipnum++; | 419 | chipnum++; |
411 | } | 420 | } |
412 | return ret; | 421 | return ret; |
413 | } | 422 | } |
414 | 423 | ||
415 | static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | 424 | static inline int do_write_buffer(struct map_info *map, struct flchip *chip, |
416 | unsigned long adr, const u_char *buf, int len) | 425 | unsigned long adr, const u_char *buf, int len) |
417 | { | 426 | { |
418 | struct cfi_private *cfi = map->fldrv_priv; | 427 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -420,7 +429,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
420 | unsigned long cmd_adr, timeo; | 429 | unsigned long cmd_adr, timeo; |
421 | DECLARE_WAITQUEUE(wait, current); | 430 | DECLARE_WAITQUEUE(wait, current); |
422 | int wbufsize, z; | 431 | int wbufsize, z; |
423 | 432 | ||
424 | /* M58LW064A requires bus alignment for buffer wriets -- saw */ | 433 | /* M58LW064A requires bus alignment for buffer wriets -- saw */ |
425 | if (adr & (map_bankwidth(map)-1)) | 434 | if (adr & (map_bankwidth(map)-1)) |
426 | return -EINVAL; | 435 | return -EINVAL; |
@@ -428,10 +437,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
428 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; | 437 | wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; |
429 | adr += chip->start; | 438 | adr += chip->start; |
430 | cmd_adr = adr & ~(wbufsize-1); | 439 | cmd_adr = adr & ~(wbufsize-1); |
431 | 440 | ||
432 | /* Let's determine this according to the interleave only once */ | 441 | /* Let's determine this according to the interleave only once */ |
433 | status_OK = CMD(0x80); | 442 | status_OK = CMD(0x80); |
434 | 443 | ||
435 | timeo = jiffies + HZ; | 444 | timeo = jiffies + HZ; |
436 | retry: | 445 | retry: |
437 | 446 | ||
@@ -439,7 +448,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
439 | printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state); | 448 | printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state); |
440 | #endif | 449 | #endif |
441 | spin_lock_bh(chip->mutex); | 450 | spin_lock_bh(chip->mutex); |
442 | 451 | ||
443 | /* Check that the chip's ready to talk to us. | 452 | /* Check that the chip's ready to talk to us. |
444 | * Later, we can actually think about interrupting it | 453 | * Later, we can actually think about interrupting it |
445 | * if it's in FL_ERASING state. | 454 | * if it's in FL_ERASING state. |
@@ -448,7 +457,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
448 | switch (chip->state) { | 457 | switch (chip->state) { |
449 | case FL_READY: | 458 | case FL_READY: |
450 | break; | 459 | break; |
451 | 460 | ||
452 | case FL_CFI_QUERY: | 461 | case FL_CFI_QUERY: |
453 | case FL_JEDEC_QUERY: | 462 | case FL_JEDEC_QUERY: |
454 | map_write(map, CMD(0x70), cmd_adr); | 463 | map_write(map, CMD(0x70), cmd_adr); |
@@ -513,7 +522,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
513 | 522 | ||
514 | /* Write length of data to come */ | 523 | /* Write length of data to come */ |
515 | map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr ); | 524 | map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr ); |
516 | 525 | ||
517 | /* Write data */ | 526 | /* Write data */ |
518 | for (z = 0; z < len; | 527 | for (z = 0; z < len; |
519 | z += map_bankwidth(map), buf += map_bankwidth(map)) { | 528 | z += map_bankwidth(map), buf += map_bankwidth(map)) { |
@@ -560,7 +569,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
560 | printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); | 569 | printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); |
561 | return -EIO; | 570 | return -EIO; |
562 | } | 571 | } |
563 | 572 | ||
564 | /* Latency issues. Drop the lock, wait a while and retry */ | 573 | /* Latency issues. Drop the lock, wait a while and retry */ |
565 | spin_unlock_bh(chip->mutex); | 574 | spin_unlock_bh(chip->mutex); |
566 | cfi_udelay(1); | 575 | cfi_udelay(1); |
@@ -572,9 +581,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
572 | if (!chip->buffer_write_time) | 581 | if (!chip->buffer_write_time) |
573 | chip->buffer_write_time++; | 582 | chip->buffer_write_time++; |
574 | } | 583 | } |
575 | if (z > 1) | 584 | if (z > 1) |
576 | chip->buffer_write_time++; | 585 | chip->buffer_write_time++; |
577 | 586 | ||
578 | /* Done and happy. */ | 587 | /* Done and happy. */ |
579 | DISABLE_VPP(map); | 588 | DISABLE_VPP(map); |
580 | chip->state = FL_STATUS; | 589 | chip->state = FL_STATUS; |
@@ -598,7 +607,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, | |||
598 | return 0; | 607 | return 0; |
599 | } | 608 | } |
600 | 609 | ||
601 | static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | 610 | static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, |
602 | size_t len, size_t *retlen, const u_char *buf) | 611 | size_t len, size_t *retlen, const u_char *buf) |
603 | { | 612 | { |
604 | struct map_info *map = mtd->priv; | 613 | struct map_info *map = mtd->priv; |
@@ -620,7 +629,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | |||
620 | printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize); | 629 | printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize); |
621 | printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len); | 630 | printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len); |
622 | #endif | 631 | #endif |
623 | 632 | ||
624 | /* Write buffer is worth it only if more than one word to write... */ | 633 | /* Write buffer is worth it only if more than one word to write... */ |
625 | while (len > 0) { | 634 | while (len > 0) { |
626 | /* We must not cross write block boundaries */ | 635 | /* We must not cross write block boundaries */ |
@@ -629,7 +638,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | |||
629 | if (size > len) | 638 | if (size > len) |
630 | size = len; | 639 | size = len; |
631 | 640 | ||
632 | ret = do_write_buffer(map, &cfi->chips[chipnum], | 641 | ret = do_write_buffer(map, &cfi->chips[chipnum], |
633 | ofs, buf, size); | 642 | ofs, buf, size); |
634 | if (ret) | 643 | if (ret) |
635 | return ret; | 644 | return ret; |
@@ -640,13 +649,13 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, | |||
640 | len -= size; | 649 | len -= size; |
641 | 650 | ||
642 | if (ofs >> cfi->chipshift) { | 651 | if (ofs >> cfi->chipshift) { |
643 | chipnum ++; | 652 | chipnum ++; |
644 | ofs = 0; | 653 | ofs = 0; |
645 | if (chipnum == cfi->numchips) | 654 | if (chipnum == cfi->numchips) |
646 | return 0; | 655 | return 0; |
647 | } | 656 | } |
648 | } | 657 | } |
649 | 658 | ||
650 | return 0; | 659 | return 0; |
651 | } | 660 | } |
652 | 661 | ||
@@ -756,7 +765,7 @@ retry: | |||
756 | status = map_read(map, adr); | 765 | status = map_read(map, adr); |
757 | if (map_word_andequal(map, status, status_OK, status_OK)) | 766 | if (map_word_andequal(map, status, status_OK, status_OK)) |
758 | break; | 767 | break; |
759 | 768 | ||
760 | /* Urgh. Chip not yet ready to talk to us. */ | 769 | /* Urgh. Chip not yet ready to talk to us. */ |
761 | if (time_after(jiffies, timeo)) { | 770 | if (time_after(jiffies, timeo)) { |
762 | spin_unlock_bh(chip->mutex); | 771 | spin_unlock_bh(chip->mutex); |
@@ -789,7 +798,7 @@ retry: | |||
789 | map_write(map, CMD(0x20), adr); | 798 | map_write(map, CMD(0x20), adr); |
790 | map_write(map, CMD(0xD0), adr); | 799 | map_write(map, CMD(0xD0), adr); |
791 | chip->state = FL_ERASING; | 800 | chip->state = FL_ERASING; |
792 | 801 | ||
793 | spin_unlock_bh(chip->mutex); | 802 | spin_unlock_bh(chip->mutex); |
794 | msleep(1000); | 803 | msleep(1000); |
795 | spin_lock_bh(chip->mutex); | 804 | spin_lock_bh(chip->mutex); |
@@ -814,7 +823,7 @@ retry: | |||
814 | status = map_read(map, adr); | 823 | status = map_read(map, adr); |
815 | if (map_word_andequal(map, status, status_OK, status_OK)) | 824 | if (map_word_andequal(map, status, status_OK, status_OK)) |
816 | break; | 825 | break; |
817 | 826 | ||
818 | /* OK Still waiting */ | 827 | /* OK Still waiting */ |
819 | if (time_after(jiffies, timeo)) { | 828 | if (time_after(jiffies, timeo)) { |
820 | map_write(map, CMD(0x70), adr); | 829 | map_write(map, CMD(0x70), adr); |
@@ -824,13 +833,13 @@ retry: | |||
824 | spin_unlock_bh(chip->mutex); | 833 | spin_unlock_bh(chip->mutex); |
825 | return -EIO; | 834 | return -EIO; |
826 | } | 835 | } |
827 | 836 | ||
828 | /* Latency issues. Drop the lock, wait a while and retry */ | 837 | /* Latency issues. Drop the lock, wait a while and retry */ |
829 | spin_unlock_bh(chip->mutex); | 838 | spin_unlock_bh(chip->mutex); |
830 | cfi_udelay(1); | 839 | cfi_udelay(1); |
831 | spin_lock_bh(chip->mutex); | 840 | spin_lock_bh(chip->mutex); |
832 | } | 841 | } |
833 | 842 | ||
834 | DISABLE_VPP(map); | 843 | DISABLE_VPP(map); |
835 | ret = 0; | 844 | ret = 0; |
836 | 845 | ||
@@ -855,7 +864,7 @@ retry: | |||
855 | /* Reset the error bits */ | 864 | /* Reset the error bits */ |
856 | map_write(map, CMD(0x50), adr); | 865 | map_write(map, CMD(0x50), adr); |
857 | map_write(map, CMD(0x70), adr); | 866 | map_write(map, CMD(0x70), adr); |
858 | 867 | ||
859 | if ((chipstatus & 0x30) == 0x30) { | 868 | if ((chipstatus & 0x30) == 0x30) { |
860 | printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); | 869 | printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); |
861 | ret = -EIO; | 870 | ret = -EIO; |
@@ -904,17 +913,17 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
904 | 913 | ||
905 | i = 0; | 914 | i = 0; |
906 | 915 | ||
907 | /* Skip all erase regions which are ended before the start of | 916 | /* Skip all erase regions which are ended before the start of |
908 | the requested erase. Actually, to save on the calculations, | 917 | the requested erase. Actually, to save on the calculations, |
909 | we skip to the first erase region which starts after the | 918 | we skip to the first erase region which starts after the |
910 | start of the requested erase, and then go back one. | 919 | start of the requested erase, and then go back one. |
911 | */ | 920 | */ |
912 | 921 | ||
913 | while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) | 922 | while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) |
914 | i++; | 923 | i++; |
915 | i--; | 924 | i--; |
916 | 925 | ||
917 | /* OK, now i is pointing at the erase region in which this | 926 | /* OK, now i is pointing at the erase region in which this |
918 | erase request starts. Check the start of the requested | 927 | erase request starts. Check the start of the requested |
919 | erase range is aligned with the erase size which is in | 928 | erase range is aligned with the erase size which is in |
920 | effect here. | 929 | effect here. |
@@ -937,7 +946,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
937 | the address actually falls | 946 | the address actually falls |
938 | */ | 947 | */ |
939 | i--; | 948 | i--; |
940 | 949 | ||
941 | if ((instr->addr + instr->len) & (regions[i].erasesize-1)) | 950 | if ((instr->addr + instr->len) & (regions[i].erasesize-1)) |
942 | return -EINVAL; | 951 | return -EINVAL; |
943 | 952 | ||
@@ -949,7 +958,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
949 | 958 | ||
950 | while(len) { | 959 | while(len) { |
951 | ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); | 960 | ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); |
952 | 961 | ||
953 | if (ret) | 962 | if (ret) |
954 | return ret; | 963 | return ret; |
955 | 964 | ||
@@ -962,15 +971,15 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) | |||
962 | if (adr >> cfi->chipshift) { | 971 | if (adr >> cfi->chipshift) { |
963 | adr = 0; | 972 | adr = 0; |
964 | chipnum++; | 973 | chipnum++; |
965 | 974 | ||
966 | if (chipnum >= cfi->numchips) | 975 | if (chipnum >= cfi->numchips) |
967 | break; | 976 | break; |
968 | } | 977 | } |
969 | } | 978 | } |
970 | 979 | ||
971 | instr->state = MTD_ERASE_DONE; | 980 | instr->state = MTD_ERASE_DONE; |
972 | mtd_erase_callback(instr); | 981 | mtd_erase_callback(instr); |
973 | 982 | ||
974 | return 0; | 983 | return 0; |
975 | } | 984 | } |
976 | 985 | ||
@@ -996,7 +1005,7 @@ static void cfi_staa_sync (struct mtd_info *mtd) | |||
996 | case FL_JEDEC_QUERY: | 1005 | case FL_JEDEC_QUERY: |
997 | chip->oldstate = chip->state; | 1006 | chip->oldstate = chip->state; |
998 | chip->state = FL_SYNCING; | 1007 | chip->state = FL_SYNCING; |
999 | /* No need to wake_up() on this state change - | 1008 | /* No need to wake_up() on this state change - |
1000 | * as the whole point is that nobody can do anything | 1009 | * as the whole point is that nobody can do anything |
1001 | * with the chip now anyway. | 1010 | * with the chip now anyway. |
1002 | */ | 1011 | */ |
@@ -1007,11 +1016,11 @@ static void cfi_staa_sync (struct mtd_info *mtd) | |||
1007 | default: | 1016 | default: |
1008 | /* Not an idle state */ | 1017 | /* Not an idle state */ |
1009 | add_wait_queue(&chip->wq, &wait); | 1018 | add_wait_queue(&chip->wq, &wait); |
1010 | 1019 | ||
1011 | spin_unlock_bh(chip->mutex); | 1020 | spin_unlock_bh(chip->mutex); |
1012 | schedule(); | 1021 | schedule(); |
1013 | remove_wait_queue(&chip->wq, &wait); | 1022 | remove_wait_queue(&chip->wq, &wait); |
1014 | 1023 | ||
1015 | goto retry; | 1024 | goto retry; |
1016 | } | 1025 | } |
1017 | } | 1026 | } |
@@ -1022,7 +1031,7 @@ static void cfi_staa_sync (struct mtd_info *mtd) | |||
1022 | chip = &cfi->chips[i]; | 1031 | chip = &cfi->chips[i]; |
1023 | 1032 | ||
1024 | spin_lock_bh(chip->mutex); | 1033 | spin_lock_bh(chip->mutex); |
1025 | 1034 | ||
1026 | if (chip->state == FL_SYNCING) { | 1035 | if (chip->state == FL_SYNCING) { |
1027 | chip->state = chip->oldstate; | 1036 | chip->state = chip->oldstate; |
1028 | wake_up(&chip->wq); | 1037 | wake_up(&chip->wq); |
@@ -1057,9 +1066,9 @@ retry: | |||
1057 | 1066 | ||
1058 | case FL_STATUS: | 1067 | case FL_STATUS: |
1059 | status = map_read(map, adr); | 1068 | status = map_read(map, adr); |
1060 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1069 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1061 | break; | 1070 | break; |
1062 | 1071 | ||
1063 | /* Urgh. Chip not yet ready to talk to us. */ | 1072 | /* Urgh. Chip not yet ready to talk to us. */ |
1064 | if (time_after(jiffies, timeo)) { | 1073 | if (time_after(jiffies, timeo)) { |
1065 | spin_unlock_bh(chip->mutex); | 1074 | spin_unlock_bh(chip->mutex); |
@@ -1088,7 +1097,7 @@ retry: | |||
1088 | map_write(map, CMD(0x60), adr); | 1097 | map_write(map, CMD(0x60), adr); |
1089 | map_write(map, CMD(0x01), adr); | 1098 | map_write(map, CMD(0x01), adr); |
1090 | chip->state = FL_LOCKING; | 1099 | chip->state = FL_LOCKING; |
1091 | 1100 | ||
1092 | spin_unlock_bh(chip->mutex); | 1101 | spin_unlock_bh(chip->mutex); |
1093 | msleep(1000); | 1102 | msleep(1000); |
1094 | spin_lock_bh(chip->mutex); | 1103 | spin_lock_bh(chip->mutex); |
@@ -1102,7 +1111,7 @@ retry: | |||
1102 | status = map_read(map, adr); | 1111 | status = map_read(map, adr); |
1103 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1112 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1104 | break; | 1113 | break; |
1105 | 1114 | ||
1106 | /* OK Still waiting */ | 1115 | /* OK Still waiting */ |
1107 | if (time_after(jiffies, timeo)) { | 1116 | if (time_after(jiffies, timeo)) { |
1108 | map_write(map, CMD(0x70), adr); | 1117 | map_write(map, CMD(0x70), adr); |
@@ -1112,13 +1121,13 @@ retry: | |||
1112 | spin_unlock_bh(chip->mutex); | 1121 | spin_unlock_bh(chip->mutex); |
1113 | return -EIO; | 1122 | return -EIO; |
1114 | } | 1123 | } |
1115 | 1124 | ||
1116 | /* Latency issues. Drop the lock, wait a while and retry */ | 1125 | /* Latency issues. Drop the lock, wait a while and retry */ |
1117 | spin_unlock_bh(chip->mutex); | 1126 | spin_unlock_bh(chip->mutex); |
1118 | cfi_udelay(1); | 1127 | cfi_udelay(1); |
1119 | spin_lock_bh(chip->mutex); | 1128 | spin_lock_bh(chip->mutex); |
1120 | } | 1129 | } |
1121 | 1130 | ||
1122 | /* Done and happy. */ | 1131 | /* Done and happy. */ |
1123 | chip->state = FL_STATUS; | 1132 | chip->state = FL_STATUS; |
1124 | DISABLE_VPP(map); | 1133 | DISABLE_VPP(map); |
@@ -1162,8 +1171,8 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1162 | cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); | 1171 | cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); |
1163 | printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); | 1172 | printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); |
1164 | cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); | 1173 | cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); |
1165 | #endif | 1174 | #endif |
1166 | 1175 | ||
1167 | if (ret) | 1176 | if (ret) |
1168 | return ret; | 1177 | return ret; |
1169 | 1178 | ||
@@ -1173,7 +1182,7 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1173 | if (adr >> cfi->chipshift) { | 1182 | if (adr >> cfi->chipshift) { |
1174 | adr = 0; | 1183 | adr = 0; |
1175 | chipnum++; | 1184 | chipnum++; |
1176 | 1185 | ||
1177 | if (chipnum >= cfi->numchips) | 1186 | if (chipnum >= cfi->numchips) |
1178 | break; | 1187 | break; |
1179 | } | 1188 | } |
@@ -1208,7 +1217,7 @@ retry: | |||
1208 | status = map_read(map, adr); | 1217 | status = map_read(map, adr); |
1209 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1218 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1210 | break; | 1219 | break; |
1211 | 1220 | ||
1212 | /* Urgh. Chip not yet ready to talk to us. */ | 1221 | /* Urgh. Chip not yet ready to talk to us. */ |
1213 | if (time_after(jiffies, timeo)) { | 1222 | if (time_after(jiffies, timeo)) { |
1214 | spin_unlock_bh(chip->mutex); | 1223 | spin_unlock_bh(chip->mutex); |
@@ -1237,7 +1246,7 @@ retry: | |||
1237 | map_write(map, CMD(0x60), adr); | 1246 | map_write(map, CMD(0x60), adr); |
1238 | map_write(map, CMD(0xD0), adr); | 1247 | map_write(map, CMD(0xD0), adr); |
1239 | chip->state = FL_UNLOCKING; | 1248 | chip->state = FL_UNLOCKING; |
1240 | 1249 | ||
1241 | spin_unlock_bh(chip->mutex); | 1250 | spin_unlock_bh(chip->mutex); |
1242 | msleep(1000); | 1251 | msleep(1000); |
1243 | spin_lock_bh(chip->mutex); | 1252 | spin_lock_bh(chip->mutex); |
@@ -1251,7 +1260,7 @@ retry: | |||
1251 | status = map_read(map, adr); | 1260 | status = map_read(map, adr); |
1252 | if (map_word_andequal(map, status, status_OK, status_OK)) | 1261 | if (map_word_andequal(map, status, status_OK, status_OK)) |
1253 | break; | 1262 | break; |
1254 | 1263 | ||
1255 | /* OK Still waiting */ | 1264 | /* OK Still waiting */ |
1256 | if (time_after(jiffies, timeo)) { | 1265 | if (time_after(jiffies, timeo)) { |
1257 | map_write(map, CMD(0x70), adr); | 1266 | map_write(map, CMD(0x70), adr); |
@@ -1261,13 +1270,13 @@ retry: | |||
1261 | spin_unlock_bh(chip->mutex); | 1270 | spin_unlock_bh(chip->mutex); |
1262 | return -EIO; | 1271 | return -EIO; |
1263 | } | 1272 | } |
1264 | 1273 | ||
1265 | /* Latency issues. Drop the unlock, wait a while and retry */ | 1274 | /* Latency issues. Drop the unlock, wait a while and retry */ |
1266 | spin_unlock_bh(chip->mutex); | 1275 | spin_unlock_bh(chip->mutex); |
1267 | cfi_udelay(1); | 1276 | cfi_udelay(1); |
1268 | spin_lock_bh(chip->mutex); | 1277 | spin_lock_bh(chip->mutex); |
1269 | } | 1278 | } |
1270 | 1279 | ||
1271 | /* Done and happy. */ | 1280 | /* Done and happy. */ |
1272 | chip->state = FL_STATUS; | 1281 | chip->state = FL_STATUS; |
1273 | DISABLE_VPP(map); | 1282 | DISABLE_VPP(map); |
@@ -1292,7 +1301,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1292 | { | 1301 | { |
1293 | unsigned long temp_adr = adr; | 1302 | unsigned long temp_adr = adr; |
1294 | unsigned long temp_len = len; | 1303 | unsigned long temp_len = len; |
1295 | 1304 | ||
1296 | cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); | 1305 | cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); |
1297 | while (temp_len) { | 1306 | while (temp_len) { |
1298 | printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); | 1307 | printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); |
@@ -1310,7 +1319,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1310 | printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); | 1319 | printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); |
1311 | cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); | 1320 | cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); |
1312 | #endif | 1321 | #endif |
1313 | 1322 | ||
1314 | return ret; | 1323 | return ret; |
1315 | } | 1324 | } |
1316 | 1325 | ||
@@ -1334,7 +1343,7 @@ static int cfi_staa_suspend(struct mtd_info *mtd) | |||
1334 | case FL_JEDEC_QUERY: | 1343 | case FL_JEDEC_QUERY: |
1335 | chip->oldstate = chip->state; | 1344 | chip->oldstate = chip->state; |
1336 | chip->state = FL_PM_SUSPENDED; | 1345 | chip->state = FL_PM_SUSPENDED; |
1337 | /* No need to wake_up() on this state change - | 1346 | /* No need to wake_up() on this state change - |
1338 | * as the whole point is that nobody can do anything | 1347 | * as the whole point is that nobody can do anything |
1339 | * with the chip now anyway. | 1348 | * with the chip now anyway. |
1340 | */ | 1349 | */ |
@@ -1353,9 +1362,9 @@ static int cfi_staa_suspend(struct mtd_info *mtd) | |||
1353 | if (ret) { | 1362 | if (ret) { |
1354 | for (i--; i >=0; i--) { | 1363 | for (i--; i >=0; i--) { |
1355 | chip = &cfi->chips[i]; | 1364 | chip = &cfi->chips[i]; |
1356 | 1365 | ||
1357 | spin_lock_bh(chip->mutex); | 1366 | spin_lock_bh(chip->mutex); |
1358 | 1367 | ||
1359 | if (chip->state == FL_PM_SUSPENDED) { | 1368 | if (chip->state == FL_PM_SUSPENDED) { |
1360 | /* No need to force it into a known state here, | 1369 | /* No need to force it into a known state here, |
1361 | because we're returning failure, and it didn't | 1370 | because we're returning failure, and it didn't |
@@ -1365,8 +1374,8 @@ static int cfi_staa_suspend(struct mtd_info *mtd) | |||
1365 | } | 1374 | } |
1366 | spin_unlock_bh(chip->mutex); | 1375 | spin_unlock_bh(chip->mutex); |
1367 | } | 1376 | } |
1368 | } | 1377 | } |
1369 | 1378 | ||
1370 | return ret; | 1379 | return ret; |
1371 | } | 1380 | } |
1372 | 1381 | ||
@@ -1378,11 +1387,11 @@ static void cfi_staa_resume(struct mtd_info *mtd) | |||
1378 | struct flchip *chip; | 1387 | struct flchip *chip; |
1379 | 1388 | ||
1380 | for (i=0; i<cfi->numchips; i++) { | 1389 | for (i=0; i<cfi->numchips; i++) { |
1381 | 1390 | ||
1382 | chip = &cfi->chips[i]; | 1391 | chip = &cfi->chips[i]; |
1383 | 1392 | ||
1384 | spin_lock_bh(chip->mutex); | 1393 | spin_lock_bh(chip->mutex); |
1385 | 1394 | ||
1386 | /* Go to known state. Chip may have been power cycled */ | 1395 | /* Go to known state. Chip may have been power cycled */ |
1387 | if (chip->state == FL_PM_SUSPENDED) { | 1396 | if (chip->state == FL_PM_SUSPENDED) { |
1388 | map_write(map, CMD(0xFF), 0); | 1397 | map_write(map, CMD(0xFF), 0); |
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index cf750038ce6a..90eb30e06b7c 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | Common Flash Interface probe code. | 2 | Common Flash Interface probe code. |
3 | (C) 2000 Red Hat. GPL'd. | 3 | (C) 2000 Red Hat. GPL'd. |
4 | $Id: cfi_probe.c,v 1.83 2004/11/16 18:19:02 nico Exp $ | 4 | $Id: cfi_probe.c,v 1.84 2005/11/07 11:14:23 gleixner Exp $ |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/config.h> | 7 | #include <linux/config.h> |
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/mtd/cfi.h> | 20 | #include <linux/mtd/cfi.h> |
21 | #include <linux/mtd/gen_probe.h> | 21 | #include <linux/mtd/gen_probe.h> |
22 | 22 | ||
23 | //#define DEBUG_CFI | 23 | //#define DEBUG_CFI |
24 | 24 | ||
25 | #ifdef DEBUG_CFI | 25 | #ifdef DEBUG_CFI |
26 | static void print_cfi_ident(struct cfi_ident *); | 26 | static void print_cfi_ident(struct cfi_ident *); |
@@ -103,7 +103,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
103 | unsigned long *chip_map, struct cfi_private *cfi) | 103 | unsigned long *chip_map, struct cfi_private *cfi) |
104 | { | 104 | { |
105 | int i; | 105 | int i; |
106 | 106 | ||
107 | if ((base + 0) >= map->size) { | 107 | if ((base + 0) >= map->size) { |
108 | printk(KERN_NOTICE | 108 | printk(KERN_NOTICE |
109 | "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n", | 109 | "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n", |
@@ -128,7 +128,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
128 | } | 128 | } |
129 | 129 | ||
130 | if (!cfi->numchips) { | 130 | if (!cfi->numchips) { |
131 | /* This is the first time we're called. Set up the CFI | 131 | /* This is the first time we're called. Set up the CFI |
132 | stuff accordingly and return */ | 132 | stuff accordingly and return */ |
133 | return cfi_chip_setup(map, cfi); | 133 | return cfi_chip_setup(map, cfi); |
134 | } | 134 | } |
@@ -138,13 +138,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
138 | unsigned long start; | 138 | unsigned long start; |
139 | if(!test_bit(i, chip_map)) { | 139 | if(!test_bit(i, chip_map)) { |
140 | /* Skip location; no valid chip at this address */ | 140 | /* Skip location; no valid chip at this address */ |
141 | continue; | 141 | continue; |
142 | } | 142 | } |
143 | start = i << cfi->chipshift; | 143 | start = i << cfi->chipshift; |
144 | /* This chip should be in read mode if it's one | 144 | /* This chip should be in read mode if it's one |
145 | we've already touched. */ | 145 | we've already touched. */ |
146 | if (qry_present(map, start, cfi)) { | 146 | if (qry_present(map, start, cfi)) { |
147 | /* Eep. This chip also had the QRY marker. | 147 | /* Eep. This chip also had the QRY marker. |
148 | * Is it an alias for the new one? */ | 148 | * Is it an alias for the new one? */ |
149 | cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); | 149 | cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); |
150 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); | 150 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); |
@@ -156,13 +156,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
156 | map->name, base, start); | 156 | map->name, base, start); |
157 | return 0; | 157 | return 0; |
158 | } | 158 | } |
159 | /* Yes, it's actually got QRY for data. Most | 159 | /* Yes, it's actually got QRY for data. Most |
160 | * unfortunate. Stick the new chip in read mode | 160 | * unfortunate. Stick the new chip in read mode |
161 | * too and if it's the same, assume it's an alias. */ | 161 | * too and if it's the same, assume it's an alias. */ |
162 | /* FIXME: Use other modes to do a proper check */ | 162 | /* FIXME: Use other modes to do a proper check */ |
163 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 163 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); |
164 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); | 164 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); |
165 | 165 | ||
166 | if (qry_present(map, base, cfi)) { | 166 | if (qry_present(map, base, cfi)) { |
167 | xip_allowed(base, map); | 167 | xip_allowed(base, map); |
168 | printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", | 168 | printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", |
@@ -171,12 +171,12 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
171 | } | 171 | } |
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | /* OK, if we got to here, then none of the previous chips appear to | 175 | /* OK, if we got to here, then none of the previous chips appear to |
176 | be aliases for the current one. */ | 176 | be aliases for the current one. */ |
177 | set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ | 177 | set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ |
178 | cfi->numchips++; | 178 | cfi->numchips++; |
179 | 179 | ||
180 | /* Put it back into Read Mode */ | 180 | /* Put it back into Read Mode */ |
181 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 181 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); |
182 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | 182 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); |
@@ -185,11 +185,11 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
185 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", | 185 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", |
186 | map->name, cfi->interleave, cfi->device_type*8, base, | 186 | map->name, cfi->interleave, cfi->device_type*8, base, |
187 | map->bankwidth*8); | 187 | map->bankwidth*8); |
188 | 188 | ||
189 | return 1; | 189 | return 1; |
190 | } | 190 | } |
191 | 191 | ||
192 | static int __xipram cfi_chip_setup(struct map_info *map, | 192 | static int __xipram cfi_chip_setup(struct map_info *map, |
193 | struct cfi_private *cfi) | 193 | struct cfi_private *cfi) |
194 | { | 194 | { |
195 | int ofs_factor = cfi->interleave*cfi->device_type; | 195 | int ofs_factor = cfi->interleave*cfi->device_type; |
@@ -209,11 +209,11 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
209 | printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); | 209 | printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); |
210 | return 0; | 210 | return 0; |
211 | } | 211 | } |
212 | 212 | ||
213 | memset(cfi->cfiq,0,sizeof(struct cfi_ident)); | 213 | memset(cfi->cfiq,0,sizeof(struct cfi_ident)); |
214 | 214 | ||
215 | cfi->cfi_mode = CFI_MODE_CFI; | 215 | cfi->cfi_mode = CFI_MODE_CFI; |
216 | 216 | ||
217 | /* Read the CFI info structure */ | 217 | /* Read the CFI info structure */ |
218 | xip_disable_qry(base, map, cfi); | 218 | xip_disable_qry(base, map, cfi); |
219 | for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) | 219 | for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) |
@@ -231,7 +231,7 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
231 | cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); | 231 | cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); |
232 | cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); | 232 | cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); |
233 | cfi->mfr = cfi_read_query(map, base); | 233 | cfi->mfr = cfi_read_query(map, base); |
234 | cfi->id = cfi_read_query(map, base + ofs_factor); | 234 | cfi->id = cfi_read_query(map, base + ofs_factor); |
235 | 235 | ||
236 | /* Put it back into Read Mode */ | 236 | /* Put it back into Read Mode */ |
237 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 237 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); |
@@ -255,10 +255,10 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
255 | 255 | ||
256 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { | 256 | for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { |
257 | cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]); | 257 | cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]); |
258 | 258 | ||
259 | #ifdef DEBUG_CFI | 259 | #ifdef DEBUG_CFI |
260 | printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n", | 260 | printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n", |
261 | i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, | 261 | i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, |
262 | (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); | 262 | (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); |
263 | #endif | 263 | #endif |
264 | } | 264 | } |
@@ -271,33 +271,33 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
271 | } | 271 | } |
272 | 272 | ||
273 | #ifdef DEBUG_CFI | 273 | #ifdef DEBUG_CFI |
274 | static char *vendorname(__u16 vendor) | 274 | static char *vendorname(__u16 vendor) |
275 | { | 275 | { |
276 | switch (vendor) { | 276 | switch (vendor) { |
277 | case P_ID_NONE: | 277 | case P_ID_NONE: |
278 | return "None"; | 278 | return "None"; |
279 | 279 | ||
280 | case P_ID_INTEL_EXT: | 280 | case P_ID_INTEL_EXT: |
281 | return "Intel/Sharp Extended"; | 281 | return "Intel/Sharp Extended"; |
282 | 282 | ||
283 | case P_ID_AMD_STD: | 283 | case P_ID_AMD_STD: |
284 | return "AMD/Fujitsu Standard"; | 284 | return "AMD/Fujitsu Standard"; |
285 | 285 | ||
286 | case P_ID_INTEL_STD: | 286 | case P_ID_INTEL_STD: |
287 | return "Intel/Sharp Standard"; | 287 | return "Intel/Sharp Standard"; |
288 | 288 | ||
289 | case P_ID_AMD_EXT: | 289 | case P_ID_AMD_EXT: |
290 | return "AMD/Fujitsu Extended"; | 290 | return "AMD/Fujitsu Extended"; |
291 | 291 | ||
292 | case P_ID_WINBOND: | 292 | case P_ID_WINBOND: |
293 | return "Winbond Standard"; | 293 | return "Winbond Standard"; |
294 | 294 | ||
295 | case P_ID_ST_ADV: | 295 | case P_ID_ST_ADV: |
296 | return "ST Advanced"; | 296 | return "ST Advanced"; |
297 | 297 | ||
298 | case P_ID_MITSUBISHI_STD: | 298 | case P_ID_MITSUBISHI_STD: |
299 | return "Mitsubishi Standard"; | 299 | return "Mitsubishi Standard"; |
300 | 300 | ||
301 | case P_ID_MITSUBISHI_EXT: | 301 | case P_ID_MITSUBISHI_EXT: |
302 | return "Mitsubishi Extended"; | 302 | return "Mitsubishi Extended"; |
303 | 303 | ||
@@ -306,13 +306,13 @@ static char *vendorname(__u16 vendor) | |||
306 | 306 | ||
307 | case P_ID_INTEL_PERFORMANCE: | 307 | case P_ID_INTEL_PERFORMANCE: |
308 | return "Intel Performance Code"; | 308 | return "Intel Performance Code"; |
309 | 309 | ||
310 | case P_ID_INTEL_DATA: | 310 | case P_ID_INTEL_DATA: |
311 | return "Intel Data"; | 311 | return "Intel Data"; |
312 | 312 | ||
313 | case P_ID_RESERVED: | 313 | case P_ID_RESERVED: |
314 | return "Not Allowed / Reserved for Future Use"; | 314 | return "Not Allowed / Reserved for Future Use"; |
315 | 315 | ||
316 | default: | 316 | default: |
317 | return "Unknown"; | 317 | return "Unknown"; |
318 | } | 318 | } |
@@ -325,21 +325,21 @@ static void print_cfi_ident(struct cfi_ident *cfip) | |||
325 | if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') { | 325 | if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') { |
326 | printk("Invalid CFI ident structure.\n"); | 326 | printk("Invalid CFI ident structure.\n"); |
327 | return; | 327 | return; |
328 | } | 328 | } |
329 | #endif | 329 | #endif |
330 | printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID)); | 330 | printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID)); |
331 | if (cfip->P_ADR) | 331 | if (cfip->P_ADR) |
332 | printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR); | 332 | printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR); |
333 | else | 333 | else |
334 | printk("No Primary Algorithm Table\n"); | 334 | printk("No Primary Algorithm Table\n"); |
335 | 335 | ||
336 | printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID)); | 336 | printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID)); |
337 | if (cfip->A_ADR) | 337 | if (cfip->A_ADR) |
338 | printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR); | 338 | printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR); |
339 | else | 339 | else |
340 | printk("No Alternate Algorithm Table\n"); | 340 | printk("No Alternate Algorithm Table\n"); |
341 | 341 | ||
342 | 342 | ||
343 | printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); | 343 | printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); |
344 | printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); | 344 | printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); |
345 | if (cfip->VppMin) { | 345 | if (cfip->VppMin) { |
@@ -348,61 +348,61 @@ static void print_cfi_ident(struct cfi_ident *cfip) | |||
348 | } | 348 | } |
349 | else | 349 | else |
350 | printk("No Vpp line\n"); | 350 | printk("No Vpp line\n"); |
351 | 351 | ||
352 | printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp); | 352 | printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp); |
353 | printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp)); | 353 | printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp)); |
354 | 354 | ||
355 | if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) { | 355 | if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) { |
356 | printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp); | 356 | printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp); |
357 | printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp)); | 357 | printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp)); |
358 | } | 358 | } |
359 | else | 359 | else |
360 | printk("Full buffer write not supported\n"); | 360 | printk("Full buffer write not supported\n"); |
361 | 361 | ||
362 | printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp); | 362 | printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp); |
363 | printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp)); | 363 | printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp)); |
364 | if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) { | 364 | if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) { |
365 | printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); | 365 | printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); |
366 | printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp)); | 366 | printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp)); |
367 | } | 367 | } |
368 | else | 368 | else |
369 | printk("Chip erase not supported\n"); | 369 | printk("Chip erase not supported\n"); |
370 | 370 | ||
371 | printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20)); | 371 | printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20)); |
372 | printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc); | 372 | printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc); |
373 | switch(cfip->InterfaceDesc) { | 373 | switch(cfip->InterfaceDesc) { |
374 | case 0: | 374 | case 0: |
375 | printk(" - x8-only asynchronous interface\n"); | 375 | printk(" - x8-only asynchronous interface\n"); |
376 | break; | 376 | break; |
377 | 377 | ||
378 | case 1: | 378 | case 1: |
379 | printk(" - x16-only asynchronous interface\n"); | 379 | printk(" - x16-only asynchronous interface\n"); |
380 | break; | 380 | break; |
381 | 381 | ||
382 | case 2: | 382 | case 2: |
383 | printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n"); | 383 | printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n"); |
384 | break; | 384 | break; |
385 | 385 | ||
386 | case 3: | 386 | case 3: |
387 | printk(" - x32-only asynchronous interface\n"); | 387 | printk(" - x32-only asynchronous interface\n"); |
388 | break; | 388 | break; |
389 | 389 | ||
390 | case 4: | 390 | case 4: |
391 | printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); | 391 | printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); |
392 | break; | 392 | break; |
393 | 393 | ||
394 | case 65535: | 394 | case 65535: |
395 | printk(" - Not Allowed / Reserved\n"); | 395 | printk(" - Not Allowed / Reserved\n"); |
396 | break; | 396 | break; |
397 | 397 | ||
398 | default: | 398 | default: |
399 | printk(" - Unknown\n"); | 399 | printk(" - Unknown\n"); |
400 | break; | 400 | break; |
401 | } | 401 | } |
402 | 402 | ||
403 | printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize); | 403 | printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize); |
404 | printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions); | 404 | printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions); |
405 | 405 | ||
406 | } | 406 | } |
407 | #endif /* DEBUG_CFI */ | 407 | #endif /* DEBUG_CFI */ |
408 | 408 | ||
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 2b2ede2bfcca..d8e7a026ba5a 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * This code is covered by the GPL. | 8 | * This code is covered by the GPL. |
9 | * | 9 | * |
10 | * $Id: cfi_util.c,v 1.8 2004/12/14 19:55:56 nico Exp $ | 10 | * $Id: cfi_util.c,v 1.10 2005/11/07 11:14:23 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -56,7 +56,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
56 | 56 | ||
57 | /* Read in the Extended Query Table */ | 57 | /* Read in the Extended Query Table */ |
58 | for (i=0; i<size; i++) { | 58 | for (i=0; i<size; i++) { |
59 | ((unsigned char *)extp)[i] = | 59 | ((unsigned char *)extp)[i] = |
60 | cfi_read_query(map, base+((adr+i)*ofs_factor)); | 60 | cfi_read_query(map, base+((adr+i)*ofs_factor)); |
61 | } | 61 | } |
62 | 62 | ||
@@ -70,15 +70,6 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
70 | local_irq_enable(); | 70 | local_irq_enable(); |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | if (extp->MajorVersion != '1' || | ||
74 | (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { | ||
75 | printk(KERN_WARNING " Unknown %s Extended Query " | ||
76 | "version %c.%c.\n", name, extp->MajorVersion, | ||
77 | extp->MinorVersion); | ||
78 | kfree(extp); | ||
79 | extp = NULL; | ||
80 | } | ||
81 | |||
82 | out: return extp; | 73 | out: return extp; |
83 | } | 74 | } |
84 | 75 | ||
@@ -122,17 +113,17 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |||
122 | 113 | ||
123 | i = 0; | 114 | i = 0; |
124 | 115 | ||
125 | /* Skip all erase regions which are ended before the start of | 116 | /* Skip all erase regions which are ended before the start of |
126 | the requested erase. Actually, to save on the calculations, | 117 | the requested erase. Actually, to save on the calculations, |
127 | we skip to the first erase region which starts after the | 118 | we skip to the first erase region which starts after the |
128 | start of the requested erase, and then go back one. | 119 | start of the requested erase, and then go back one. |
129 | */ | 120 | */ |
130 | 121 | ||
131 | while (i < mtd->numeraseregions && ofs >= regions[i].offset) | 122 | while (i < mtd->numeraseregions && ofs >= regions[i].offset) |
132 | i++; | 123 | i++; |
133 | i--; | 124 | i--; |
134 | 125 | ||
135 | /* OK, now i is pointing at the erase region in which this | 126 | /* OK, now i is pointing at the erase region in which this |
136 | erase request starts. Check the start of the requested | 127 | erase request starts. Check the start of the requested |
137 | erase range is aligned with the erase size which is in | 128 | erase range is aligned with the erase size which is in |
138 | effect here. | 129 | effect here. |
@@ -155,7 +146,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |||
155 | the address actually falls | 146 | the address actually falls |
156 | */ | 147 | */ |
157 | i--; | 148 | i--; |
158 | 149 | ||
159 | if ((ofs + len) & (regions[i].erasesize-1)) | 150 | if ((ofs + len) & (regions[i].erasesize-1)) |
160 | return -EINVAL; | 151 | return -EINVAL; |
161 | 152 | ||
@@ -168,7 +159,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |||
168 | int size = regions[i].erasesize; | 159 | int size = regions[i].erasesize; |
169 | 160 | ||
170 | ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk); | 161 | ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk); |
171 | 162 | ||
172 | if (ret) | 163 | if (ret) |
173 | return ret; | 164 | return ret; |
174 | 165 | ||
@@ -182,7 +173,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, | |||
182 | if (adr >> cfi->chipshift) { | 173 | if (adr >> cfi->chipshift) { |
183 | adr = 0; | 174 | adr = 0; |
184 | chipnum++; | 175 | chipnum++; |
185 | 176 | ||
186 | if (chipnum >= cfi->numchips) | 177 | if (chipnum >= cfi->numchips) |
187 | break; | 178 | break; |
188 | } | 179 | } |
diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c index d7d739a108ae..c2127840a183 100644 --- a/drivers/mtd/chips/chipreg.c +++ b/drivers/mtd/chips/chipreg.c | |||
@@ -41,7 +41,7 @@ static struct mtd_chip_driver *get_mtd_chip_driver (const char *name) | |||
41 | 41 | ||
42 | list_for_each(pos, &chip_drvs_list) { | 42 | list_for_each(pos, &chip_drvs_list) { |
43 | this = list_entry(pos, typeof(*this), list); | 43 | this = list_entry(pos, typeof(*this), list); |
44 | 44 | ||
45 | if (!strcmp(this->name, name)) { | 45 | if (!strcmp(this->name, name)) { |
46 | ret = this; | 46 | ret = this; |
47 | break; | 47 | break; |
@@ -73,7 +73,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map) | |||
73 | 73 | ||
74 | ret = drv->probe(map); | 74 | ret = drv->probe(map); |
75 | 75 | ||
76 | /* We decrease the use count here. It may have been a | 76 | /* We decrease the use count here. It may have been a |
77 | probe-only module, which is no longer required from this | 77 | probe-only module, which is no longer required from this |
78 | point, having given us a handle on (and increased the use | 78 | point, having given us a handle on (and increased the use |
79 | count of) the actual driver code. | 79 | count of) the actual driver code. |
@@ -82,7 +82,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map) | |||
82 | 82 | ||
83 | if (ret) | 83 | if (ret) |
84 | return ret; | 84 | return ret; |
85 | 85 | ||
86 | return NULL; | 86 | return NULL; |
87 | } | 87 | } |
88 | /* | 88 | /* |
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index e1a5b76596c5..77303ce5dcf1 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h | |||
@@ -25,7 +25,7 @@ struct fwh_xxlock_thunk { | |||
25 | * so this code has not been tested with interleaved chips, | 25 | * so this code has not been tested with interleaved chips, |
26 | * and will likely fail in that context. | 26 | * and will likely fail in that context. |
27 | */ | 27 | */ |
28 | static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, | 28 | static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, |
29 | unsigned long adr, int len, void *thunk) | 29 | unsigned long adr, int len, void *thunk) |
30 | { | 30 | { |
31 | struct cfi_private *cfi = map->fldrv_priv; | 31 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -44,7 +44,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, | |||
44 | * - on 64k boundariesand | 44 | * - on 64k boundariesand |
45 | * - bit 1 set high | 45 | * - bit 1 set high |
46 | * - block lock registers are 4MiB lower - overflow subtract (danger) | 46 | * - block lock registers are 4MiB lower - overflow subtract (danger) |
47 | * | 47 | * |
48 | * The address manipulation is first done on the logical address | 48 | * The address manipulation is first done on the logical address |
49 | * which is 0 at the start of the chip, and then the offset of | 49 | * which is 0 at the start of the chip, and then the offset of |
50 | * the individual chip is addted to it. Any other order a weird | 50 | * the individual chip is addted to it. Any other order a weird |
@@ -93,7 +93,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
93 | 93 | ||
94 | ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len, | 94 | ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len, |
95 | (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK); | 95 | (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK); |
96 | 96 | ||
97 | return ret; | 97 | return ret; |
98 | } | 98 | } |
99 | 99 | ||
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index dc065b22f79e..41bd59d20d85 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Routines common to all CFI-type probes. | 2 | * Routines common to all CFI-type probes. |
3 | * (C) 2001-2003 Red Hat, Inc. | 3 | * (C) 2001-2003 Red Hat, Inc. |
4 | * GPL'd | 4 | * GPL'd |
5 | * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $ | 5 | * $Id: gen_probe.c,v 1.24 2005/11/07 11:14:23 gleixner Exp $ |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
@@ -26,7 +26,7 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) | |||
26 | 26 | ||
27 | /* First probe the map to see if we have CFI stuff there. */ | 27 | /* First probe the map to see if we have CFI stuff there. */ |
28 | cfi = genprobe_ident_chips(map, cp); | 28 | cfi = genprobe_ident_chips(map, cp); |
29 | 29 | ||
30 | if (!cfi) | 30 | if (!cfi) |
31 | return NULL; | 31 | return NULL; |
32 | 32 | ||
@@ -36,12 +36,12 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) | |||
36 | mtd = check_cmd_set(map, 1); /* First the primary cmdset */ | 36 | mtd = check_cmd_set(map, 1); /* First the primary cmdset */ |
37 | if (!mtd) | 37 | if (!mtd) |
38 | mtd = check_cmd_set(map, 0); /* Then the secondary */ | 38 | mtd = check_cmd_set(map, 0); /* Then the secondary */ |
39 | 39 | ||
40 | if (mtd) | 40 | if (mtd) |
41 | return mtd; | 41 | return mtd; |
42 | 42 | ||
43 | printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); | 43 | printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); |
44 | 44 | ||
45 | kfree(cfi->cfiq); | 45 | kfree(cfi->cfiq); |
46 | kfree(cfi); | 46 | kfree(cfi); |
47 | map->fldrv_priv = NULL; | 47 | map->fldrv_priv = NULL; |
@@ -60,14 +60,14 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
60 | 60 | ||
61 | memset(&cfi, 0, sizeof(cfi)); | 61 | memset(&cfi, 0, sizeof(cfi)); |
62 | 62 | ||
63 | /* Call the probetype-specific code with all permutations of | 63 | /* Call the probetype-specific code with all permutations of |
64 | interleave and device type, etc. */ | 64 | interleave and device type, etc. */ |
65 | if (!genprobe_new_chip(map, cp, &cfi)) { | 65 | if (!genprobe_new_chip(map, cp, &cfi)) { |
66 | /* The probe didn't like it */ | 66 | /* The probe didn't like it */ |
67 | printk(KERN_DEBUG "%s: Found no %s device at location zero\n", | 67 | printk(KERN_DEBUG "%s: Found no %s device at location zero\n", |
68 | cp->name, map->name); | 68 | cp->name, map->name); |
69 | return NULL; | 69 | return NULL; |
70 | } | 70 | } |
71 | 71 | ||
72 | #if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD | 72 | #if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD |
73 | probe routines won't ever return a broken CFI structure anyway, | 73 | probe routines won't ever return a broken CFI structure anyway, |
@@ -92,13 +92,13 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
92 | } else { | 92 | } else { |
93 | BUG(); | 93 | BUG(); |
94 | } | 94 | } |
95 | 95 | ||
96 | cfi.numchips = 1; | 96 | cfi.numchips = 1; |
97 | 97 | ||
98 | /* | 98 | /* |
99 | * Allocate memory for bitmap of valid chips. | 99 | * Allocate memory for bitmap of valid chips. |
100 | * Align bitmap storage size to full byte. | 100 | * Align bitmap storage size to full byte. |
101 | */ | 101 | */ |
102 | max_chips = map->size >> cfi.chipshift; | 102 | max_chips = map->size >> cfi.chipshift; |
103 | mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0); | 103 | mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0); |
104 | chip_map = kmalloc(mapsize, GFP_KERNEL); | 104 | chip_map = kmalloc(mapsize, GFP_KERNEL); |
@@ -122,7 +122,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
122 | } | 122 | } |
123 | 123 | ||
124 | /* | 124 | /* |
125 | * Now allocate the space for the structures we need to return to | 125 | * Now allocate the space for the structures we need to return to |
126 | * our caller, and copy the appropriate data into them. | 126 | * our caller, and copy the appropriate data into them. |
127 | */ | 127 | */ |
128 | 128 | ||
@@ -154,7 +154,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
154 | return retcfi; | 154 | return retcfi; |
155 | } | 155 | } |
156 | 156 | ||
157 | 157 | ||
158 | static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, | 158 | static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, |
159 | struct cfi_private *cfi) | 159 | struct cfi_private *cfi) |
160 | { | 160 | { |
@@ -189,7 +189,7 @@ extern cfi_cmdset_fn_t cfi_cmdset_0001; | |||
189 | extern cfi_cmdset_fn_t cfi_cmdset_0002; | 189 | extern cfi_cmdset_fn_t cfi_cmdset_0002; |
190 | extern cfi_cmdset_fn_t cfi_cmdset_0020; | 190 | extern cfi_cmdset_fn_t cfi_cmdset_0020; |
191 | 191 | ||
192 | static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, | 192 | static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, |
193 | int primary) | 193 | int primary) |
194 | { | 194 | { |
195 | struct cfi_private *cfi = map->fldrv_priv; | 195 | struct cfi_private *cfi = map->fldrv_priv; |
@@ -199,7 +199,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, | |||
199 | cfi_cmdset_fn_t *probe_function; | 199 | cfi_cmdset_fn_t *probe_function; |
200 | 200 | ||
201 | sprintf(probename, "cfi_cmdset_%4.4X", type); | 201 | sprintf(probename, "cfi_cmdset_%4.4X", type); |
202 | 202 | ||
203 | probe_function = inter_module_get_request(probename, probename); | 203 | probe_function = inter_module_get_request(probename, probename); |
204 | 204 | ||
205 | if (probe_function) { | 205 | if (probe_function) { |
@@ -221,7 +221,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) | |||
221 | { | 221 | { |
222 | struct cfi_private *cfi = map->fldrv_priv; | 222 | struct cfi_private *cfi = map->fldrv_priv; |
223 | __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; | 223 | __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; |
224 | 224 | ||
225 | if (type == P_ID_NONE || type == P_ID_RESERVED) | 225 | if (type == P_ID_NONE || type == P_ID_RESERVED) |
226 | return NULL; | 226 | return NULL; |
227 | 227 | ||
@@ -235,6 +235,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) | |||
235 | #ifdef CONFIG_MTD_CFI_INTELEXT | 235 | #ifdef CONFIG_MTD_CFI_INTELEXT |
236 | case 0x0001: | 236 | case 0x0001: |
237 | case 0x0003: | 237 | case 0x0003: |
238 | case 0x0200: | ||
238 | return cfi_cmdset_0001(map, primary); | 239 | return cfi_cmdset_0001(map, primary); |
239 | #endif | 240 | #endif |
240 | #ifdef CONFIG_MTD_CFI_AMDSTD | 241 | #ifdef CONFIG_MTD_CFI_AMDSTD |
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c index 4f6778f3ee3e..c40b48dabed3 100644 --- a/drivers/mtd/chips/jedec.c +++ b/drivers/mtd/chips/jedec.c | |||
@@ -1,6 +1,6 @@ | |||
1 | 1 | ||
2 | /* JEDEC Flash Interface. | 2 | /* JEDEC Flash Interface. |
3 | * This is an older type of interface for self programming flash. It is | 3 | * This is an older type of interface for self programming flash. It is |
4 | * commonly use in older AMD chips and is obsolete compared with CFI. | 4 | * commonly use in older AMD chips and is obsolete compared with CFI. |
5 | * It is called JEDEC because the JEDEC association distributes the ID codes | 5 | * It is called JEDEC because the JEDEC association distributes the ID codes |
6 | * for the chips. | 6 | * for the chips. |
@@ -88,9 +88,9 @@ static const struct JEDECTable JEDEC_table[] = { | |||
88 | 88 | ||
89 | static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); | 89 | static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); |
90 | static void jedec_sync(struct mtd_info *mtd) {}; | 90 | static void jedec_sync(struct mtd_info *mtd) {}; |
91 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, | 91 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, |
92 | size_t *retlen, u_char *buf); | 92 | size_t *retlen, u_char *buf); |
93 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, | 93 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, |
94 | size_t *retlen, u_char *buf); | 94 | size_t *retlen, u_char *buf); |
95 | 95 | ||
96 | static struct mtd_info *jedec_probe(struct map_info *map); | 96 | static struct mtd_info *jedec_probe(struct map_info *map); |
@@ -122,7 +122,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
122 | 122 | ||
123 | memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private)); | 123 | memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private)); |
124 | priv = (struct jedec_private *)&MTD[1]; | 124 | priv = (struct jedec_private *)&MTD[1]; |
125 | 125 | ||
126 | my_bank_size = map->size; | 126 | my_bank_size = map->size; |
127 | 127 | ||
128 | if (map->size/my_bank_size > MAX_JEDEC_CHIPS) | 128 | if (map->size/my_bank_size > MAX_JEDEC_CHIPS) |
@@ -131,13 +131,13 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
131 | kfree(MTD); | 131 | kfree(MTD); |
132 | return NULL; | 132 | return NULL; |
133 | } | 133 | } |
134 | 134 | ||
135 | for (Base = 0; Base < map->size; Base += my_bank_size) | 135 | for (Base = 0; Base < map->size; Base += my_bank_size) |
136 | { | 136 | { |
137 | // Perhaps zero could designate all tests? | 137 | // Perhaps zero could designate all tests? |
138 | if (map->buswidth == 0) | 138 | if (map->buswidth == 0) |
139 | map->buswidth = 1; | 139 | map->buswidth = 1; |
140 | 140 | ||
141 | if (map->buswidth == 1){ | 141 | if (map->buswidth == 1){ |
142 | if (jedec_probe8(map,Base,priv) == 0) { | 142 | if (jedec_probe8(map,Base,priv) == 0) { |
143 | printk("did recognize jedec chip\n"); | 143 | printk("did recognize jedec chip\n"); |
@@ -150,7 +150,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
150 | if (map->buswidth == 4) | 150 | if (map->buswidth == 4) |
151 | jedec_probe32(map,Base,priv); | 151 | jedec_probe32(map,Base,priv); |
152 | } | 152 | } |
153 | 153 | ||
154 | // Get the biggest sector size | 154 | // Get the biggest sector size |
155 | SectorSize = 0; | 155 | SectorSize = 0; |
156 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 156 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
@@ -160,7 +160,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
160 | if (priv->chips[I].sectorsize > SectorSize) | 160 | if (priv->chips[I].sectorsize > SectorSize) |
161 | SectorSize = priv->chips[I].sectorsize; | 161 | SectorSize = priv->chips[I].sectorsize; |
162 | } | 162 | } |
163 | 163 | ||
164 | // Quickly ensure that the other sector sizes are factors of the largest | 164 | // Quickly ensure that the other sector sizes are factors of the largest |
165 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 165 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
166 | { | 166 | { |
@@ -169,9 +169,9 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
169 | printk("mtd: Failed. Device has incompatible mixed sector sizes\n"); | 169 | printk("mtd: Failed. Device has incompatible mixed sector sizes\n"); |
170 | kfree(MTD); | 170 | kfree(MTD); |
171 | return NULL; | 171 | return NULL; |
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | /* Generate a part name that includes the number of different chips and | 175 | /* Generate a part name that includes the number of different chips and |
176 | other configuration information */ | 176 | other configuration information */ |
177 | count = 1; | 177 | count = 1; |
@@ -181,13 +181,13 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
181 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 181 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
182 | { | 182 | { |
183 | const struct JEDECTable *JEDEC; | 183 | const struct JEDECTable *JEDEC; |
184 | 184 | ||
185 | if (priv->chips[I+1].jedec == priv->chips[I].jedec) | 185 | if (priv->chips[I+1].jedec == priv->chips[I].jedec) |
186 | { | 186 | { |
187 | count++; | 187 | count++; |
188 | continue; | 188 | continue; |
189 | } | 189 | } |
190 | 190 | ||
191 | // Locate the chip in the jedec table | 191 | // Locate the chip in the jedec table |
192 | JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec); | 192 | JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec); |
193 | if (JEDEC == 0) | 193 | if (JEDEC == 0) |
@@ -196,11 +196,11 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
196 | kfree(MTD); | 196 | kfree(MTD); |
197 | return NULL; | 197 | return NULL; |
198 | } | 198 | } |
199 | 199 | ||
200 | if (Uniq != 0) | 200 | if (Uniq != 0) |
201 | strcat(Part,","); | 201 | strcat(Part,","); |
202 | Uniq++; | 202 | Uniq++; |
203 | 203 | ||
204 | if (count != 1) | 204 | if (count != 1) |
205 | sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name); | 205 | sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name); |
206 | else | 206 | else |
@@ -208,7 +208,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
208 | if (strlen(Part) > sizeof(Part)*2/3) | 208 | if (strlen(Part) > sizeof(Part)*2/3) |
209 | break; | 209 | break; |
210 | count = 1; | 210 | count = 1; |
211 | } | 211 | } |
212 | 212 | ||
213 | /* Determine if the chips are organized in a linear fashion, or if there | 213 | /* Determine if the chips are organized in a linear fashion, or if there |
214 | are empty banks. Note, the last bank does not count here, only the | 214 | are empty banks. Note, the last bank does not count here, only the |
@@ -233,7 +233,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
233 | { | 233 | { |
234 | if (priv->bank_fill[I] != my_bank_size) | 234 | if (priv->bank_fill[I] != my_bank_size) |
235 | priv->is_banked = 1; | 235 | priv->is_banked = 1; |
236 | 236 | ||
237 | /* This even could be eliminated, but new de-optimized read/write | 237 | /* This even could be eliminated, but new de-optimized read/write |
238 | functions have to be written */ | 238 | functions have to be written */ |
239 | printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]); | 239 | printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]); |
@@ -242,7 +242,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
242 | printk("mtd: Failed. Cannot handle unsymmetric banking\n"); | 242 | printk("mtd: Failed. Cannot handle unsymmetric banking\n"); |
243 | kfree(MTD); | 243 | kfree(MTD); |
244 | return NULL; | 244 | return NULL; |
245 | } | 245 | } |
246 | } | 246 | } |
247 | } | 247 | } |
248 | } | 248 | } |
@@ -250,7 +250,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) | |||
250 | strcat(Part,", banked"); | 250 | strcat(Part,", banked"); |
251 | 251 | ||
252 | // printk("Part: '%s'\n",Part); | 252 | // printk("Part: '%s'\n",Part); |
253 | 253 | ||
254 | memset(MTD,0,sizeof(*MTD)); | 254 | memset(MTD,0,sizeof(*MTD)); |
255 | // strlcpy(MTD->name,Part,sizeof(MTD->name)); | 255 | // strlcpy(MTD->name,Part,sizeof(MTD->name)); |
256 | MTD->name = map->name; | 256 | MTD->name = map->name; |
@@ -291,7 +291,7 @@ static int checkparity(u_char C) | |||
291 | 291 | ||
292 | /* Take an array of JEDEC numbers that represent interleved flash chips | 292 | /* Take an array of JEDEC numbers that represent interleved flash chips |
293 | and process them. Check to make sure they are good JEDEC numbers, look | 293 | and process them. Check to make sure they are good JEDEC numbers, look |
294 | them up and then add them to the chip list */ | 294 | them up and then add them to the chip list */ |
295 | static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | 295 | static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, |
296 | unsigned long base,struct jedec_private *priv) | 296 | unsigned long base,struct jedec_private *priv) |
297 | { | 297 | { |
@@ -306,16 +306,16 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | |||
306 | if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0) | 306 | if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0) |
307 | return 0; | 307 | return 0; |
308 | } | 308 | } |
309 | 309 | ||
310 | // Finally, just make sure all the chip sizes are the same | 310 | // Finally, just make sure all the chip sizes are the same |
311 | JEDEC = jedec_idtoinf(Mfg[0],Id[0]); | 311 | JEDEC = jedec_idtoinf(Mfg[0],Id[0]); |
312 | 312 | ||
313 | if (JEDEC == 0) | 313 | if (JEDEC == 0) |
314 | { | 314 | { |
315 | printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]); | 315 | printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]); |
316 | return 0; | 316 | return 0; |
317 | } | 317 | } |
318 | 318 | ||
319 | Size = JEDEC->size; | 319 | Size = JEDEC->size; |
320 | SectorSize = JEDEC->sectorsize; | 320 | SectorSize = JEDEC->sectorsize; |
321 | for (I = 0; I != Count; I++) | 321 | for (I = 0; I != Count; I++) |
@@ -331,7 +331,7 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | |||
331 | { | 331 | { |
332 | printk("mtd: Failed. Interleved flash does not have matching characteristics\n"); | 332 | printk("mtd: Failed. Interleved flash does not have matching characteristics\n"); |
333 | return 0; | 333 | return 0; |
334 | } | 334 | } |
335 | } | 335 | } |
336 | 336 | ||
337 | // Load the Chips | 337 | // Load the Chips |
@@ -345,13 +345,13 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | |||
345 | { | 345 | { |
346 | printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n"); | 346 | printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n"); |
347 | return 0; | 347 | return 0; |
348 | } | 348 | } |
349 | 349 | ||
350 | // Add them to the table | 350 | // Add them to the table |
351 | for (J = 0; J != Count; J++) | 351 | for (J = 0; J != Count; J++) |
352 | { | 352 | { |
353 | unsigned long Bank; | 353 | unsigned long Bank; |
354 | 354 | ||
355 | JEDEC = jedec_idtoinf(Mfg[J],Id[J]); | 355 | JEDEC = jedec_idtoinf(Mfg[J],Id[J]); |
356 | priv->chips[I].jedec = (Mfg[J] << 8) | Id[J]; | 356 | priv->chips[I].jedec = (Mfg[J] << 8) | Id[J]; |
357 | priv->chips[I].size = JEDEC->size; | 357 | priv->chips[I].size = JEDEC->size; |
@@ -364,17 +364,17 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | |||
364 | // log2 n :| | 364 | // log2 n :| |
365 | priv->chips[I].addrshift = 0; | 365 | priv->chips[I].addrshift = 0; |
366 | for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++); | 366 | for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++); |
367 | 367 | ||
368 | // Determine how filled this bank is. | 368 | // Determine how filled this bank is. |
369 | Bank = base & (~(my_bank_size-1)); | 369 | Bank = base & (~(my_bank_size-1)); |
370 | if (priv->bank_fill[Bank/my_bank_size] < base + | 370 | if (priv->bank_fill[Bank/my_bank_size] < base + |
371 | (JEDEC->size << priv->chips[I].addrshift) - Bank) | 371 | (JEDEC->size << priv->chips[I].addrshift) - Bank) |
372 | priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank; | 372 | priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank; |
373 | I++; | 373 | I++; |
374 | } | 374 | } |
375 | 375 | ||
376 | priv->size += priv->chips[I-1].size*Count; | 376 | priv->size += priv->chips[I-1].size*Count; |
377 | 377 | ||
378 | return priv->chips[I-1].size; | 378 | return priv->chips[I-1].size; |
379 | } | 379 | } |
380 | 380 | ||
@@ -392,7 +392,7 @@ static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id) | |||
392 | // Look for flash using an 8 bit bus interface | 392 | // Look for flash using an 8 bit bus interface |
393 | static int jedec_probe8(struct map_info *map,unsigned long base, | 393 | static int jedec_probe8(struct map_info *map,unsigned long base, |
394 | struct jedec_private *priv) | 394 | struct jedec_private *priv) |
395 | { | 395 | { |
396 | #define flread(x) map_read8(map,base+x) | 396 | #define flread(x) map_read8(map,base+x) |
397 | #define flwrite(v,x) map_write8(map,v,base+x) | 397 | #define flwrite(v,x) map_write8(map,v,base+x) |
398 | 398 | ||
@@ -410,20 +410,20 @@ static int jedec_probe8(struct map_info *map,unsigned long base, | |||
410 | OldVal = flread(base); | 410 | OldVal = flread(base); |
411 | for (I = 0; OldVal != flread(base) && I < 10000; I++) | 411 | for (I = 0; OldVal != flread(base) && I < 10000; I++) |
412 | OldVal = flread(base); | 412 | OldVal = flread(base); |
413 | 413 | ||
414 | // Reset the chip | 414 | // Reset the chip |
415 | flwrite(Reset,0x555); | 415 | flwrite(Reset,0x555); |
416 | 416 | ||
417 | // Send the sequence | 417 | // Send the sequence |
418 | flwrite(AutoSel1,0x555); | 418 | flwrite(AutoSel1,0x555); |
419 | flwrite(AutoSel2,0x2AA); | 419 | flwrite(AutoSel2,0x2AA); |
420 | flwrite(AutoSel3,0x555); | 420 | flwrite(AutoSel3,0x555); |
421 | 421 | ||
422 | // Get the JEDEC numbers | 422 | // Get the JEDEC numbers |
423 | Mfg[0] = flread(0); | 423 | Mfg[0] = flread(0); |
424 | Id[0] = flread(1); | 424 | Id[0] = flread(1); |
425 | // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]); | 425 | // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]); |
426 | 426 | ||
427 | Size = handle_jedecs(map,Mfg,Id,1,base,priv); | 427 | Size = handle_jedecs(map,Mfg,Id,1,base,priv); |
428 | // printk("handle_jedecs Size is %x\n",(unsigned int)Size); | 428 | // printk("handle_jedecs Size is %x\n",(unsigned int)Size); |
429 | if (Size == 0) | 429 | if (Size == 0) |
@@ -431,13 +431,13 @@ static int jedec_probe8(struct map_info *map,unsigned long base, | |||
431 | flwrite(Reset,0x555); | 431 | flwrite(Reset,0x555); |
432 | return 0; | 432 | return 0; |
433 | } | 433 | } |
434 | 434 | ||
435 | 435 | ||
436 | // Reset. | 436 | // Reset. |
437 | flwrite(Reset,0x555); | 437 | flwrite(Reset,0x555); |
438 | 438 | ||
439 | return 1; | 439 | return 1; |
440 | 440 | ||
441 | #undef flread | 441 | #undef flread |
442 | #undef flwrite | 442 | #undef flwrite |
443 | } | 443 | } |
@@ -470,17 +470,17 @@ static int jedec_probe32(struct map_info *map,unsigned long base, | |||
470 | OldVal = flread(base); | 470 | OldVal = flread(base); |
471 | for (I = 0; OldVal != flread(base) && I < 10000; I++) | 471 | for (I = 0; OldVal != flread(base) && I < 10000; I++) |
472 | OldVal = flread(base); | 472 | OldVal = flread(base); |
473 | 473 | ||
474 | // Reset the chip | 474 | // Reset the chip |
475 | flwrite(Reset,0x555); | 475 | flwrite(Reset,0x555); |
476 | 476 | ||
477 | // Send the sequence | 477 | // Send the sequence |
478 | flwrite(AutoSel1,0x555); | 478 | flwrite(AutoSel1,0x555); |
479 | flwrite(AutoSel2,0x2AA); | 479 | flwrite(AutoSel2,0x2AA); |
480 | flwrite(AutoSel3,0x555); | 480 | flwrite(AutoSel3,0x555); |
481 | 481 | ||
482 | // Test #1, JEDEC numbers are readable from 0x??00/0x??01 | 482 | // Test #1, JEDEC numbers are readable from 0x??00/0x??01 |
483 | if (flread(0) != flread(0x100) || | 483 | if (flread(0) != flread(0x100) || |
484 | flread(1) != flread(0x101)) | 484 | flread(1) != flread(0x101)) |
485 | { | 485 | { |
486 | flwrite(Reset,0x555); | 486 | flwrite(Reset,0x555); |
@@ -494,14 +494,14 @@ static int jedec_probe32(struct map_info *map,unsigned long base, | |||
494 | OldVal = flread(1); | 494 | OldVal = flread(1); |
495 | for (I = 0; I != 4; I++) | 495 | for (I = 0; I != 4; I++) |
496 | Id[I] = (OldVal >> (I*8)); | 496 | Id[I] = (OldVal >> (I*8)); |
497 | 497 | ||
498 | Size = handle_jedecs(map,Mfg,Id,4,base,priv); | 498 | Size = handle_jedecs(map,Mfg,Id,4,base,priv); |
499 | if (Size == 0) | 499 | if (Size == 0) |
500 | { | 500 | { |
501 | flwrite(Reset,0x555); | 501 | flwrite(Reset,0x555); |
502 | return 0; | 502 | return 0; |
503 | } | 503 | } |
504 | 504 | ||
505 | /* Check if there is address wrap around within a single bank, if this | 505 | /* Check if there is address wrap around within a single bank, if this |
506 | returns JEDEC numbers then we assume that it is wrap around. Notice | 506 | returns JEDEC numbers then we assume that it is wrap around. Notice |
507 | we call this routine with the JEDEC return still enabled, if two or | 507 | we call this routine with the JEDEC return still enabled, if two or |
@@ -519,27 +519,27 @@ static int jedec_probe32(struct map_info *map,unsigned long base, | |||
519 | 519 | ||
520 | // Reset. | 520 | // Reset. |
521 | flwrite(0xF0F0F0F0,0x555); | 521 | flwrite(0xF0F0F0F0,0x555); |
522 | 522 | ||
523 | return 1; | 523 | return 1; |
524 | 524 | ||
525 | #undef flread | 525 | #undef flread |
526 | #undef flwrite | 526 | #undef flwrite |
527 | } | 527 | } |
528 | 528 | ||
529 | /* Linear read. */ | 529 | /* Linear read. */ |
530 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, | 530 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, |
531 | size_t *retlen, u_char *buf) | 531 | size_t *retlen, u_char *buf) |
532 | { | 532 | { |
533 | struct map_info *map = mtd->priv; | 533 | struct map_info *map = mtd->priv; |
534 | 534 | ||
535 | map_copy_from(map, buf, from, len); | 535 | map_copy_from(map, buf, from, len); |
536 | *retlen = len; | 536 | *retlen = len; |
537 | return 0; | 537 | return 0; |
538 | } | 538 | } |
539 | 539 | ||
540 | /* Banked read. Take special care to jump past the holes in the bank | 540 | /* Banked read. Take special care to jump past the holes in the bank |
541 | mapping. This version assumes symetry in the holes.. */ | 541 | mapping. This version assumes symetry in the holes.. */ |
542 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, | 542 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, |
543 | size_t *retlen, u_char *buf) | 543 | size_t *retlen, u_char *buf) |
544 | { | 544 | { |
545 | struct map_info *map = mtd->priv; | 545 | struct map_info *map = mtd->priv; |
@@ -555,17 +555,17 @@ static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, | |||
555 | if (priv->bank_fill[0] - offset < len) | 555 | if (priv->bank_fill[0] - offset < len) |
556 | get = priv->bank_fill[0] - offset; | 556 | get = priv->bank_fill[0] - offset; |
557 | 557 | ||
558 | bank /= priv->bank_fill[0]; | 558 | bank /= priv->bank_fill[0]; |
559 | map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); | 559 | map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); |
560 | 560 | ||
561 | len -= get; | 561 | len -= get; |
562 | *retlen += get; | 562 | *retlen += get; |
563 | from += get; | 563 | from += get; |
564 | } | 564 | } |
565 | return 0; | 565 | return 0; |
566 | } | 566 | } |
567 | 567 | ||
568 | /* Pass the flags value that the flash return before it re-entered read | 568 | /* Pass the flags value that the flash return before it re-entered read |
569 | mode. */ | 569 | mode. */ |
570 | static void jedec_flash_failed(unsigned char code) | 570 | static void jedec_flash_failed(unsigned char code) |
571 | { | 571 | { |
@@ -579,17 +579,17 @@ static void jedec_flash_failed(unsigned char code) | |||
579 | printk("mtd: Programming didn't take\n"); | 579 | printk("mtd: Programming didn't take\n"); |
580 | } | 580 | } |
581 | 581 | ||
582 | /* This uses the erasure function described in the AMD Flash Handbook, | 582 | /* This uses the erasure function described in the AMD Flash Handbook, |
583 | it will work for flashes with a fixed sector size only. Flashes with | 583 | it will work for flashes with a fixed sector size only. Flashes with |
584 | a selection of sector sizes (ie the AMD Am29F800B) will need a different | 584 | a selection of sector sizes (ie the AMD Am29F800B) will need a different |
585 | routine. This routine tries to parallize erasing multiple chips/sectors | 585 | routine. This routine tries to parallize erasing multiple chips/sectors |
586 | where possible */ | 586 | where possible */ |
587 | static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | 587 | static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) |
588 | { | 588 | { |
589 | // Does IO to the currently selected chip | 589 | // Does IO to the currently selected chip |
590 | #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift)) | 590 | #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift)) |
591 | #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift)) | 591 | #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift)) |
592 | 592 | ||
593 | unsigned long Time = 0; | 593 | unsigned long Time = 0; |
594 | unsigned long NoTime = 0; | 594 | unsigned long NoTime = 0; |
595 | unsigned long start = instr->addr, len = instr->len; | 595 | unsigned long start = instr->addr, len = instr->len; |
@@ -603,7 +603,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
603 | (len % mtd->erasesize) != 0 || | 603 | (len % mtd->erasesize) != 0 || |
604 | (len/mtd->erasesize) == 0) | 604 | (len/mtd->erasesize) == 0) |
605 | return -EINVAL; | 605 | return -EINVAL; |
606 | 606 | ||
607 | jedec_flash_chip_scan(priv,start,len); | 607 | jedec_flash_chip_scan(priv,start,len); |
608 | 608 | ||
609 | // Start the erase sequence on each chip | 609 | // Start the erase sequence on each chip |
@@ -611,16 +611,16 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
611 | { | 611 | { |
612 | unsigned long off; | 612 | unsigned long off; |
613 | struct jedec_flash_chip *chip = priv->chips + I; | 613 | struct jedec_flash_chip *chip = priv->chips + I; |
614 | 614 | ||
615 | if (chip->length == 0) | 615 | if (chip->length == 0) |
616 | continue; | 616 | continue; |
617 | 617 | ||
618 | if (chip->start + chip->length > chip->size) | 618 | if (chip->start + chip->length > chip->size) |
619 | { | 619 | { |
620 | printk("DIE\n"); | 620 | printk("DIE\n"); |
621 | return -EIO; | 621 | return -EIO; |
622 | } | 622 | } |
623 | 623 | ||
624 | flwrite(0xF0,chip->start + 0x555); | 624 | flwrite(0xF0,chip->start + 0x555); |
625 | flwrite(0xAA,chip->start + 0x555); | 625 | flwrite(0xAA,chip->start + 0x555); |
626 | flwrite(0x55,chip->start + 0x2AA); | 626 | flwrite(0x55,chip->start + 0x2AA); |
@@ -628,8 +628,8 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
628 | flwrite(0xAA,chip->start + 0x555); | 628 | flwrite(0xAA,chip->start + 0x555); |
629 | flwrite(0x55,chip->start + 0x2AA); | 629 | flwrite(0x55,chip->start + 0x2AA); |
630 | 630 | ||
631 | /* Once we start selecting the erase sectors the delay between each | 631 | /* Once we start selecting the erase sectors the delay between each |
632 | command must not exceed 50us or it will immediately start erasing | 632 | command must not exceed 50us or it will immediately start erasing |
633 | and ignore the other sectors */ | 633 | and ignore the other sectors */ |
634 | for (off = 0; off < len; off += chip->sectorsize) | 634 | for (off = 0; off < len; off += chip->sectorsize) |
635 | { | 635 | { |
@@ -641,19 +641,19 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
641 | { | 641 | { |
642 | printk("mtd: Ack! We timed out the erase timer!\n"); | 642 | printk("mtd: Ack! We timed out the erase timer!\n"); |
643 | return -EIO; | 643 | return -EIO; |
644 | } | 644 | } |
645 | } | 645 | } |
646 | } | 646 | } |
647 | 647 | ||
648 | /* We could split this into a timer routine and return early, performing | 648 | /* We could split this into a timer routine and return early, performing |
649 | background erasure.. Maybe later if the need warrents */ | 649 | background erasure.. Maybe later if the need warrents */ |
650 | 650 | ||
651 | /* Poll the flash for erasure completion, specs say this can take as long | 651 | /* Poll the flash for erasure completion, specs say this can take as long |
652 | as 480 seconds to do all the sectors (for a 2 meg flash). | 652 | as 480 seconds to do all the sectors (for a 2 meg flash). |
653 | Erasure time is dependent on chip age, temp and wear.. */ | 653 | Erasure time is dependent on chip age, temp and wear.. */ |
654 | 654 | ||
655 | /* This being a generic routine assumes a 32 bit bus. It does read32s | 655 | /* This being a generic routine assumes a 32 bit bus. It does read32s |
656 | and bundles interleved chips into the same grouping. This will work | 656 | and bundles interleved chips into the same grouping. This will work |
657 | for all bus widths */ | 657 | for all bus widths */ |
658 | Time = 0; | 658 | Time = 0; |
659 | NoTime = 0; | 659 | NoTime = 0; |
@@ -664,20 +664,20 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
664 | unsigned todo[4] = {0,0,0,0}; | 664 | unsigned todo[4] = {0,0,0,0}; |
665 | unsigned todo_left = 0; | 665 | unsigned todo_left = 0; |
666 | unsigned J; | 666 | unsigned J; |
667 | 667 | ||
668 | if (chip->length == 0) | 668 | if (chip->length == 0) |
669 | continue; | 669 | continue; |
670 | 670 | ||
671 | /* Find all chips in this data line, realistically this is all | 671 | /* Find all chips in this data line, realistically this is all |
672 | or nothing up to the interleve count */ | 672 | or nothing up to the interleve count */ |
673 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) | 673 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) |
674 | { | 674 | { |
675 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == | 675 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == |
676 | (chip->base & (~((1<<chip->addrshift)-1)))) | 676 | (chip->base & (~((1<<chip->addrshift)-1)))) |
677 | { | 677 | { |
678 | todo_left++; | 678 | todo_left++; |
679 | todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1; | 679 | todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1; |
680 | } | 680 | } |
681 | } | 681 | } |
682 | 682 | ||
683 | /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1], | 683 | /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1], |
@@ -687,7 +687,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
687 | { | 687 | { |
688 | __u32 Last[4]; | 688 | __u32 Last[4]; |
689 | unsigned long Count = 0; | 689 | unsigned long Count = 0; |
690 | 690 | ||
691 | /* During erase bit 7 is held low and bit 6 toggles, we watch this, | 691 | /* During erase bit 7 is held low and bit 6 toggles, we watch this, |
692 | should it stop toggling or go high then the erase is completed, | 692 | should it stop toggling or go high then the erase is completed, |
693 | or this is not really flash ;> */ | 693 | or this is not really flash ;> */ |
@@ -718,23 +718,23 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
718 | __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF; | 718 | __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF; |
719 | if (todo[J] == 0) | 719 | if (todo[J] == 0) |
720 | continue; | 720 | continue; |
721 | 721 | ||
722 | if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2) | 722 | if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2) |
723 | { | 723 | { |
724 | // printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2); | 724 | // printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2); |
725 | continue; | 725 | continue; |
726 | } | 726 | } |
727 | 727 | ||
728 | if (Byte1 == Byte2) | 728 | if (Byte1 == Byte2) |
729 | { | 729 | { |
730 | jedec_flash_failed(Byte3); | 730 | jedec_flash_failed(Byte3); |
731 | return -EIO; | 731 | return -EIO; |
732 | } | 732 | } |
733 | 733 | ||
734 | todo[J] = 0; | 734 | todo[J] = 0; |
735 | todo_left--; | 735 | todo_left--; |
736 | } | 736 | } |
737 | 737 | ||
738 | /* if (NoTime == 0) | 738 | /* if (NoTime == 0) |
739 | Time += HZ/10 - schedule_timeout(HZ/10);*/ | 739 | Time += HZ/10 - schedule_timeout(HZ/10);*/ |
740 | NoTime = 0; | 740 | NoTime = 0; |
@@ -751,7 +751,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
751 | break; | 751 | break; |
752 | } | 752 | } |
753 | Count++; | 753 | Count++; |
754 | 754 | ||
755 | /* // Count time, max of 15s per sector (according to AMD) | 755 | /* // Count time, max of 15s per sector (according to AMD) |
756 | if (Time > 15*len/mtd->erasesize*HZ) | 756 | if (Time > 15*len/mtd->erasesize*HZ) |
757 | { | 757 | { |
@@ -759,38 +759,38 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
759 | return -EIO; | 759 | return -EIO; |
760 | } */ | 760 | } */ |
761 | } | 761 | } |
762 | 762 | ||
763 | // Skip to the next chip if we used chip erase | 763 | // Skip to the next chip if we used chip erase |
764 | if (chip->length == chip->size) | 764 | if (chip->length == chip->size) |
765 | off = chip->size; | 765 | off = chip->size; |
766 | else | 766 | else |
767 | off += chip->sectorsize; | 767 | off += chip->sectorsize; |
768 | 768 | ||
769 | if (off >= chip->length) | 769 | if (off >= chip->length) |
770 | break; | 770 | break; |
771 | NoTime = 1; | 771 | NoTime = 1; |
772 | } | 772 | } |
773 | 773 | ||
774 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) | 774 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) |
775 | { | 775 | { |
776 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == | 776 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == |
777 | (chip->base & (~((1<<chip->addrshift)-1)))) | 777 | (chip->base & (~((1<<chip->addrshift)-1)))) |
778 | priv->chips[J].length = 0; | 778 | priv->chips[J].length = 0; |
779 | } | 779 | } |
780 | } | 780 | } |
781 | 781 | ||
782 | //printk("done\n"); | 782 | //printk("done\n"); |
783 | instr->state = MTD_ERASE_DONE; | 783 | instr->state = MTD_ERASE_DONE; |
784 | mtd_erase_callback(instr); | 784 | mtd_erase_callback(instr); |
785 | return 0; | 785 | return 0; |
786 | 786 | ||
787 | #undef flread | 787 | #undef flread |
788 | #undef flwrite | 788 | #undef flwrite |
789 | } | 789 | } |
790 | 790 | ||
791 | /* This is the simple flash writing function. It writes to every byte, in | 791 | /* This is the simple flash writing function. It writes to every byte, in |
792 | sequence. It takes care of how to properly address the flash if | 792 | sequence. It takes care of how to properly address the flash if |
793 | the flash is interleved. It can only be used if all the chips in the | 793 | the flash is interleved. It can only be used if all the chips in the |
794 | array are identical!*/ | 794 | array are identical!*/ |
795 | static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | 795 | static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, |
796 | size_t *retlen, const u_char *buf) | 796 | size_t *retlen, const u_char *buf) |
@@ -800,25 +800,25 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
800 | of addrshift (interleave index) and then adds the control register index. */ | 800 | of addrshift (interleave index) and then adds the control register index. */ |
801 | #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) | 801 | #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) |
802 | #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) | 802 | #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) |
803 | 803 | ||
804 | struct map_info *map = mtd->priv; | 804 | struct map_info *map = mtd->priv; |
805 | struct jedec_private *priv = map->fldrv_priv; | 805 | struct jedec_private *priv = map->fldrv_priv; |
806 | unsigned long base; | 806 | unsigned long base; |
807 | unsigned long off; | 807 | unsigned long off; |
808 | size_t save_len = len; | 808 | size_t save_len = len; |
809 | 809 | ||
810 | if (start + len > mtd->size) | 810 | if (start + len > mtd->size) |
811 | return -EIO; | 811 | return -EIO; |
812 | 812 | ||
813 | //printk("Here"); | 813 | //printk("Here"); |
814 | 814 | ||
815 | //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len); | 815 | //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len); |
816 | while (len != 0) | 816 | while (len != 0) |
817 | { | 817 | { |
818 | struct jedec_flash_chip *chip = priv->chips; | 818 | struct jedec_flash_chip *chip = priv->chips; |
819 | unsigned long bank; | 819 | unsigned long bank; |
820 | unsigned long boffset; | 820 | unsigned long boffset; |
821 | 821 | ||
822 | // Compute the base of the flash. | 822 | // Compute the base of the flash. |
823 | off = ((unsigned long)start) % (chip->size << chip->addrshift); | 823 | off = ((unsigned long)start) % (chip->size << chip->addrshift); |
824 | base = start - off; | 824 | base = start - off; |
@@ -828,10 +828,10 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
828 | boffset = base & (priv->bank_fill[0]-1); | 828 | boffset = base & (priv->bank_fill[0]-1); |
829 | bank = (bank/priv->bank_fill[0])*my_bank_size; | 829 | bank = (bank/priv->bank_fill[0])*my_bank_size; |
830 | base = bank + boffset; | 830 | base = bank + boffset; |
831 | 831 | ||
832 | // printk("Flasing %X %X %X\n",base,chip->size,len); | 832 | // printk("Flasing %X %X %X\n",base,chip->size,len); |
833 | // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift); | 833 | // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift); |
834 | 834 | ||
835 | // Loop over this page | 835 | // Loop over this page |
836 | for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) | 836 | for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) |
837 | { | 837 | { |
@@ -845,7 +845,7 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
845 | } | 845 | } |
846 | if (((~oldbyte) & *buf) != 0) | 846 | if (((~oldbyte) & *buf) != 0) |
847 | printk("mtd: warn: Trying to set a 0 to a 1\n"); | 847 | printk("mtd: warn: Trying to set a 0 to a 1\n"); |
848 | 848 | ||
849 | // Write | 849 | // Write |
850 | flwrite(0xAA,0x555); | 850 | flwrite(0xAA,0x555); |
851 | flwrite(0x55,0x2AA); | 851 | flwrite(0x55,0x2AA); |
@@ -854,10 +854,10 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
854 | Last[0] = map_read8(map,base + off); | 854 | Last[0] = map_read8(map,base + off); |
855 | Last[1] = map_read8(map,base + off); | 855 | Last[1] = map_read8(map,base + off); |
856 | Last[2] = map_read8(map,base + off); | 856 | Last[2] = map_read8(map,base + off); |
857 | 857 | ||
858 | /* Wait for the flash to finish the operation. We store the last 4 | 858 | /* Wait for the flash to finish the operation. We store the last 4 |
859 | status bytes that have been retrieved so we can determine why | 859 | status bytes that have been retrieved so we can determine why |
860 | it failed. The toggle bits keep toggling when there is a | 860 | it failed. The toggle bits keep toggling when there is a |
861 | failure */ | 861 | failure */ |
862 | for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && | 862 | for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && |
863 | Count < 10000; Count++) | 863 | Count < 10000; Count++) |
@@ -866,7 +866,7 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | |||
866 | { | 866 | { |
867 | jedec_flash_failed(Last[(Count - 3) % 4]); | 867 | jedec_flash_failed(Last[(Count - 3) % 4]); |
868 | return -EIO; | 868 | return -EIO; |
869 | } | 869 | } |
870 | } | 870 | } |
871 | } | 871 | } |
872 | *retlen = save_len; | 872 | *retlen = save_len; |
@@ -885,24 +885,24 @@ static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start | |||
885 | // Zero the records | 885 | // Zero the records |
886 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 886 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
887 | priv->chips[I].start = priv->chips[I].length = 0; | 887 | priv->chips[I].start = priv->chips[I].length = 0; |
888 | 888 | ||
889 | // Intersect the region with each chip | 889 | // Intersect the region with each chip |
890 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | 890 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) |
891 | { | 891 | { |
892 | struct jedec_flash_chip *chip = priv->chips + I; | 892 | struct jedec_flash_chip *chip = priv->chips + I; |
893 | unsigned long ByteStart; | 893 | unsigned long ByteStart; |
894 | unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift); | 894 | unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift); |
895 | 895 | ||
896 | // End is before this chip or the start is after it | 896 | // End is before this chip or the start is after it |
897 | if (start+len < chip->offset || | 897 | if (start+len < chip->offset || |
898 | ChipEndByte - (1 << chip->addrshift) < start) | 898 | ChipEndByte - (1 << chip->addrshift) < start) |
899 | continue; | 899 | continue; |
900 | 900 | ||
901 | if (start < chip->offset) | 901 | if (start < chip->offset) |
902 | { | 902 | { |
903 | ByteStart = chip->offset; | 903 | ByteStart = chip->offset; |
904 | chip->start = 0; | 904 | chip->start = 0; |
905 | } | 905 | } |
906 | else | 906 | else |
907 | { | 907 | { |
908 | chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift; | 908 | chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift; |
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 30da428eb7b9..edb306c03c0a 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | Common Flash Interface probe code. | 2 | Common Flash Interface probe code. |
3 | (C) 2000 Red Hat. GPL'd. | 3 | (C) 2000 Red Hat. GPL'd. |
4 | $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $ | 4 | $Id: jedec_probe.c,v 1.66 2005/11/07 11:14:23 gleixner Exp $ |
5 | See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) | 5 | See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) |
6 | for the standard this probe goes back to. | 6 | for the standard this probe goes back to. |
7 | 7 | ||
@@ -1719,7 +1719,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
1719 | 1719 | ||
1720 | static struct mtd_info *jedec_probe(struct map_info *map); | 1720 | static struct mtd_info *jedec_probe(struct map_info *map); |
1721 | 1721 | ||
1722 | static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, | 1722 | static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, |
1723 | struct cfi_private *cfi) | 1723 | struct cfi_private *cfi) |
1724 | { | 1724 | { |
1725 | map_word result; | 1725 | map_word result; |
@@ -1730,7 +1730,7 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, | |||
1730 | return result.x[0] & mask; | 1730 | return result.x[0] & mask; |
1731 | } | 1731 | } |
1732 | 1732 | ||
1733 | static inline u32 jedec_read_id(struct map_info *map, __u32 base, | 1733 | static inline u32 jedec_read_id(struct map_info *map, __u32 base, |
1734 | struct cfi_private *cfi) | 1734 | struct cfi_private *cfi) |
1735 | { | 1735 | { |
1736 | map_word result; | 1736 | map_word result; |
@@ -1741,7 +1741,7 @@ static inline u32 jedec_read_id(struct map_info *map, __u32 base, | |||
1741 | return result.x[0] & mask; | 1741 | return result.x[0] & mask; |
1742 | } | 1742 | } |
1743 | 1743 | ||
1744 | static inline void jedec_reset(u32 base, struct map_info *map, | 1744 | static inline void jedec_reset(u32 base, struct map_info *map, |
1745 | struct cfi_private *cfi) | 1745 | struct cfi_private *cfi) |
1746 | { | 1746 | { |
1747 | /* Reset */ | 1747 | /* Reset */ |
@@ -1765,7 +1765,7 @@ static inline void jedec_reset(u32 base, struct map_info *map, | |||
1765 | * so ensure we're in read mode. Send both the Intel and the AMD command | 1765 | * so ensure we're in read mode. Send both the Intel and the AMD command |
1766 | * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so | 1766 | * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so |
1767 | * this should be safe. | 1767 | * this should be safe. |
1768 | */ | 1768 | */ |
1769 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | 1769 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); |
1770 | /* FIXME - should have reset delay before continuing */ | 1770 | /* FIXME - should have reset delay before continuing */ |
1771 | } | 1771 | } |
@@ -1807,14 +1807,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) | |||
1807 | printk("Found: %s\n",jedec_table[index].name); | 1807 | printk("Found: %s\n",jedec_table[index].name); |
1808 | 1808 | ||
1809 | num_erase_regions = jedec_table[index].NumEraseRegions; | 1809 | num_erase_regions = jedec_table[index].NumEraseRegions; |
1810 | 1810 | ||
1811 | p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); | 1811 | p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); |
1812 | if (!p_cfi->cfiq) { | 1812 | if (!p_cfi->cfiq) { |
1813 | //xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); | 1813 | //xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); |
1814 | return 0; | 1814 | return 0; |
1815 | } | 1815 | } |
1816 | 1816 | ||
1817 | memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); | 1817 | memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); |
1818 | 1818 | ||
1819 | p_cfi->cfiq->P_ID = jedec_table[index].CmdSet; | 1819 | p_cfi->cfiq->P_ID = jedec_table[index].CmdSet; |
1820 | p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions; | 1820 | p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions; |
@@ -1969,7 +1969,7 @@ static inline int jedec_match( __u32 base, | |||
1969 | cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); | 1969 | cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); |
1970 | /* FIXME - should have a delay before continuing */ | 1970 | /* FIXME - should have a delay before continuing */ |
1971 | 1971 | ||
1972 | match_done: | 1972 | match_done: |
1973 | return rc; | 1973 | return rc; |
1974 | } | 1974 | } |
1975 | 1975 | ||
@@ -1998,23 +1998,23 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
1998 | "Probe at base(0x%08x) past the end of the map(0x%08lx)\n", | 1998 | "Probe at base(0x%08x) past the end of the map(0x%08lx)\n", |
1999 | base, map->size -1); | 1999 | base, map->size -1); |
2000 | return 0; | 2000 | return 0; |
2001 | 2001 | ||
2002 | } | 2002 | } |
2003 | /* Ensure the unlock addresses we try stay inside the map */ | 2003 | /* Ensure the unlock addresses we try stay inside the map */ |
2004 | probe_offset1 = cfi_build_cmd_addr( | 2004 | probe_offset1 = cfi_build_cmd_addr( |
2005 | cfi->addr_unlock1, | 2005 | cfi->addr_unlock1, |
2006 | cfi_interleave(cfi), | 2006 | cfi_interleave(cfi), |
2007 | cfi->device_type); | 2007 | cfi->device_type); |
2008 | probe_offset2 = cfi_build_cmd_addr( | 2008 | probe_offset2 = cfi_build_cmd_addr( |
2009 | cfi->addr_unlock1, | 2009 | cfi->addr_unlock1, |
2010 | cfi_interleave(cfi), | 2010 | cfi_interleave(cfi), |
2011 | cfi->device_type); | 2011 | cfi->device_type); |
2012 | if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || | 2012 | if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || |
2013 | ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) | 2013 | ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) |
2014 | { | 2014 | { |
2015 | goto retry; | 2015 | goto retry; |
2016 | } | 2016 | } |
2017 | 2017 | ||
2018 | /* Reset */ | 2018 | /* Reset */ |
2019 | jedec_reset(base, map, cfi); | 2019 | jedec_reset(base, map, cfi); |
2020 | 2020 | ||
@@ -2027,13 +2027,13 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
2027 | /* FIXME - should have a delay before continuing */ | 2027 | /* FIXME - should have a delay before continuing */ |
2028 | 2028 | ||
2029 | if (!cfi->numchips) { | 2029 | if (!cfi->numchips) { |
2030 | /* This is the first time we're called. Set up the CFI | 2030 | /* This is the first time we're called. Set up the CFI |
2031 | stuff accordingly and return */ | 2031 | stuff accordingly and return */ |
2032 | 2032 | ||
2033 | cfi->mfr = jedec_read_mfr(map, base, cfi); | 2033 | cfi->mfr = jedec_read_mfr(map, base, cfi); |
2034 | cfi->id = jedec_read_id(map, base, cfi); | 2034 | cfi->id = jedec_read_id(map, base, cfi); |
2035 | DEBUG(MTD_DEBUG_LEVEL3, | 2035 | DEBUG(MTD_DEBUG_LEVEL3, |
2036 | "Search for id:(%02x %02x) interleave(%d) type(%d)\n", | 2036 | "Search for id:(%02x %02x) interleave(%d) type(%d)\n", |
2037 | cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); | 2037 | cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); |
2038 | for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) { | 2038 | for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) { |
2039 | if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { | 2039 | if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { |
@@ -2062,7 +2062,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
2062 | return 0; | 2062 | return 0; |
2063 | } | 2063 | } |
2064 | } | 2064 | } |
2065 | 2065 | ||
2066 | /* Check each previous chip locations to see if it's an alias */ | 2066 | /* Check each previous chip locations to see if it's an alias */ |
2067 | for (i=0; i < (base >> cfi->chipshift); i++) { | 2067 | for (i=0; i < (base >> cfi->chipshift); i++) { |
2068 | unsigned long start; | 2068 | unsigned long start; |
@@ -2083,7 +2083,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
2083 | map->name, base, start); | 2083 | map->name, base, start); |
2084 | return 0; | 2084 | return 0; |
2085 | } | 2085 | } |
2086 | 2086 | ||
2087 | /* Yes, it's actually got the device IDs as data. Most | 2087 | /* Yes, it's actually got the device IDs as data. Most |
2088 | * unfortunate. Stick the new chip in read mode | 2088 | * unfortunate. Stick the new chip in read mode |
2089 | * too and if it's the same, assume it's an alias. */ | 2089 | * too and if it's the same, assume it's an alias. */ |
@@ -2097,20 +2097,20 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
2097 | } | 2097 | } |
2098 | } | 2098 | } |
2099 | } | 2099 | } |
2100 | 2100 | ||
2101 | /* OK, if we got to here, then none of the previous chips appear to | 2101 | /* OK, if we got to here, then none of the previous chips appear to |
2102 | be aliases for the current one. */ | 2102 | be aliases for the current one. */ |
2103 | set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ | 2103 | set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ |
2104 | cfi->numchips++; | 2104 | cfi->numchips++; |
2105 | 2105 | ||
2106 | ok_out: | 2106 | ok_out: |
2107 | /* Put it back into Read Mode */ | 2107 | /* Put it back into Read Mode */ |
2108 | jedec_reset(base, map, cfi); | 2108 | jedec_reset(base, map, cfi); |
2109 | 2109 | ||
2110 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", | 2110 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", |
2111 | map->name, cfi_interleave(cfi), cfi->device_type*8, base, | 2111 | map->name, cfi_interleave(cfi), cfi->device_type*8, base, |
2112 | map->bankwidth*8); | 2112 | map->bankwidth*8); |
2113 | 2113 | ||
2114 | return 1; | 2114 | return 1; |
2115 | } | 2115 | } |
2116 | 2116 | ||
diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index c6c83833cc32..a611de9b1515 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Common code to handle absent "placeholder" devices | 2 | * Common code to handle absent "placeholder" devices |
3 | * Copyright 2001 Resilience Corporation <ebrower@resilience.com> | 3 | * Copyright 2001 Resilience Corporation <ebrower@resilience.com> |
4 | * $Id: map_absent.c,v 1.5 2004/11/16 18:29:00 dwmw2 Exp $ | 4 | * $Id: map_absent.c,v 1.6 2005/11/07 11:14:23 gleixner Exp $ |
5 | * | 5 | * |
6 | * This map driver is used to allocate "placeholder" MTD | 6 | * This map driver is used to allocate "placeholder" MTD |
7 | * devices on systems that have socketed/removable media. | 7 | * devices on systems that have socketed/removable media. |
8 | * Use of this driver as a fallback preserves the expected | 8 | * Use of this driver as a fallback preserves the expected |
9 | * registration of MTD device nodes regardless of probe outcome. | 9 | * registration of MTD device nodes regardless of probe outcome. |
10 | * A usage example is as follows: | 10 | * A usage example is as follows: |
11 | * | 11 | * |
@@ -80,7 +80,7 @@ static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
80 | static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) | 80 | static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) |
81 | { | 81 | { |
82 | *retlen = 0; | 82 | *retlen = 0; |
83 | return -ENODEV; | 83 | return -ENODEV; |
84 | } | 84 | } |
85 | 85 | ||
86 | static int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr) | 86 | static int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr) |
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c index c3cf0f63bc93..2d26bdef82d5 100644 --- a/drivers/mtd/chips/sharp.c +++ b/drivers/mtd/chips/sharp.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright 2000,2001 David A. Schleef <ds@schleef.org> | 4 | * Copyright 2000,2001 David A. Schleef <ds@schleef.org> |
5 | * 2000,2001 Lineo, Inc. | 5 | * 2000,2001 Lineo, Inc. |
6 | * | 6 | * |
7 | * $Id: sharp.c,v 1.14 2004/08/09 13:19:43 dwmw2 Exp $ | 7 | * $Id: sharp.c,v 1.16 2005/11/07 11:14:23 gleixner Exp $ |
8 | * | 8 | * |
9 | * Devices supported: | 9 | * Devices supported: |
10 | * LH28F016SCT Symmetrical block flash memory, 2Mx8 | 10 | * LH28F016SCT Symmetrical block flash memory, 2Mx8 |
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/mtd/cfi.h> | 31 | #include <linux/mtd/cfi.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/slab.h> | ||
34 | 35 | ||
35 | #define CMD_RESET 0xffffffff | 36 | #define CMD_RESET 0xffffffff |
36 | #define CMD_READ_ID 0x90909090 | 37 | #define CMD_READ_ID 0x90909090 |
@@ -214,7 +215,7 @@ static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd) | |||
214 | /* This function returns with the chip->mutex lock held. */ | 215 | /* This function returns with the chip->mutex lock held. */ |
215 | static int sharp_wait(struct map_info *map, struct flchip *chip) | 216 | static int sharp_wait(struct map_info *map, struct flchip *chip) |
216 | { | 217 | { |
217 | __u16 status; | 218 | int status, i; |
218 | unsigned long timeo = jiffies + HZ; | 219 | unsigned long timeo = jiffies + HZ; |
219 | DECLARE_WAITQUEUE(wait, current); | 220 | DECLARE_WAITQUEUE(wait, current); |
220 | int adr = 0; | 221 | int adr = 0; |
@@ -227,13 +228,11 @@ retry: | |||
227 | map_write32(map,CMD_READ_STATUS,adr); | 228 | map_write32(map,CMD_READ_STATUS,adr); |
228 | chip->state = FL_STATUS; | 229 | chip->state = FL_STATUS; |
229 | case FL_STATUS: | 230 | case FL_STATUS: |
230 | status = map_read32(map,adr); | 231 | for(i=0;i<100;i++){ |
231 | //printk("status=%08x\n",status); | 232 | status = map_read32(map,adr); |
232 | 233 | if((status & SR_READY)==SR_READY) | |
233 | udelay(100); | 234 | break; |
234 | if((status & SR_READY)!=SR_READY){ | 235 | udelay(1); |
235 | //printk(".status=%08x\n",status); | ||
236 | udelay(100); | ||
237 | } | 236 | } |
238 | break; | 237 | break; |
239 | default: | 238 | default: |
@@ -460,12 +459,12 @@ static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip, | |||
460 | remove_wait_queue(&chip->wq, &wait); | 459 | remove_wait_queue(&chip->wq, &wait); |
461 | 460 | ||
462 | //spin_lock_bh(chip->mutex); | 461 | //spin_lock_bh(chip->mutex); |
463 | 462 | ||
464 | if (signal_pending(current)){ | 463 | if (signal_pending(current)){ |
465 | ret = -EINTR; | 464 | ret = -EINTR; |
466 | goto out; | 465 | goto out; |
467 | } | 466 | } |
468 | 467 | ||
469 | } | 468 | } |
470 | ret = -ETIME; | 469 | ret = -ETIME; |
471 | out: | 470 | out: |
@@ -564,7 +563,7 @@ static int sharp_suspend(struct mtd_info *mtd) | |||
564 | static void sharp_resume(struct mtd_info *mtd) | 563 | static void sharp_resume(struct mtd_info *mtd) |
565 | { | 564 | { |
566 | printk("sharp_resume()\n"); | 565 | printk("sharp_resume()\n"); |
567 | 566 | ||
568 | } | 567 | } |
569 | 568 | ||
570 | static void sharp_destroy(struct mtd_info *mtd) | 569 | static void sharp_destroy(struct mtd_info *mtd) |
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index ef24837019d3..6b8bb2e4dcfd 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c | |||
@@ -1,24 +1,24 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $ | 2 | * $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $ |
3 | * | 3 | * |
4 | * Read flash partition table from command line | 4 | * Read flash partition table from command line |
5 | * | 5 | * |
6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
7 | * | 7 | * |
8 | * The format for the command line is as follows: | 8 | * The format for the command line is as follows: |
9 | * | 9 | * |
10 | * mtdparts=<mtddef>[;<mtddef] | 10 | * mtdparts=<mtddef>[;<mtddef] |
11 | * <mtddef> := <mtd-id>:<partdef>[,<partdef>] | 11 | * <mtddef> := <mtd-id>:<partdef>[,<partdef>] |
12 | * <partdef> := <size>[@offset][<name>][ro] | 12 | * <partdef> := <size>[@offset][<name>][ro] |
13 | * <mtd-id> := unique name used in mapping driver/device (mtd->name) | 13 | * <mtd-id> := unique name used in mapping driver/device (mtd->name) |
14 | * <size> := standard linux memsize OR "-" to denote all remaining space | 14 | * <size> := standard linux memsize OR "-" to denote all remaining space |
15 | * <name> := '(' NAME ')' | 15 | * <name> := '(' NAME ')' |
16 | * | 16 | * |
17 | * Examples: | 17 | * Examples: |
18 | * | 18 | * |
19 | * 1 NOR Flash, with 1 single writable partition: | 19 | * 1 NOR Flash, with 1 single writable partition: |
20 | * edb7312-nor:- | 20 | * edb7312-nor:- |
21 | * | 21 | * |
22 | * 1 NOR Flash with 2 partitions, 1 NAND with one | 22 | * 1 NOR Flash with 2 partitions, 1 NAND with one |
23 | * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) | 23 | * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) |
24 | */ | 24 | */ |
@@ -60,17 +60,17 @@ static int cmdline_parsed = 0; | |||
60 | 60 | ||
61 | /* | 61 | /* |
62 | * Parse one partition definition for an MTD. Since there can be many | 62 | * Parse one partition definition for an MTD. Since there can be many |
63 | * comma separated partition definitions, this function calls itself | 63 | * comma separated partition definitions, this function calls itself |
64 | * recursively until no more partition definitions are found. Nice side | 64 | * recursively until no more partition definitions are found. Nice side |
65 | * effect: the memory to keep the mtd_partition structs and the names | 65 | * effect: the memory to keep the mtd_partition structs and the names |
66 | * is allocated upon the last definition being found. At that point the | 66 | * is allocated upon the last definition being found. At that point the |
67 | * syntax has been verified ok. | 67 | * syntax has been verified ok. |
68 | */ | 68 | */ |
69 | static struct mtd_partition * newpart(char *s, | 69 | static struct mtd_partition * newpart(char *s, |
70 | char **retptr, | 70 | char **retptr, |
71 | int *num_parts, | 71 | int *num_parts, |
72 | int this_part, | 72 | int this_part, |
73 | unsigned char **extra_mem_ptr, | 73 | unsigned char **extra_mem_ptr, |
74 | int extra_mem_size) | 74 | int extra_mem_size) |
75 | { | 75 | { |
76 | struct mtd_partition *parts; | 76 | struct mtd_partition *parts; |
@@ -102,7 +102,7 @@ static struct mtd_partition * newpart(char *s, | |||
102 | mask_flags = 0; /* this is going to be a regular partition */ | 102 | mask_flags = 0; /* this is going to be a regular partition */ |
103 | delim = 0; | 103 | delim = 0; |
104 | /* check for offset */ | 104 | /* check for offset */ |
105 | if (*s == '@') | 105 | if (*s == '@') |
106 | { | 106 | { |
107 | s++; | 107 | s++; |
108 | offset = memparse(s, &s); | 108 | offset = memparse(s, &s); |
@@ -112,7 +112,7 @@ static struct mtd_partition * newpart(char *s, | |||
112 | { | 112 | { |
113 | delim = ')'; | 113 | delim = ')'; |
114 | } | 114 | } |
115 | 115 | ||
116 | if (delim) | 116 | if (delim) |
117 | { | 117 | { |
118 | char *p; | 118 | char *p; |
@@ -131,12 +131,12 @@ static struct mtd_partition * newpart(char *s, | |||
131 | name = NULL; | 131 | name = NULL; |
132 | name_len = 13; /* Partition_000 */ | 132 | name_len = 13; /* Partition_000 */ |
133 | } | 133 | } |
134 | 134 | ||
135 | /* record name length for memory allocation later */ | 135 | /* record name length for memory allocation later */ |
136 | extra_mem_size += name_len + 1; | 136 | extra_mem_size += name_len + 1; |
137 | 137 | ||
138 | /* test for options */ | 138 | /* test for options */ |
139 | if (strncmp(s, "ro", 2) == 0) | 139 | if (strncmp(s, "ro", 2) == 0) |
140 | { | 140 | { |
141 | mask_flags |= MTD_WRITEABLE; | 141 | mask_flags |= MTD_WRITEABLE; |
142 | s += 2; | 142 | s += 2; |
@@ -151,7 +151,7 @@ static struct mtd_partition * newpart(char *s, | |||
151 | return NULL; | 151 | return NULL; |
152 | } | 152 | } |
153 | /* more partitions follow, parse them */ | 153 | /* more partitions follow, parse them */ |
154 | if ((parts = newpart(s + 1, &s, num_parts, | 154 | if ((parts = newpart(s + 1, &s, num_parts, |
155 | this_part + 1, &extra_mem, extra_mem_size)) == 0) | 155 | this_part + 1, &extra_mem, extra_mem_size)) == 0) |
156 | return NULL; | 156 | return NULL; |
157 | } | 157 | } |
@@ -187,7 +187,7 @@ static struct mtd_partition * newpart(char *s, | |||
187 | extra_mem += name_len + 1; | 187 | extra_mem += name_len + 1; |
188 | 188 | ||
189 | dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", | 189 | dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", |
190 | this_part, | 190 | this_part, |
191 | parts[this_part].name, | 191 | parts[this_part].name, |
192 | parts[this_part].offset, | 192 | parts[this_part].offset, |
193 | parts[this_part].size, | 193 | parts[this_part].size, |
@@ -204,8 +204,8 @@ static struct mtd_partition * newpart(char *s, | |||
204 | return parts; | 204 | return parts; |
205 | } | 205 | } |
206 | 206 | ||
207 | /* | 207 | /* |
208 | * Parse the command line. | 208 | * Parse the command line. |
209 | */ | 209 | */ |
210 | static int mtdpart_setup_real(char *s) | 210 | static int mtdpart_setup_real(char *s) |
211 | { | 211 | { |
@@ -230,7 +230,7 @@ static int mtdpart_setup_real(char *s) | |||
230 | 230 | ||
231 | dbg(("parsing <%s>\n", p+1)); | 231 | dbg(("parsing <%s>\n", p+1)); |
232 | 232 | ||
233 | /* | 233 | /* |
234 | * parse one mtd. have it reserve memory for the | 234 | * parse one mtd. have it reserve memory for the |
235 | * struct cmdline_mtd_partition and the mtd-id string. | 235 | * struct cmdline_mtd_partition and the mtd-id string. |
236 | */ | 236 | */ |
@@ -239,7 +239,7 @@ static int mtdpart_setup_real(char *s) | |||
239 | &num_parts, /* out: number of parts */ | 239 | &num_parts, /* out: number of parts */ |
240 | 0, /* first partition */ | 240 | 0, /* first partition */ |
241 | (unsigned char**)&this_mtd, /* out: extra mem */ | 241 | (unsigned char**)&this_mtd, /* out: extra mem */ |
242 | mtd_id_len + 1 + sizeof(*this_mtd) + | 242 | mtd_id_len + 1 + sizeof(*this_mtd) + |
243 | sizeof(void*)-1 /*alignment*/); | 243 | sizeof(void*)-1 /*alignment*/); |
244 | if(!parts) | 244 | if(!parts) |
245 | { | 245 | { |
@@ -254,21 +254,21 @@ static int mtdpart_setup_real(char *s) | |||
254 | } | 254 | } |
255 | 255 | ||
256 | /* align this_mtd */ | 256 | /* align this_mtd */ |
257 | this_mtd = (struct cmdline_mtd_partition *) | 257 | this_mtd = (struct cmdline_mtd_partition *) |
258 | ALIGN((unsigned long)this_mtd, sizeof(void*)); | 258 | ALIGN((unsigned long)this_mtd, sizeof(void*)); |
259 | /* enter results */ | 259 | /* enter results */ |
260 | this_mtd->parts = parts; | 260 | this_mtd->parts = parts; |
261 | this_mtd->num_parts = num_parts; | 261 | this_mtd->num_parts = num_parts; |
262 | this_mtd->mtd_id = (char*)(this_mtd + 1); | 262 | this_mtd->mtd_id = (char*)(this_mtd + 1); |
263 | strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); | 263 | strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); |
264 | 264 | ||
265 | /* link into chain */ | 265 | /* link into chain */ |
266 | this_mtd->next = partitions; | 266 | this_mtd->next = partitions; |
267 | partitions = this_mtd; | 267 | partitions = this_mtd; |
268 | 268 | ||
269 | dbg(("mtdid=<%s> num_parts=<%d>\n", | 269 | dbg(("mtdid=<%s> num_parts=<%d>\n", |
270 | this_mtd->mtd_id, this_mtd->num_parts)); | 270 | this_mtd->mtd_id, this_mtd->num_parts)); |
271 | 271 | ||
272 | 272 | ||
273 | /* EOS - we're done */ | 273 | /* EOS - we're done */ |
274 | if (*s == 0) | 274 | if (*s == 0) |
@@ -292,7 +292,7 @@ static int mtdpart_setup_real(char *s) | |||
292 | * information. It returns partitions for the requested mtd device, or | 292 | * information. It returns partitions for the requested mtd device, or |
293 | * the first one in the chain if a NULL mtd_id is passed in. | 293 | * the first one in the chain if a NULL mtd_id is passed in. |
294 | */ | 294 | */ |
295 | static int parse_cmdline_partitions(struct mtd_info *master, | 295 | static int parse_cmdline_partitions(struct mtd_info *master, |
296 | struct mtd_partition **pparts, | 296 | struct mtd_partition **pparts, |
297 | unsigned long origin) | 297 | unsigned long origin) |
298 | { | 298 | { |
@@ -322,7 +322,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, | |||
322 | part->parts[i].size = master->size - offset; | 322 | part->parts[i].size = master->size - offset; |
323 | if (offset + part->parts[i].size > master->size) | 323 | if (offset + part->parts[i].size > master->size) |
324 | { | 324 | { |
325 | printk(KERN_WARNING ERRP | 325 | printk(KERN_WARNING ERRP |
326 | "%s: partitioning exceeds flash size, truncating\n", | 326 | "%s: partitioning exceeds flash size, truncating\n", |
327 | part->mtd_id); | 327 | part->mtd_id); |
328 | part->parts[i].size = master->size - offset; | 328 | part->parts[i].size = master->size - offset; |
@@ -338,8 +338,8 @@ static int parse_cmdline_partitions(struct mtd_info *master, | |||
338 | } | 338 | } |
339 | 339 | ||
340 | 340 | ||
341 | /* | 341 | /* |
342 | * This is the handler for our kernel parameter, called from | 342 | * This is the handler for our kernel parameter, called from |
343 | * main.c::checksetup(). Note that we can not yet kmalloc() anything, | 343 | * main.c::checksetup(). Note that we can not yet kmalloc() anything, |
344 | * so we only save the commandline for later processing. | 344 | * so we only save the commandline for later processing. |
345 | * | 345 | * |
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index c4a56a4ac5e2..9a2aa4033c6a 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/maps/Kconfig | 1 | # drivers/mtd/maps/Kconfig |
2 | # $Id: Kconfig,v 1.15 2004/12/22 17:51:15 joern Exp $ | 2 | # $Id: Kconfig,v 1.18 2005/11/07 11:14:24 gleixner Exp $ |
3 | 3 | ||
4 | menu "Self-contained MTD device drivers" | 4 | menu "Self-contained MTD device drivers" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -110,7 +110,7 @@ config MTDRAM_ABS_POS | |||
110 | If you have system RAM accessible by the CPU but not used by Linux | 110 | If you have system RAM accessible by the CPU but not used by Linux |
111 | in normal operation, you can give the physical address at which the | 111 | in normal operation, you can give the physical address at which the |
112 | available RAM starts, and the MTDRAM driver will use it instead of | 112 | available RAM starts, and the MTDRAM driver will use it instead of |
113 | allocating space from Linux's available memory. Otherwise, leave | 113 | allocating space from Linux's available memory. Otherwise, leave |
114 | this set to zero. Most people will want to leave this as zero. | 114 | this set to zero. Most people will want to leave this as zero. |
115 | 115 | ||
116 | config MTD_BLKMTD | 116 | config MTD_BLKMTD |
@@ -165,7 +165,7 @@ config MTD_DOC2001 | |||
165 | select MTD_DOCPROBE | 165 | select MTD_DOCPROBE |
166 | select MTD_NAND_IDS | 166 | select MTD_NAND_IDS |
167 | ---help--- | 167 | ---help--- |
168 | This provides an alternative MTD device driver for the M-Systems | 168 | This provides an alternative MTD device driver for the M-Systems |
169 | DiskOnChip Millennium devices. Use this if you have problems with | 169 | DiskOnChip Millennium devices. Use this if you have problems with |
170 | the combined DiskOnChip 2000 and Millennium driver above. To get | 170 | the combined DiskOnChip 2000 and Millennium driver above. To get |
171 | the DiskOnChip probe code to load and use this driver instead of | 171 | the DiskOnChip probe code to load and use this driver instead of |
@@ -192,7 +192,7 @@ config MTD_DOC2001PLUS | |||
192 | 192 | ||
193 | If you use this device, you probably also want to enable the INFTL | 193 | If you use this device, you probably also want to enable the INFTL |
194 | 'Inverse NAND Flash Translation Layer' option below, which is used | 194 | 'Inverse NAND Flash Translation Layer' option below, which is used |
195 | to emulate a block device by using a kind of file system on the | 195 | to emulate a block device by using a kind of file system on the |
196 | flash chips. | 196 | flash chips. |
197 | 197 | ||
198 | NOTE: This driver will soon be replaced by the new DiskOnChip driver | 198 | NOTE: This driver will soon be replaced by the new DiskOnChip driver |
diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c index 59a29e616a22..f9db52f6bf00 100644 --- a/drivers/mtd/devices/blkmtd.c +++ b/drivers/mtd/devices/blkmtd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: blkmtd.c,v 1.24 2004/11/16 18:29:01 dwmw2 Exp $ | 2 | * $Id: blkmtd.c,v 1.27 2005/11/07 11:14:24 gleixner Exp $ |
3 | * | 3 | * |
4 | * blkmtd.c - use a block device as a fake MTD | 4 | * blkmtd.c - use a block device as a fake MTD |
5 | * | 5 | * |
@@ -39,7 +39,7 @@ | |||
39 | 39 | ||
40 | /* Default erase size in K, always make it a multiple of PAGE_SIZE */ | 40 | /* Default erase size in K, always make it a multiple of PAGE_SIZE */ |
41 | #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */ | 41 | #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */ |
42 | #define VERSION "$Revision: 1.24 $" | 42 | #define VERSION "$Revision: 1.27 $" |
43 | 43 | ||
44 | /* Info for the block device */ | 44 | /* Info for the block device */ |
45 | struct blkmtd_dev { | 45 | struct blkmtd_dev { |
@@ -117,7 +117,7 @@ static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error | |||
117 | unlock_page(page); | 117 | unlock_page(page); |
118 | page_cache_release(page); | 118 | page_cache_release(page); |
119 | } while (bvec >= bio->bi_io_vec); | 119 | } while (bvec >= bio->bi_io_vec); |
120 | 120 | ||
121 | complete((struct completion*)bio->bi_private); | 121 | complete((struct completion*)bio->bi_private); |
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
@@ -135,7 +135,7 @@ static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page) | |||
135 | unlock_page(page); | 135 | unlock_page(page); |
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | 138 | ||
139 | ClearPageUptodate(page); | 139 | ClearPageUptodate(page); |
140 | ClearPageError(page); | 140 | ClearPageError(page); |
141 | 141 | ||
@@ -707,7 +707,7 @@ static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size | |||
707 | dev->mtd_info.erasesize >> 10, | 707 | dev->mtd_info.erasesize >> 10, |
708 | readonly ? "(read-only)" : ""); | 708 | readonly ? "(read-only)" : ""); |
709 | } | 709 | } |
710 | 710 | ||
711 | return dev; | 711 | return dev; |
712 | 712 | ||
713 | devinit_err: | 713 | devinit_err: |
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 4a7a805e7564..0aaa0ced9aba 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $ | 2 | * $Id: block2mtd.c,v 1.29 2005/11/07 11:14:24 gleixner Exp $ |
3 | * | 3 | * |
4 | * block2mtd.c - create an mtd from a block device | 4 | * block2mtd.c - create an mtd from a block device |
5 | * | 5 | * |
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/mtd/mtd.h> | 19 | #include <linux/mtd/mtd.h> |
20 | #include <linux/buffer_head.h> | 20 | #include <linux/buffer_head.h> |
21 | 21 | ||
22 | #define VERSION "$Revision: 1.28 $" | 22 | #define VERSION "$Revision: 1.29 $" |
23 | 23 | ||
24 | 24 | ||
25 | #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) | 25 | #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) |
@@ -111,7 +111,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) | |||
111 | return PTR_ERR(page); | 111 | return PTR_ERR(page); |
112 | 112 | ||
113 | max = (u_long*)page_address(page) + PAGE_SIZE; | 113 | max = (u_long*)page_address(page) + PAGE_SIZE; |
114 | for (p=(u_long*)page_address(page); p<max; p++) | 114 | for (p=(u_long*)page_address(page); p<max; p++) |
115 | if (*p != -1UL) { | 115 | if (*p != -1UL) { |
116 | lock_page(page); | 116 | lock_page(page); |
117 | memset(page_address(page), 0xff, PAGE_SIZE); | 117 | memset(page_address(page), 0xff, PAGE_SIZE); |
@@ -206,7 +206,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, | |||
206 | if (retlen) | 206 | if (retlen) |
207 | *retlen = 0; | 207 | *retlen = 0; |
208 | while (len) { | 208 | while (len) { |
209 | if ((offset+len) > PAGE_SIZE) | 209 | if ((offset+len) > PAGE_SIZE) |
210 | cpylen = PAGE_SIZE - offset; // multiple pages | 210 | cpylen = PAGE_SIZE - offset; // multiple pages |
211 | else | 211 | else |
212 | cpylen = len; // this page | 212 | cpylen = len; // this page |
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 5fc532895a24..be5e88b3888d 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (c) 1999 Machine Vision Holdings, Inc. | 4 | * (c) 1999 Machine Vision Holdings, Inc. |
5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
6 | * | 6 | * |
7 | * $Id: doc2000.c,v 1.66 2005/01/05 18:05:12 dwmw2 Exp $ | 7 | * $Id: doc2000.c,v 1.67 2005/11/07 11:14:24 gleixner Exp $ |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -58,7 +58,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
58 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); | 58 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); |
59 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | 59 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, |
60 | size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); | 60 | size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); |
61 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | 61 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, |
62 | unsigned long count, loff_t to, size_t *retlen, | 62 | unsigned long count, loff_t to, size_t *retlen, |
63 | u_char *eccbuf, struct nand_oobinfo *oobsel); | 63 | u_char *eccbuf, struct nand_oobinfo *oobsel); |
64 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | 64 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, |
@@ -76,14 +76,14 @@ static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles) | |||
76 | { | 76 | { |
77 | volatile char dummy; | 77 | volatile char dummy; |
78 | int i; | 78 | int i; |
79 | 79 | ||
80 | for (i = 0; i < cycles; i++) { | 80 | for (i = 0; i < cycles; i++) { |
81 | if (DoC_is_Millennium(doc)) | 81 | if (DoC_is_Millennium(doc)) |
82 | dummy = ReadDOC(doc->virtadr, NOP); | 82 | dummy = ReadDOC(doc->virtadr, NOP); |
83 | else | 83 | else |
84 | dummy = ReadDOC(doc->virtadr, DOCStatus); | 84 | dummy = ReadDOC(doc->virtadr, DOCStatus); |
85 | } | 85 | } |
86 | 86 | ||
87 | } | 87 | } |
88 | 88 | ||
89 | /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ | 89 | /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ |
@@ -220,8 +220,8 @@ static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs, | |||
220 | WriteDOC(ofs & 0xff, docptr, WritePipeTerm); | 220 | WriteDOC(ofs & 0xff, docptr, WritePipeTerm); |
221 | 221 | ||
222 | DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */ | 222 | DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */ |
223 | 223 | ||
224 | /* FIXME: The SlowIO's for millennium could be replaced by | 224 | /* FIXME: The SlowIO's for millennium could be replaced by |
225 | a single WritePipeTerm here. mf. */ | 225 | a single WritePipeTerm here. mf. */ |
226 | 226 | ||
227 | /* Lower the ALE line */ | 227 | /* Lower the ALE line */ |
@@ -377,9 +377,9 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
377 | if (mfr == 0xff || mfr == 0) | 377 | if (mfr == 0xff || mfr == 0) |
378 | return 0; | 378 | return 0; |
379 | 379 | ||
380 | /* Check it's the same as the first chip we identified. | 380 | /* Check it's the same as the first chip we identified. |
381 | * M-Systems say that any given DiskOnChip device should only | 381 | * M-Systems say that any given DiskOnChip device should only |
382 | * contain _one_ type of flash part, although that's not a | 382 | * contain _one_ type of flash part, although that's not a |
383 | * hardware restriction. */ | 383 | * hardware restriction. */ |
384 | if (doc->mfr) { | 384 | if (doc->mfr) { |
385 | if (doc->mfr == mfr && doc->id == id) | 385 | if (doc->mfr == mfr && doc->id == id) |
@@ -397,7 +397,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
397 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { | 397 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { |
398 | if (nand_manuf_ids[j].id == mfr) | 398 | if (nand_manuf_ids[j].id == mfr) |
399 | break; | 399 | break; |
400 | } | 400 | } |
401 | printk(KERN_INFO | 401 | printk(KERN_INFO |
402 | "Flash chip found: Manufacturer ID: %2.2X, " | 402 | "Flash chip found: Manufacturer ID: %2.2X, " |
403 | "Chip ID: %2.2X (%s:%s)\n", mfr, id, | 403 | "Chip ID: %2.2X (%s:%s)\n", mfr, id, |
@@ -405,7 +405,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
405 | if (!doc->mfr) { | 405 | if (!doc->mfr) { |
406 | doc->mfr = mfr; | 406 | doc->mfr = mfr; |
407 | doc->id = id; | 407 | doc->id = id; |
408 | doc->chipshift = | 408 | doc->chipshift = |
409 | ffs((nand_flash_ids[i].chipsize << 20)) - 1; | 409 | ffs((nand_flash_ids[i].chipsize << 20)) - 1; |
410 | doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0; | 410 | doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0; |
411 | doc->pageadrlen = doc->chipshift > 25 ? 3 : 2; | 411 | doc->pageadrlen = doc->chipshift > 25 ? 3 : 2; |
@@ -467,7 +467,7 @@ static void DoC_ScanChips(struct DiskOnChip *this, int maxchips) | |||
467 | 467 | ||
468 | ret = 0; | 468 | ret = 0; |
469 | 469 | ||
470 | /* Fill out the chip array with {floor, chipno} for each | 470 | /* Fill out the chip array with {floor, chipno} for each |
471 | * detected chip in the device. */ | 471 | * detected chip in the device. */ |
472 | for (floor = 0; floor < MAX_FLOORS; floor++) { | 472 | for (floor = 0; floor < MAX_FLOORS; floor++) { |
473 | for (chip = 0; chip < numchips[floor]; chip++) { | 473 | for (chip = 0; chip < numchips[floor]; chip++) { |
@@ -757,12 +757,12 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
757 | (long)from, eccbuf[0], eccbuf[1], eccbuf[2], | 757 | (long)from, eccbuf[0], eccbuf[1], eccbuf[2], |
758 | eccbuf[3], eccbuf[4], eccbuf[5]); | 758 | eccbuf[3], eccbuf[4], eccbuf[5]); |
759 | #endif | 759 | #endif |
760 | 760 | ||
761 | /* disable the ECC engine */ | 761 | /* disable the ECC engine */ |
762 | WriteDOC(DOC_ECC_DIS, docptr , ECCConf); | 762 | WriteDOC(DOC_ECC_DIS, docptr , ECCConf); |
763 | } | 763 | } |
764 | 764 | ||
765 | /* according to 11.4.1, we need to wait for the busy line | 765 | /* according to 11.4.1, we need to wait for the busy line |
766 | * drop if we read to the end of the page. */ | 766 | * drop if we read to the end of the page. */ |
767 | if(0 == ((from + len) & 0x1ff)) | 767 | if(0 == ((from + len) & 0x1ff)) |
768 | { | 768 | { |
@@ -941,7 +941,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
941 | 941 | ||
942 | /* Let the caller know we completed it */ | 942 | /* Let the caller know we completed it */ |
943 | *retlen += len; | 943 | *retlen += len; |
944 | 944 | ||
945 | if (eccbuf) { | 945 | if (eccbuf) { |
946 | unsigned char x[8]; | 946 | unsigned char x[8]; |
947 | size_t dummy; | 947 | size_t dummy; |
@@ -950,10 +950,10 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
950 | /* Write the ECC data to flash */ | 950 | /* Write the ECC data to flash */ |
951 | for (di=0; di<6; di++) | 951 | for (di=0; di<6; di++) |
952 | x[di] = eccbuf[di]; | 952 | x[di] = eccbuf[di]; |
953 | 953 | ||
954 | x[6]=0x55; | 954 | x[6]=0x55; |
955 | x[7]=0x55; | 955 | x[7]=0x55; |
956 | 956 | ||
957 | ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); | 957 | ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); |
958 | if (ret) { | 958 | if (ret) { |
959 | up(&this->lock); | 959 | up(&this->lock); |
@@ -970,7 +970,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
970 | return 0; | 970 | return 0; |
971 | } | 971 | } |
972 | 972 | ||
973 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | 973 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, |
974 | unsigned long count, loff_t to, size_t *retlen, | 974 | unsigned long count, loff_t to, size_t *retlen, |
975 | u_char *eccbuf, struct nand_oobinfo *oobsel) | 975 | u_char *eccbuf, struct nand_oobinfo *oobsel) |
976 | { | 976 | { |
@@ -1022,7 +1022,7 @@ static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | |||
1022 | break; | 1022 | break; |
1023 | 1023 | ||
1024 | to += thislen; | 1024 | to += thislen; |
1025 | } | 1025 | } |
1026 | 1026 | ||
1027 | up(&writev_buf_sem); | 1027 | up(&writev_buf_sem); |
1028 | *retlen = totretlen; | 1028 | *retlen = totretlen; |
@@ -1080,7 +1080,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | |||
1080 | /* Reading the full OOB data drops us off of the end of the page, | 1080 | /* Reading the full OOB data drops us off of the end of the page, |
1081 | * causing the flash device to go into busy mode, so we need | 1081 | * causing the flash device to go into busy mode, so we need |
1082 | * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ | 1082 | * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ |
1083 | 1083 | ||
1084 | ret = DoC_WaitReady(this); | 1084 | ret = DoC_WaitReady(this); |
1085 | 1085 | ||
1086 | up(&this->lock); | 1086 | up(&this->lock); |
@@ -1190,7 +1190,7 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len, | |||
1190 | return 0; | 1190 | return 0; |
1191 | 1191 | ||
1192 | } | 1192 | } |
1193 | 1193 | ||
1194 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | 1194 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, |
1195 | size_t * retlen, const u_char * buf) | 1195 | size_t * retlen, const u_char * buf) |
1196 | { | 1196 | { |
@@ -1222,7 +1222,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1222 | } | 1222 | } |
1223 | 1223 | ||
1224 | instr->state = MTD_ERASING; | 1224 | instr->state = MTD_ERASING; |
1225 | 1225 | ||
1226 | /* FIXME: Do this in the background. Use timers or schedule_task() */ | 1226 | /* FIXME: Do this in the background. Use timers or schedule_task() */ |
1227 | while(len) { | 1227 | while(len) { |
1228 | mychip = &this->chips[ofs >> this->chipshift]; | 1228 | mychip = &this->chips[ofs >> this->chipshift]; |
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 1e704915ef08..fcb28a6fd89f 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (c) 1999 Machine Vision Holdings, Inc. | 4 | * (c) 1999 Machine Vision Holdings, Inc. |
5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 5 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
6 | * | 6 | * |
7 | * $Id: doc2001.c,v 1.48 2005/01/05 18:05:12 dwmw2 Exp $ | 7 | * $Id: doc2001.c,v 1.49 2005/11/07 11:14:24 gleixner Exp $ |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -196,10 +196,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
196 | DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP); | 196 | DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP); |
197 | DoC_WaitReady(doc->virtadr); | 197 | DoC_WaitReady(doc->virtadr); |
198 | 198 | ||
199 | /* Read the NAND chip ID: 1. Send ReadID command */ | 199 | /* Read the NAND chip ID: 1. Send ReadID command */ |
200 | DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP); | 200 | DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP); |
201 | 201 | ||
202 | /* Read the NAND chip ID: 2. Send address byte zero */ | 202 | /* Read the NAND chip ID: 2. Send address byte zero */ |
203 | DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00); | 203 | DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00); |
204 | 204 | ||
205 | /* Read the manufacturer and device id codes of the flash device through | 205 | /* Read the manufacturer and device id codes of the flash device through |
@@ -223,7 +223,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
223 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { | 223 | for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { |
224 | if (nand_manuf_ids[j].id == mfr) | 224 | if (nand_manuf_ids[j].id == mfr) |
225 | break; | 225 | break; |
226 | } | 226 | } |
227 | printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " | 227 | printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " |
228 | "Chip ID: %2.2X (%s:%s)\n", | 228 | "Chip ID: %2.2X (%s:%s)\n", |
229 | mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name); | 229 | mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name); |
@@ -275,7 +275,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) | |||
275 | return; | 275 | return; |
276 | } | 276 | } |
277 | 277 | ||
278 | /* Fill out the chip array with {floor, chipno} for each | 278 | /* Fill out the chip array with {floor, chipno} for each |
279 | * detected chip in the device. */ | 279 | * detected chip in the device. */ |
280 | for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) { | 280 | for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) { |
281 | for (chip = 0 ; chip < numchips[floor] ; chip++) { | 281 | for (chip = 0 ; chip < numchips[floor] ; chip++) { |
@@ -309,7 +309,7 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) | |||
309 | tmp2 = ReadDOC(doc2->virtadr, AliasResolution); | 309 | tmp2 = ReadDOC(doc2->virtadr, AliasResolution); |
310 | if (tmp1 != tmp2) | 310 | if (tmp1 != tmp2) |
311 | return 0; | 311 | return 0; |
312 | 312 | ||
313 | WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution); | 313 | WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution); |
314 | tmp2 = ReadDOC(doc2->virtadr, AliasResolution); | 314 | tmp2 = ReadDOC(doc2->virtadr, AliasResolution); |
315 | if (tmp2 == (tmp1+1) % 0xff) | 315 | if (tmp2 == (tmp1+1) % 0xff) |
@@ -425,7 +425,7 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
425 | return -EINVAL; | 425 | return -EINVAL; |
426 | 426 | ||
427 | /* Don't allow a single read to cross a 512-byte block boundary */ | 427 | /* Don't allow a single read to cross a 512-byte block boundary */ |
428 | if (from + len > ((from | 0x1ff) + 1)) | 428 | if (from + len > ((from | 0x1ff) + 1)) |
429 | len = ((from | 0x1ff) + 1) - from; | 429 | len = ((from | 0x1ff) + 1) - from; |
430 | 430 | ||
431 | /* Find the chip which is to be used and select it */ | 431 | /* Find the chip which is to be used and select it */ |
@@ -552,7 +552,7 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
552 | 552 | ||
553 | #if 0 | 553 | #if 0 |
554 | /* Don't allow a single write to cross a 512-byte block boundary */ | 554 | /* Don't allow a single write to cross a 512-byte block boundary */ |
555 | if (to + len > ( (to | 0x1ff) + 1)) | 555 | if (to + len > ( (to | 0x1ff) + 1)) |
556 | len = ((to | 0x1ff) + 1) - to; | 556 | len = ((to | 0x1ff) + 1) - to; |
557 | #else | 557 | #else |
558 | /* Don't allow writes which aren't exactly one block */ | 558 | /* Don't allow writes which aren't exactly one block */ |
@@ -632,7 +632,7 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
632 | 632 | ||
633 | /* write the block status BLOCK_USED (0x5555) at the end of ECC data | 633 | /* write the block status BLOCK_USED (0x5555) at the end of ECC data |
634 | FIXME: this is only a hack for programming the IPL area for LinuxBIOS | 634 | FIXME: this is only a hack for programming the IPL area for LinuxBIOS |
635 | and should be replace with proper codes in user space utilities */ | 635 | and should be replace with proper codes in user space utilities */ |
636 | WriteDOC(0x55, docptr, Mil_CDSN_IO); | 636 | WriteDOC(0x55, docptr, Mil_CDSN_IO); |
637 | WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); | 637 | WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); |
638 | 638 | ||
@@ -802,7 +802,7 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr) | |||
802 | void __iomem *docptr = this->virtadr; | 802 | void __iomem *docptr = this->virtadr; |
803 | struct Nand *mychip = &this->chips[ofs >> this->chipshift]; | 803 | struct Nand *mychip = &this->chips[ofs >> this->chipshift]; |
804 | 804 | ||
805 | if (len != mtd->erasesize) | 805 | if (len != mtd->erasesize) |
806 | printk(KERN_WARNING "Erase not right size (%x != %x)n", | 806 | printk(KERN_WARNING "Erase not right size (%x != %x)n", |
807 | len, mtd->erasesize); | 807 | len, mtd->erasesize); |
808 | 808 | ||
@@ -870,9 +870,9 @@ static void __exit cleanup_doc2001(void) | |||
870 | while ((mtd=docmillist)) { | 870 | while ((mtd=docmillist)) { |
871 | this = mtd->priv; | 871 | this = mtd->priv; |
872 | docmillist = this->nextdoc; | 872 | docmillist = this->nextdoc; |
873 | 873 | ||
874 | del_mtd_device(mtd); | 874 | del_mtd_device(mtd); |
875 | 875 | ||
876 | iounmap(this->virtadr); | 876 | iounmap(this->virtadr); |
877 | kfree(this->chips); | 877 | kfree(this->chips); |
878 | kfree(mtd); | 878 | kfree(mtd); |
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index ed47bafb2ce2..0595cc7324b2 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * (c) 1999 Machine Vision Holdings, Inc. | 6 | * (c) 1999 Machine Vision Holdings, Inc. |
7 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> | 7 | * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> |
8 | * | 8 | * |
9 | * $Id: doc2001plus.c,v 1.13 2005/01/05 18:05:12 dwmw2 Exp $ | 9 | * $Id: doc2001plus.c,v 1.14 2005/11/07 11:14:24 gleixner Exp $ |
10 | * | 10 | * |
11 | * Released under GPL | 11 | * Released under GPL |
12 | */ | 12 | */ |
@@ -293,10 +293,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) | |||
293 | DoC_Command(docptr, NAND_CMD_RESET, 0); | 293 | DoC_Command(docptr, NAND_CMD_RESET, 0); |
294 | DoC_WaitReady(docptr); | 294 | DoC_WaitReady(docptr); |
295 | 295 | ||
296 | /* Read the NAND chip ID: 1. Send ReadID command */ | 296 | /* Read the NAND chip ID: 1. Send ReadID command */ |
297 | DoC_Command(docptr, NAND_CMD_READID, 0); | 297 | DoC_Command(docptr, NAND_CMD_READID, 0); |
298 | 298 | ||
299 | /* Read the NAND chip ID: 2. Send address byte zero */ | 299 | /* Read the NAND chip ID: 2. Send address byte zero */ |
300 | DoC_Address(doc, 1, 0x00, 0, 0x00); | 300 | DoC_Address(doc, 1, 0x00, 0, 0x00); |
301 | 301 | ||
302 | WriteDOC(0, docptr, Mplus_FlashControl); | 302 | WriteDOC(0, docptr, Mplus_FlashControl); |
@@ -365,7 +365,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) | |||
365 | this->interleave = 1; | 365 | this->interleave = 1; |
366 | 366 | ||
367 | /* Check the ASIC agrees */ | 367 | /* Check the ASIC agrees */ |
368 | if ( (this->interleave << 2) != | 368 | if ( (this->interleave << 2) != |
369 | (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) { | 369 | (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) { |
370 | u_char conf = ReadDOC(this->virtadr, Mplus_Configuration); | 370 | u_char conf = ReadDOC(this->virtadr, Mplus_Configuration); |
371 | printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n", | 371 | printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n", |
@@ -398,7 +398,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) | |||
398 | return; | 398 | return; |
399 | } | 399 | } |
400 | 400 | ||
401 | /* Fill out the chip array with {floor, chipno} for each | 401 | /* Fill out the chip array with {floor, chipno} for each |
402 | * detected chip in the device. */ | 402 | * detected chip in the device. */ |
403 | for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { | 403 | for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { |
404 | for (chip = 0 ; chip < numchips[floor] ; chip++) { | 404 | for (chip = 0 ; chip < numchips[floor] ; chip++) { |
@@ -432,7 +432,7 @@ static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) | |||
432 | tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); | 432 | tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); |
433 | if (tmp1 != tmp2) | 433 | if (tmp1 != tmp2) |
434 | return 0; | 434 | return 0; |
435 | 435 | ||
436 | WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); | 436 | WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); |
437 | tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); | 437 | tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); |
438 | if (tmp2 == (tmp1+1) % 0xff) | 438 | if (tmp2 == (tmp1+1) % 0xff) |
@@ -624,7 +624,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
624 | return -EINVAL; | 624 | return -EINVAL; |
625 | 625 | ||
626 | /* Don't allow a single read to cross a 512-byte block boundary */ | 626 | /* Don't allow a single read to cross a 512-byte block boundary */ |
627 | if (from + len > ((from | 0x1ff) + 1)) | 627 | if (from + len > ((from | 0x1ff) + 1)) |
628 | len = ((from | 0x1ff) + 1) - from; | 628 | len = ((from | 0x1ff) + 1) - from; |
629 | 629 | ||
630 | DoC_CheckASIC(docptr); | 630 | DoC_CheckASIC(docptr); |
@@ -1066,7 +1066,7 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1066 | 1066 | ||
1067 | DoC_CheckASIC(docptr); | 1067 | DoC_CheckASIC(docptr); |
1068 | 1068 | ||
1069 | if (len != mtd->erasesize) | 1069 | if (len != mtd->erasesize) |
1070 | printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n", | 1070 | printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n", |
1071 | len, mtd->erasesize); | 1071 | len, mtd->erasesize); |
1072 | 1072 | ||
@@ -1136,9 +1136,9 @@ static void __exit cleanup_doc2001plus(void) | |||
1136 | while ((mtd=docmilpluslist)) { | 1136 | while ((mtd=docmilpluslist)) { |
1137 | this = mtd->priv; | 1137 | this = mtd->priv; |
1138 | docmilpluslist = this->nextdoc; | 1138 | docmilpluslist = this->nextdoc; |
1139 | 1139 | ||
1140 | del_mtd_device(mtd); | 1140 | del_mtd_device(mtd); |
1141 | 1141 | ||
1142 | iounmap(this->virtadr); | 1142 | iounmap(this->virtadr); |
1143 | kfree(this->chips); | 1143 | kfree(this->chips); |
1144 | kfree(mtd); | 1144 | kfree(mtd); |
diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index 24f670b5a4f3..cd3db72bef96 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c | |||
@@ -4,10 +4,10 @@ | |||
4 | * GNU GPL License. The rest is simply to convert the disk on chip | 4 | * GNU GPL License. The rest is simply to convert the disk on chip |
5 | * syndrom into a standard syndom. | 5 | * syndrom into a standard syndom. |
6 | * | 6 | * |
7 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 7 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
8 | * Copyright (C) 2000 Netgem S.A. | 8 | * Copyright (C) 2000 Netgem S.A. |
9 | * | 9 | * |
10 | * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 Exp $ | 10 | * $Id: docecc.c,v 1.7 2005/11/07 11:14:25 gleixner Exp $ |
11 | * | 11 | * |
12 | * 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 |
13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -122,7 +122,7 @@ for(ci=(n)-1;ci >=0;ci--)\ | |||
122 | a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) | 122 | a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) |
123 | we consider the integer "i" whose binary representation with a(0) being LSB | 123 | we consider the integer "i" whose binary representation with a(0) being LSB |
124 | and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry | 124 | and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry |
125 | "index_of[i]". Now, @^index_of[i] is that element whose polynomial | 125 | "index_of[i]". Now, @^index_of[i] is that element whose polynomial |
126 | representation is (a(0),a(1),a(2),...,a(m-1)). | 126 | representation is (a(0),a(1),a(2),...,a(m-1)). |
127 | NOTE: | 127 | NOTE: |
128 | The element alpha_to[2^m-1] = 0 always signifying that the | 128 | The element alpha_to[2^m-1] = 0 always signifying that the |
@@ -130,7 +130,7 @@ for(ci=(n)-1;ci >=0;ci--)\ | |||
130 | Similarily, the element index_of[0] = A0 always signifying | 130 | Similarily, the element index_of[0] = A0 always signifying |
131 | that the power of alpha which has the polynomial representation | 131 | that the power of alpha which has the polynomial representation |
132 | (0,0,...,0) is "infinity". | 132 | (0,0,...,0) is "infinity". |
133 | 133 | ||
134 | */ | 134 | */ |
135 | 135 | ||
136 | static void | 136 | static void |
@@ -176,7 +176,7 @@ generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1]) | |||
176 | * are written back. NOTE! This array must be at least NN-KK elements long. | 176 | * are written back. NOTE! This array must be at least NN-KK elements long. |
177 | * The corrected data are written in eras_val[]. They must be xor with the data | 177 | * The corrected data are written in eras_val[]. They must be xor with the data |
178 | * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] . | 178 | * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] . |
179 | * | 179 | * |
180 | * First "no_eras" erasures are declared by the calling program. Then, the | 180 | * First "no_eras" erasures are declared by the calling program. Then, the |
181 | * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). | 181 | * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). |
182 | * If the number of channel errors is not greater than "t_after_eras" the | 182 | * If the number of channel errors is not greater than "t_after_eras" the |
@@ -189,7 +189,7 @@ generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1]) | |||
189 | * */ | 189 | * */ |
190 | static int | 190 | static int |
191 | eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | 191 | eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], |
192 | gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], | 192 | gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], |
193 | int no_eras) | 193 | int no_eras) |
194 | { | 194 | { |
195 | int deg_lambda, el, deg_omega; | 195 | int deg_lambda, el, deg_omega; |
@@ -212,7 +212,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
212 | count = 0; | 212 | count = 0; |
213 | goto finish; | 213 | goto finish; |
214 | } | 214 | } |
215 | 215 | ||
216 | for(i=1;i<=NN-KK;i++){ | 216 | for(i=1;i<=NN-KK;i++){ |
217 | s[i] = bb[0]; | 217 | s[i] = bb[0]; |
218 | } | 218 | } |
@@ -220,7 +220,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
220 | if(bb[j] == 0) | 220 | if(bb[j] == 0) |
221 | continue; | 221 | continue; |
222 | tmp = Index_of[bb[j]]; | 222 | tmp = Index_of[bb[j]]; |
223 | 223 | ||
224 | for(i=1;i<=NN-KK;i++) | 224 | for(i=1;i<=NN-KK;i++) |
225 | s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)]; | 225 | s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)]; |
226 | } | 226 | } |
@@ -234,7 +234,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
234 | tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM); | 234 | tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM); |
235 | s[i] = tmp; | 235 | s[i] = tmp; |
236 | } | 236 | } |
237 | 237 | ||
238 | CLEAR(&lambda[1],NN-KK); | 238 | CLEAR(&lambda[1],NN-KK); |
239 | lambda[0] = 1; | 239 | lambda[0] = 1; |
240 | 240 | ||
@@ -252,7 +252,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
252 | #if DEBUG_ECC >= 1 | 252 | #if DEBUG_ECC >= 1 |
253 | /* Test code that verifies the erasure locator polynomial just constructed | 253 | /* Test code that verifies the erasure locator polynomial just constructed |
254 | Needed only for decoder debugging. */ | 254 | Needed only for decoder debugging. */ |
255 | 255 | ||
256 | /* find roots of the erasure location polynomial */ | 256 | /* find roots of the erasure location polynomial */ |
257 | for(i=1;i<=no_eras;i++) | 257 | for(i=1;i<=no_eras;i++) |
258 | reg[i] = Index_of[lambda[i]]; | 258 | reg[i] = Index_of[lambda[i]]; |
@@ -286,7 +286,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
286 | } | 286 | } |
287 | for(i=0;i<NN-KK+1;i++) | 287 | for(i=0;i<NN-KK+1;i++) |
288 | b[i] = Index_of[lambda[i]]; | 288 | b[i] = Index_of[lambda[i]]; |
289 | 289 | ||
290 | /* | 290 | /* |
291 | * Begin Berlekamp-Massey algorithm to determine error+erasure | 291 | * Begin Berlekamp-Massey algorithm to determine error+erasure |
292 | * locator polynomial | 292 | * locator polynomial |
@@ -389,7 +389,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
389 | omega[i] = Index_of[tmp]; | 389 | omega[i] = Index_of[tmp]; |
390 | } | 390 | } |
391 | omega[NN-KK] = A0; | 391 | omega[NN-KK] = A0; |
392 | 392 | ||
393 | /* | 393 | /* |
394 | * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = | 394 | * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = |
395 | * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form | 395 | * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form |
@@ -402,7 +402,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
402 | } | 402 | } |
403 | num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; | 403 | num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)]; |
404 | den = 0; | 404 | den = 0; |
405 | 405 | ||
406 | /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ | 406 | /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ |
407 | for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { | 407 | for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) { |
408 | if(lambda[i+1] != A0) | 408 | if(lambda[i+1] != A0) |
@@ -436,11 +436,11 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], | |||
436 | /* The sector bytes are packed into NB_DATA MM bits words */ | 436 | /* The sector bytes are packed into NB_DATA MM bits words */ |
437 | #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM) | 437 | #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM) |
438 | 438 | ||
439 | /* | 439 | /* |
440 | * Correct the errors in 'sector[]' by using 'ecc1[]' which is the | 440 | * Correct the errors in 'sector[]' by using 'ecc1[]' which is the |
441 | * content of the feedback shift register applyied to the sector and | 441 | * content of the feedback shift register applyied to the sector and |
442 | * the ECC. Return the number of errors corrected (and correct them in | 442 | * the ECC. Return the number of errors corrected (and correct them in |
443 | * sector), or -1 if error | 443 | * sector), or -1 if error |
444 | */ | 444 | */ |
445 | int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | 445 | int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) |
446 | { | 446 | { |
@@ -454,7 +454,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
454 | Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); | 454 | Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); |
455 | if (!Alpha_to) | 455 | if (!Alpha_to) |
456 | return -1; | 456 | return -1; |
457 | 457 | ||
458 | Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); | 458 | Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); |
459 | if (!Index_of) { | 459 | if (!Index_of) { |
460 | kfree(Alpha_to); | 460 | kfree(Alpha_to); |
@@ -470,7 +470,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
470 | bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4); | 470 | bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4); |
471 | bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2); | 471 | bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2); |
472 | 472 | ||
473 | nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, | 473 | nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, |
474 | error_val, error_pos, 0); | 474 | error_val, error_pos, 0); |
475 | if (nb_errors <= 0) | 475 | if (nb_errors <= 0) |
476 | goto the_end; | 476 | goto the_end; |
@@ -489,7 +489,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
489 | can be modified since pos is even */ | 489 | can be modified since pos is even */ |
490 | index = (pos >> 3) ^ 1; | 490 | index = (pos >> 3) ^ 1; |
491 | bitpos = pos & 7; | 491 | bitpos = pos & 7; |
492 | if ((index >= 0 && index < SECTOR_SIZE) || | 492 | if ((index >= 0 && index < SECTOR_SIZE) || |
493 | index == (SECTOR_SIZE + 1)) { | 493 | index == (SECTOR_SIZE + 1)) { |
494 | val = error_val[i] >> (2 + bitpos); | 494 | val = error_val[i] >> (2 + bitpos); |
495 | parity ^= val; | 495 | parity ^= val; |
@@ -500,7 +500,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
500 | bitpos = (bitpos + 10) & 7; | 500 | bitpos = (bitpos + 10) & 7; |
501 | if (bitpos == 0) | 501 | if (bitpos == 0) |
502 | bitpos = 8; | 502 | bitpos = 8; |
503 | if ((index >= 0 && index < SECTOR_SIZE) || | 503 | if ((index >= 0 && index < SECTOR_SIZE) || |
504 | index == (SECTOR_SIZE + 1)) { | 504 | index == (SECTOR_SIZE + 1)) { |
505 | val = error_val[i] << (8 - bitpos); | 505 | val = error_val[i] << (8 - bitpos); |
506 | parity ^= val; | 506 | parity ^= val; |
@@ -509,7 +509,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) | |||
509 | } | 509 | } |
510 | } | 510 | } |
511 | } | 511 | } |
512 | 512 | ||
513 | /* use parity to test extra errors */ | 513 | /* use parity to test extra errors */ |
514 | if ((parity & 0xff) != 0) | 514 | if ((parity & 0xff) != 0) |
515 | nb_errors = -1; | 515 | nb_errors = -1; |
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 197d67045e1e..13178b9dd00a 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c | |||
@@ -4,22 +4,22 @@ | |||
4 | /* (C) 1999 Machine Vision Holdings, Inc. */ | 4 | /* (C) 1999 Machine Vision Holdings, Inc. */ |
5 | /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ | 5 | /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ |
6 | 6 | ||
7 | /* $Id: docprobe.c,v 1.44 2005/01/05 12:40:36 dwmw2 Exp $ */ | 7 | /* $Id: docprobe.c,v 1.46 2005/11/07 11:14:25 gleixner Exp $ */ |
8 | 8 | ||
9 | 9 | ||
10 | 10 | ||
11 | /* DOC_PASSIVE_PROBE: | 11 | /* DOC_PASSIVE_PROBE: |
12 | In order to ensure that the BIOS checksum is correct at boot time, and | 12 | In order to ensure that the BIOS checksum is correct at boot time, and |
13 | hence that the onboard BIOS extension gets executed, the DiskOnChip | 13 | hence that the onboard BIOS extension gets executed, the DiskOnChip |
14 | goes into reset mode when it is read sequentially: all registers | 14 | goes into reset mode when it is read sequentially: all registers |
15 | return 0xff until the chip is woken up again by writing to the | 15 | return 0xff until the chip is woken up again by writing to the |
16 | DOCControl register. | 16 | DOCControl register. |
17 | 17 | ||
18 | Unfortunately, this means that the probe for the DiskOnChip is unsafe, | 18 | Unfortunately, this means that the probe for the DiskOnChip is unsafe, |
19 | because one of the first things it does is write to where it thinks | 19 | because one of the first things it does is write to where it thinks |
20 | the DOCControl register should be - which may well be shared memory | 20 | the DOCControl register should be - which may well be shared memory |
21 | for another device. I've had machines which lock up when this is | 21 | for another device. I've had machines which lock up when this is |
22 | attempted. Hence the possibility to do a passive probe, which will fail | 22 | attempted. Hence the possibility to do a passive probe, which will fail |
23 | to detect a chip in reset mode, but is at least guaranteed not to lock | 23 | to detect a chip in reset mode, but is at least guaranteed not to lock |
24 | the machine. | 24 | the machine. |
25 | 25 | ||
@@ -33,9 +33,9 @@ | |||
33 | 33 | ||
34 | The old Millennium-only driver has been retained just in case there | 34 | The old Millennium-only driver has been retained just in case there |
35 | are problems with the new code. If the combined driver doesn't work | 35 | are problems with the new code. If the combined driver doesn't work |
36 | for you, you can try the old one by undefining DOC_SINGLE_DRIVER | 36 | for you, you can try the old one by undefining DOC_SINGLE_DRIVER |
37 | below and also enabling it in your configuration. If this fixes the | 37 | below and also enabling it in your configuration. If this fixes the |
38 | problems, please send a report to the MTD mailing list at | 38 | problems, please send a report to the MTD mailing list at |
39 | <linux-mtd@lists.infradead.org>. | 39 | <linux-mtd@lists.infradead.org>. |
40 | */ | 40 | */ |
41 | #define DOC_SINGLE_DRIVER | 41 | #define DOC_SINGLE_DRIVER |
@@ -68,16 +68,16 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe | |||
68 | static unsigned long __initdata doc_locations[] = { | 68 | static unsigned long __initdata doc_locations[] = { |
69 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) | 69 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) |
70 | #ifdef CONFIG_MTD_DOCPROBE_HIGH | 70 | #ifdef CONFIG_MTD_DOCPROBE_HIGH |
71 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, | 71 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, |
72 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, | 72 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, |
73 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, | 73 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, |
74 | 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, | 74 | 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, |
75 | 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, | 75 | 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, |
76 | #else /* CONFIG_MTD_DOCPROBE_HIGH */ | 76 | #else /* CONFIG_MTD_DOCPROBE_HIGH */ |
77 | 0xc8000, 0xca000, 0xcc000, 0xce000, | 77 | 0xc8000, 0xca000, 0xcc000, 0xce000, |
78 | 0xd0000, 0xd2000, 0xd4000, 0xd6000, | 78 | 0xd0000, 0xd2000, 0xd4000, 0xd6000, |
79 | 0xd8000, 0xda000, 0xdc000, 0xde000, | 79 | 0xd8000, 0xda000, 0xdc000, 0xde000, |
80 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, | 80 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, |
81 | 0xe8000, 0xea000, 0xec000, 0xee000, | 81 | 0xe8000, 0xea000, 0xec000, 0xee000, |
82 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ | 82 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ |
83 | #elif defined(__PPC__) | 83 | #elif defined(__PPC__) |
@@ -111,35 +111,35 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
111 | return 0; | 111 | return 0; |
112 | #endif /* CONFIG_MTD_DOCPROBE_55AA */ | 112 | #endif /* CONFIG_MTD_DOCPROBE_55AA */ |
113 | 113 | ||
114 | #ifndef DOC_PASSIVE_PROBE | 114 | #ifndef DOC_PASSIVE_PROBE |
115 | /* It's not possible to cleanly detect the DiskOnChip - the | 115 | /* It's not possible to cleanly detect the DiskOnChip - the |
116 | * bootup procedure will put the device into reset mode, and | 116 | * bootup procedure will put the device into reset mode, and |
117 | * it's not possible to talk to it without actually writing | 117 | * it's not possible to talk to it without actually writing |
118 | * to the DOCControl register. So we store the current contents | 118 | * to the DOCControl register. So we store the current contents |
119 | * of the DOCControl register's location, in case we later decide | 119 | * of the DOCControl register's location, in case we later decide |
120 | * that it's not a DiskOnChip, and want to put it back how we | 120 | * that it's not a DiskOnChip, and want to put it back how we |
121 | * found it. | 121 | * found it. |
122 | */ | 122 | */ |
123 | tmp2 = ReadDOC(window, DOCControl); | 123 | tmp2 = ReadDOC(window, DOCControl); |
124 | 124 | ||
125 | /* Reset the DiskOnChip ASIC */ | 125 | /* Reset the DiskOnChip ASIC */ |
126 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, | 126 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, |
127 | window, DOCControl); | 127 | window, DOCControl); |
128 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, | 128 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, |
129 | window, DOCControl); | 129 | window, DOCControl); |
130 | 130 | ||
131 | /* Enable the DiskOnChip ASIC */ | 131 | /* Enable the DiskOnChip ASIC */ |
132 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, | 132 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, |
133 | window, DOCControl); | 133 | window, DOCControl); |
134 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, | 134 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, |
135 | window, DOCControl); | 135 | window, DOCControl); |
136 | #endif /* !DOC_PASSIVE_PROBE */ | 136 | #endif /* !DOC_PASSIVE_PROBE */ |
137 | 137 | ||
138 | /* We need to read the ChipID register four times. For some | 138 | /* We need to read the ChipID register four times. For some |
139 | newer DiskOnChip 2000 units, the first three reads will | 139 | newer DiskOnChip 2000 units, the first three reads will |
140 | return the DiskOnChip Millennium ident. Don't ask. */ | 140 | return the DiskOnChip Millennium ident. Don't ask. */ |
141 | ChipID = ReadDOC(window, ChipID); | 141 | ChipID = ReadDOC(window, ChipID); |
142 | 142 | ||
143 | switch (ChipID) { | 143 | switch (ChipID) { |
144 | case DOC_ChipID_Doc2k: | 144 | case DOC_ChipID_Doc2k: |
145 | /* Check the TOGGLE bit in the ECC register */ | 145 | /* Check the TOGGLE bit in the ECC register */ |
@@ -149,7 +149,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
149 | if (tmp != tmpb && tmp == tmpc) | 149 | if (tmp != tmpb && tmp == tmpc) |
150 | return ChipID; | 150 | return ChipID; |
151 | break; | 151 | break; |
152 | 152 | ||
153 | case DOC_ChipID_DocMil: | 153 | case DOC_ChipID_DocMil: |
154 | /* Check for the new 2000 with Millennium ASIC */ | 154 | /* Check for the new 2000 with Millennium ASIC */ |
155 | ReadDOC(window, ChipID); | 155 | ReadDOC(window, ChipID); |
@@ -164,7 +164,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
164 | if (tmp != tmpb && tmp == tmpc) | 164 | if (tmp != tmpb && tmp == tmpc) |
165 | return ChipID; | 165 | return ChipID; |
166 | break; | 166 | break; |
167 | 167 | ||
168 | case DOC_ChipID_DocMilPlus16: | 168 | case DOC_ChipID_DocMilPlus16: |
169 | case DOC_ChipID_DocMilPlus32: | 169 | case DOC_ChipID_DocMilPlus32: |
170 | case 0: | 170 | case 0: |
@@ -179,7 +179,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
179 | DOC_MODE_BDECT; | 179 | DOC_MODE_BDECT; |
180 | WriteDOC(tmp, window, Mplus_DOCControl); | 180 | WriteDOC(tmp, window, Mplus_DOCControl); |
181 | WriteDOC(~tmp, window, Mplus_CtrlConfirm); | 181 | WriteDOC(~tmp, window, Mplus_CtrlConfirm); |
182 | 182 | ||
183 | mdelay(1); | 183 | mdelay(1); |
184 | /* Enable the DiskOnChip ASIC */ | 184 | /* Enable the DiskOnChip ASIC */ |
185 | tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | | 185 | tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | |
@@ -187,7 +187,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
187 | WriteDOC(tmp, window, Mplus_DOCControl); | 187 | WriteDOC(tmp, window, Mplus_DOCControl); |
188 | WriteDOC(~tmp, window, Mplus_CtrlConfirm); | 188 | WriteDOC(~tmp, window, Mplus_CtrlConfirm); |
189 | mdelay(1); | 189 | mdelay(1); |
190 | #endif /* !DOC_PASSIVE_PROBE */ | 190 | #endif /* !DOC_PASSIVE_PROBE */ |
191 | 191 | ||
192 | ChipID = ReadDOC(window, ChipID); | 192 | ChipID = ReadDOC(window, ChipID); |
193 | 193 | ||
@@ -227,7 +227,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr | |||
227 | WriteDOC(tmp2, window, DOCControl); | 227 | WriteDOC(tmp2, window, DOCControl); |
228 | #endif | 228 | #endif |
229 | return 0; | 229 | return 0; |
230 | } | 230 | } |
231 | 231 | ||
232 | static int docfound; | 232 | static int docfound; |
233 | 233 | ||
@@ -244,10 +244,10 @@ static void __init DoC_Probe(unsigned long physadr) | |||
244 | void (*initroutine)(struct mtd_info *) = NULL; | 244 | void (*initroutine)(struct mtd_info *) = NULL; |
245 | 245 | ||
246 | docptr = ioremap(physadr, DOC_IOREMAP_LEN); | 246 | docptr = ioremap(physadr, DOC_IOREMAP_LEN); |
247 | 247 | ||
248 | if (!docptr) | 248 | if (!docptr) |
249 | return; | 249 | return; |
250 | 250 | ||
251 | if ((ChipID = doccheck(docptr, physadr))) { | 251 | if ((ChipID = doccheck(docptr, physadr))) { |
252 | if (ChipID == DOC_ChipID_Doc2kTSOP) { | 252 | if (ChipID == DOC_ChipID_Doc2kTSOP) { |
253 | /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */ | 253 | /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */ |
@@ -263,9 +263,9 @@ static void __init DoC_Probe(unsigned long physadr) | |||
263 | iounmap(docptr); | 263 | iounmap(docptr); |
264 | return; | 264 | return; |
265 | } | 265 | } |
266 | 266 | ||
267 | this = (struct DiskOnChip *)(&mtd[1]); | 267 | this = (struct DiskOnChip *)(&mtd[1]); |
268 | 268 | ||
269 | memset((char *)mtd,0, sizeof(struct mtd_info)); | 269 | memset((char *)mtd,0, sizeof(struct mtd_info)); |
270 | memset((char *)this, 0, sizeof(struct DiskOnChip)); | 270 | memset((char *)this, 0, sizeof(struct DiskOnChip)); |
271 | 271 | ||
@@ -281,13 +281,13 @@ static void __init DoC_Probe(unsigned long physadr) | |||
281 | im_funcname = "DoC2k_init"; | 281 | im_funcname = "DoC2k_init"; |
282 | im_modname = "doc2000"; | 282 | im_modname = "doc2000"; |
283 | break; | 283 | break; |
284 | 284 | ||
285 | case DOC_ChipID_Doc2k: | 285 | case DOC_ChipID_Doc2k: |
286 | name="2000"; | 286 | name="2000"; |
287 | im_funcname = "DoC2k_init"; | 287 | im_funcname = "DoC2k_init"; |
288 | im_modname = "doc2000"; | 288 | im_modname = "doc2000"; |
289 | break; | 289 | break; |
290 | 290 | ||
291 | case DOC_ChipID_DocMil: | 291 | case DOC_ChipID_DocMil: |
292 | name="Millennium"; | 292 | name="Millennium"; |
293 | #ifdef DOC_SINGLE_DRIVER | 293 | #ifdef DOC_SINGLE_DRIVER |
@@ -331,7 +331,7 @@ static void __init DoC_Probe(unsigned long physadr) | |||
331 | static int __init init_doc(void) | 331 | static int __init init_doc(void) |
332 | { | 332 | { |
333 | int i; | 333 | int i; |
334 | 334 | ||
335 | if (doc_config_location) { | 335 | if (doc_config_location) { |
336 | printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); | 336 | printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); |
337 | DoC_Probe(doc_config_location); | 337 | DoC_Probe(doc_config_location); |
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index df987a53ed9c..1e876fcb0408 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c | |||
@@ -2,7 +2,7 @@ | |||
2 | /* | 2 | /* |
3 | * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. | 3 | * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. |
4 | * | 4 | * |
5 | * $Id: lart.c,v 1.7 2004/08/09 13:19:44 dwmw2 Exp $ | 5 | * $Id: lart.c,v 1.9 2005/11/07 11:14:25 gleixner Exp $ |
6 | * | 6 | * |
7 | * Author: Abraham vd Merwe <abraham@2d3d.co.za> | 7 | * Author: Abraham vd Merwe <abraham@2d3d.co.za> |
8 | * | 8 | * |
@@ -122,7 +122,7 @@ static char module_name[] = "lart"; | |||
122 | 122 | ||
123 | /* | 123 | /* |
124 | * The data line mapping on LART is as follows: | 124 | * The data line mapping on LART is as follows: |
125 | * | 125 | * |
126 | * U2 CPU | U3 CPU | 126 | * U2 CPU | U3 CPU |
127 | * ------------------- | 127 | * ------------------- |
128 | * 0 20 | 0 12 | 128 | * 0 20 | 0 12 |
@@ -181,7 +181,7 @@ static char module_name[] = "lart"; | |||
181 | (((x) & 0x00004000) >> 13) \ | 181 | (((x) & 0x00004000) >> 13) \ |
182 | ) | 182 | ) |
183 | 183 | ||
184 | /* | 184 | /* |
185 | * The address line mapping on LART is as follows: | 185 | * The address line mapping on LART is as follows: |
186 | * | 186 | * |
187 | * U3 CPU | U2 CPU | 187 | * U3 CPU | U2 CPU |
@@ -204,7 +204,7 @@ static char module_name[] = "lart"; | |||
204 | * 12 15 | 12 15 | 204 | * 12 15 | 12 15 |
205 | * 13 14 | 13 14 | 205 | * 13 14 | 13 14 |
206 | * 14 16 | 14 16 | 206 | * 14 16 | 14 16 |
207 | * | 207 | * |
208 | * MAIN BLOCK BOUNDARY | 208 | * MAIN BLOCK BOUNDARY |
209 | * | 209 | * |
210 | * 15 17 | 15 18 | 210 | * 15 17 | 15 18 |
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 765c0179c8df..e8685ee6c1e4 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /** | 1 | /** |
2 | * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $ | 2 | * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $ |
3 | * | 3 | * |
4 | * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de> | 4 | * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de> |
5 | * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de> | 5 | * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de> |
@@ -41,10 +41,10 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
41 | 41 | ||
42 | if (instr->addr + instr->len > mtd->size) | 42 | if (instr->addr + instr->len > mtd->size) |
43 | return -EINVAL; | 43 | return -EINVAL; |
44 | 44 | ||
45 | memset(start + instr->addr, 0xff, instr->len); | 45 | memset(start + instr->addr, 0xff, instr->len); |
46 | 46 | ||
47 | /* This'll catch a few races. Free the thing before returning :) | 47 | /* This'll catch a few races. Free the thing before returning :) |
48 | * I don't feel at all ashamed. This kind of thing is possible anyway | 48 | * I don't feel at all ashamed. This kind of thing is possible anyway |
49 | * with flash, but unlikely. | 49 | * with flash, but unlikely. |
50 | */ | 50 | */ |
@@ -63,7 +63,7 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, | |||
63 | 63 | ||
64 | if (from + len > mtd->size) | 64 | if (from + len > mtd->size) |
65 | return -EINVAL; | 65 | return -EINVAL; |
66 | 66 | ||
67 | *mtdbuf = start + from; | 67 | *mtdbuf = start + from; |
68 | *retlen = len; | 68 | *retlen = len; |
69 | return 0; | 69 | return 0; |
@@ -84,7 +84,7 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
84 | 84 | ||
85 | if (len > mtd->size - from) | 85 | if (len > mtd->size - from) |
86 | len = mtd->size - from; | 86 | len = mtd->size - from; |
87 | 87 | ||
88 | memcpy(buf, start + from, len); | 88 | memcpy(buf, start + from, len); |
89 | 89 | ||
90 | *retlen = len; | 90 | *retlen = len; |
@@ -101,7 +101,7 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
101 | 101 | ||
102 | if (len > mtd->size - to) | 102 | if (len > mtd->size - to) |
103 | len = mtd->size - to; | 103 | len = mtd->size - to; |
104 | 104 | ||
105 | memcpy(start + to, buf, len); | 105 | memcpy(start + to, buf, len); |
106 | 106 | ||
107 | *retlen = len; | 107 | *retlen = len; |
@@ -159,7 +159,7 @@ static int register_device(char *name, unsigned long start, unsigned long len) | |||
159 | } | 159 | } |
160 | 160 | ||
161 | list_add_tail(&new->list, &phram_list); | 161 | list_add_tail(&new->list, &phram_list); |
162 | return 0; | 162 | return 0; |
163 | 163 | ||
164 | out2: | 164 | out2: |
165 | iounmap(new->mtd.priv); | 165 | iounmap(new->mtd.priv); |
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 5b3defadf884..de48b35f5609 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: pmc551.c,v 1.30 2005/01/05 18:05:13 dwmw2 Exp $ | 2 | * $Id: pmc551.c,v 1.32 2005/11/07 11:14:25 gleixner Exp $ |
3 | * | 3 | * |
4 | * PMC551 PCI Mezzanine Ram Device | 4 | * PMC551 PCI Mezzanine Ram Device |
5 | * | 5 | * |
@@ -27,7 +27,7 @@ | |||
27 | * it as high speed swap or for a high speed disk device of some | 27 | * it as high speed swap or for a high speed disk device of some |
28 | * sort. Which becomes very useful on diskless systems in the | 28 | * sort. Which becomes very useful on diskless systems in the |
29 | * embedded market I might add. | 29 | * embedded market I might add. |
30 | * | 30 | * |
31 | * Notes: | 31 | * Notes: |
32 | * Due to what I assume is more buggy SROM, the 64M PMC551 I | 32 | * Due to what I assume is more buggy SROM, the 64M PMC551 I |
33 | * have available claims that all 4 of it's DRAM banks have 64M | 33 | * have available claims that all 4 of it's DRAM banks have 64M |
@@ -63,10 +63,10 @@ | |||
63 | * Minyard set up the card to utilize a 1M sliding apature. | 63 | * Minyard set up the card to utilize a 1M sliding apature. |
64 | * | 64 | * |
65 | * Corey Minyard <minyard@nortelnetworks.com> | 65 | * Corey Minyard <minyard@nortelnetworks.com> |
66 | * * Modified driver to utilize a sliding aperture instead of | 66 | * * Modified driver to utilize a sliding aperture instead of |
67 | * mapping all memory into kernel space which turned out to | 67 | * mapping all memory into kernel space which turned out to |
68 | * be very wasteful. | 68 | * be very wasteful. |
69 | * * Located a bug in the SROM's initialization sequence that | 69 | * * Located a bug in the SROM's initialization sequence that |
70 | * made the memory unusable, added a fix to code to touch up | 70 | * made the memory unusable, added a fix to code to touch up |
71 | * the DRAM some. | 71 | * the DRAM some. |
72 | * | 72 | * |
@@ -390,7 +390,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) | |||
390 | bcmd |= (0x40|0x20); | 390 | bcmd |= (0x40|0x20); |
391 | pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd); | 391 | pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd); |
392 | 392 | ||
393 | /* | 393 | /* |
394 | * Take care and turn off the memory on the device while we | 394 | * Take care and turn off the memory on the device while we |
395 | * tweak the configurations | 395 | * tweak the configurations |
396 | */ | 396 | */ |
@@ -408,7 +408,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) | |||
408 | * Grab old BAR0 config so that we can figure out memory size | 408 | * Grab old BAR0 config so that we can figure out memory size |
409 | * This is another bit of kludge going on. The reason for the | 409 | * This is another bit of kludge going on. The reason for the |
410 | * redundancy is I am hoping to retain the original configuration | 410 | * redundancy is I am hoping to retain the original configuration |
411 | * previously assigned to the card by the BIOS or some previous | 411 | * previously assigned to the card by the BIOS or some previous |
412 | * fixup routine in the kernel. So we read the old config into cfg, | 412 | * fixup routine in the kernel. So we read the old config into cfg, |
413 | * then write all 1's to the memory space, read back the result into | 413 | * then write all 1's to the memory space, read back the result into |
414 | * "size", and then write back all the old config. | 414 | * "size", and then write back all the old config. |
@@ -480,7 +480,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) | |||
480 | } while ( (PCI_COMMAND_IO) & cmd ); | 480 | } while ( (PCI_COMMAND_IO) & cmd ); |
481 | 481 | ||
482 | /* | 482 | /* |
483 | * Turn on auto refresh | 483 | * Turn on auto refresh |
484 | * The loop is taken directly from Ramix's example code. I assume that | 484 | * The loop is taken directly from Ramix's example code. I assume that |
485 | * this must be held high for some duration of time, but I can find no | 485 | * this must be held high for some duration of time, but I can find no |
486 | * documentation refrencing the reasons why. | 486 | * documentation refrencing the reasons why. |
@@ -615,7 +615,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) | |||
615 | pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd ); | 615 | pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd ); |
616 | printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n" | 616 | printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n" |
617 | "pmc551: System Control Register is %slocked to PCI access\n" | 617 | "pmc551: System Control Register is %slocked to PCI access\n" |
618 | "pmc551: System Control Register is %slocked to EEPROM access\n", | 618 | "pmc551: System Control Register is %slocked to EEPROM access\n", |
619 | (bcmd&0x1)?"software":"hardware", | 619 | (bcmd&0x1)?"software":"hardware", |
620 | (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un"); | 620 | (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un"); |
621 | #endif | 621 | #endif |
@@ -744,7 +744,7 @@ static int __init init_pmc551(void) | |||
744 | priv->start = ioremap(((PCI_Device->resource[0].start) | 744 | priv->start = ioremap(((PCI_Device->resource[0].start) |
745 | & PCI_BASE_ADDRESS_MEM_MASK), | 745 | & PCI_BASE_ADDRESS_MEM_MASK), |
746 | priv->asize); | 746 | priv->asize); |
747 | 747 | ||
748 | if (!priv->start) { | 748 | if (!priv->start) { |
749 | printk(KERN_NOTICE "pmc551: Unable to map IO space\n"); | 749 | printk(KERN_NOTICE "pmc551: Unable to map IO space\n"); |
750 | kfree(mtd->priv); | 750 | kfree(mtd->priv); |
@@ -765,7 +765,7 @@ static int __init init_pmc551(void) | |||
765 | priv->curr_map0 ); | 765 | priv->curr_map0 ); |
766 | 766 | ||
767 | #ifdef CONFIG_MTD_PMC551_DEBUG | 767 | #ifdef CONFIG_MTD_PMC551_DEBUG |
768 | printk( KERN_DEBUG "pmc551: aperture set to %d\n", | 768 | printk( KERN_DEBUG "pmc551: aperture set to %d\n", |
769 | (priv->base_map0 & 0xF0)>>4 ); | 769 | (priv->base_map0 & 0xF0)>>4 ); |
770 | #endif | 770 | #endif |
771 | 771 | ||
@@ -823,13 +823,13 @@ static void __exit cleanup_pmc551(void) | |||
823 | while((mtd=pmc551list)) { | 823 | while((mtd=pmc551list)) { |
824 | priv = mtd->priv; | 824 | priv = mtd->priv; |
825 | pmc551list = priv->nextpmc551; | 825 | pmc551list = priv->nextpmc551; |
826 | 826 | ||
827 | if(priv->start) { | 827 | if(priv->start) { |
828 | printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n", | 828 | printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n", |
829 | priv->asize>>20, priv->start); | 829 | priv->asize>>20, priv->start); |
830 | iounmap (priv->start); | 830 | iounmap (priv->start); |
831 | } | 831 | } |
832 | 832 | ||
833 | kfree (mtd->priv); | 833 | kfree (mtd->priv); |
834 | del_mtd_device (mtd); | 834 | del_mtd_device (mtd); |
835 | kfree (mtd); | 835 | kfree (mtd); |
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 84fa91392a8c..6faee6c6958c 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /*====================================================================== | 1 | /*====================================================================== |
2 | 2 | ||
3 | $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $ | 3 | $Id: slram.c,v 1.36 2005/11/07 11:14:25 gleixner Exp $ |
4 | 4 | ||
5 | This driver provides a method to access memory not used by the kernel | 5 | This driver provides a method to access memory not used by the kernel |
6 | itself (i.e. if the kernel commandline mem=xxx is used). To actually | 6 | itself (i.e. if the kernel commandline mem=xxx is used). To actually |
@@ -18,14 +18,14 @@ | |||
18 | <start>: start of the memory region, decimal or hex (0xabcdef) | 18 | <start>: start of the memory region, decimal or hex (0xabcdef) |
19 | <end/offset>: end of the memory region. It's possible to use +0x1234 | 19 | <end/offset>: end of the memory region. It's possible to use +0x1234 |
20 | to specify the offset instead of the absolute address | 20 | to specify the offset instead of the absolute address |
21 | 21 | ||
22 | NOTE: | 22 | NOTE: |
23 | With slram it's only possible to map a contigous memory region. Therfore | 23 | With slram it's only possible to map a contigous memory region. Therfore |
24 | if there's a device mapped somewhere in the region specified slram will | 24 | if there's a device mapped somewhere in the region specified slram will |
25 | fail to load (see kernel log if modprobe fails). | 25 | fail to load (see kernel log if modprobe fails). |
26 | 26 | ||
27 | - | 27 | - |
28 | 28 | ||
29 | Jochen Schaeuble <psionic@psionic.de> | 29 | Jochen Schaeuble <psionic@psionic.de> |
30 | 30 | ||
31 | ======================================================================*/ | 31 | ======================================================================*/ |
@@ -89,10 +89,10 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
89 | if (instr->addr + instr->len > mtd->size) { | 89 | if (instr->addr + instr->len > mtd->size) { |
90 | return(-EINVAL); | 90 | return(-EINVAL); |
91 | } | 91 | } |
92 | 92 | ||
93 | memset(priv->start + instr->addr, 0xff, instr->len); | 93 | memset(priv->start + instr->addr, 0xff, instr->len); |
94 | 94 | ||
95 | /* This'll catch a few races. Free the thing before returning :) | 95 | /* This'll catch a few races. Free the thing before returning :) |
96 | * I don't feel at all ashamed. This kind of thing is possible anyway | 96 | * I don't feel at all ashamed. This kind of thing is possible anyway |
97 | * with flash, but unlikely. | 97 | * with flash, but unlikely. |
98 | */ | 98 | */ |
@@ -170,12 +170,12 @@ static int register_device(char *name, unsigned long start, unsigned long length | |||
170 | } | 170 | } |
171 | (*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); | 171 | (*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); |
172 | (*curmtd)->next = NULL; | 172 | (*curmtd)->next = NULL; |
173 | 173 | ||
174 | if ((*curmtd)->mtdinfo) { | 174 | if ((*curmtd)->mtdinfo) { |
175 | memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info)); | 175 | memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info)); |
176 | (*curmtd)->mtdinfo->priv = | 176 | (*curmtd)->mtdinfo->priv = |
177 | kmalloc(sizeof(slram_priv_t), GFP_KERNEL); | 177 | kmalloc(sizeof(slram_priv_t), GFP_KERNEL); |
178 | 178 | ||
179 | if (!(*curmtd)->mtdinfo->priv) { | 179 | if (!(*curmtd)->mtdinfo->priv) { |
180 | kfree((*curmtd)->mtdinfo); | 180 | kfree((*curmtd)->mtdinfo); |
181 | (*curmtd)->mtdinfo = NULL; | 181 | (*curmtd)->mtdinfo = NULL; |
@@ -188,7 +188,7 @@ static int register_device(char *name, unsigned long start, unsigned long length | |||
188 | E("slram: Cannot allocate new MTD device.\n"); | 188 | E("slram: Cannot allocate new MTD device.\n"); |
189 | return(-ENOMEM); | 189 | return(-ENOMEM); |
190 | } | 190 | } |
191 | 191 | ||
192 | if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start = | 192 | if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start = |
193 | ioremap(start, length))) { | 193 | ioremap(start, length))) { |
194 | E("slram: ioremap failed\n"); | 194 | E("slram: ioremap failed\n"); |
@@ -223,7 +223,7 @@ static int register_device(char *name, unsigned long start, unsigned long length | |||
223 | T("slram: Mapped from 0x%p to 0x%p\n", | 223 | T("slram: Mapped from 0x%p to 0x%p\n", |
224 | ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start, | 224 | ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start, |
225 | ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end); | 225 | ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end); |
226 | return(0); | 226 | return(0); |
227 | } | 227 | } |
228 | 228 | ||
229 | static void unregister_devices(void) | 229 | static void unregister_devices(void) |
@@ -256,7 +256,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) | |||
256 | char *buffer; | 256 | char *buffer; |
257 | unsigned long devstart; | 257 | unsigned long devstart; |
258 | unsigned long devlength; | 258 | unsigned long devlength; |
259 | 259 | ||
260 | if ((!devname) || (!szstart) || (!szlength)) { | 260 | if ((!devname) || (!szstart) || (!szlength)) { |
261 | unregister_devices(); | 261 | unregister_devices(); |
262 | return(-EINVAL); | 262 | return(-EINVAL); |
@@ -264,7 +264,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) | |||
264 | 264 | ||
265 | devstart = simple_strtoul(szstart, &buffer, 0); | 265 | devstart = simple_strtoul(szstart, &buffer, 0); |
266 | devstart = handle_unit(devstart, buffer); | 266 | devstart = handle_unit(devstart, buffer); |
267 | 267 | ||
268 | if (*(szlength) != '+') { | 268 | if (*(szlength) != '+') { |
269 | devlength = simple_strtoul(szlength, &buffer, 0); | 269 | devlength = simple_strtoul(szlength, &buffer, 0); |
270 | devlength = handle_unit(devlength, buffer) - devstart; | 270 | devlength = handle_unit(devlength, buffer) - devstart; |
@@ -278,7 +278,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) | |||
278 | E("slram: Illegal start / length parameter.\n"); | 278 | E("slram: Illegal start / length parameter.\n"); |
279 | return(-EINVAL); | 279 | return(-EINVAL); |
280 | } | 280 | } |
281 | 281 | ||
282 | if ((devstart = register_device(devname, devstart, devlength))){ | 282 | if ((devstart = register_device(devname, devstart, devlength))){ |
283 | unregister_devices(); | 283 | unregister_devices(); |
284 | return((int)devstart); | 284 | return((int)devstart); |
@@ -335,7 +335,7 @@ static int init_slram(void) | |||
335 | } | 335 | } |
336 | #else | 336 | #else |
337 | int count; | 337 | int count; |
338 | 338 | ||
339 | for (count = 0; (map[count]) && (count < SLRAM_MAX_DEVICES_PARAMS); | 339 | for (count = 0; (map[count]) && (count < SLRAM_MAX_DEVICES_PARAMS); |
340 | count++) { | 340 | count++) { |
341 | } | 341 | } |
@@ -350,10 +350,10 @@ static int init_slram(void) | |||
350 | if (parse_cmdline(devname, map[i * 3 + 1], map[i * 3 + 2])!=0) { | 350 | if (parse_cmdline(devname, map[i * 3 + 1], map[i * 3 + 2])!=0) { |
351 | return(-EINVAL); | 351 | return(-EINVAL); |
352 | } | 352 | } |
353 | 353 | ||
354 | } | 354 | } |
355 | #endif /* !MODULE */ | 355 | #endif /* !MODULE */ |
356 | 356 | ||
357 | return(0); | 357 | return(0); |
358 | } | 358 | } |
359 | 359 | ||
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index d32c1b3a8ce3..de7e231d6d18 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* This version ported to the Linux-MTD system by dwmw2@infradead.org | 1 | /* This version ported to the Linux-MTD system by dwmw2@infradead.org |
2 | * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $ | 2 | * $Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $ |
3 | * | 3 | * |
4 | * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 4 | * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
5 | * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups | 5 | * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups |
@@ -53,7 +53,7 @@ | |||
53 | Use of the FTL format for non-PCMCIA applications may be an | 53 | Use of the FTL format for non-PCMCIA applications may be an |
54 | infringement of these patents. For additional information, | 54 | infringement of these patents. For additional information, |
55 | contact M-Systems (http://www.m-sys.com) directly. | 55 | contact M-Systems (http://www.m-sys.com) directly. |
56 | 56 | ||
57 | ======================================================================*/ | 57 | ======================================================================*/ |
58 | #include <linux/mtd/blktrans.h> | 58 | #include <linux/mtd/blktrans.h> |
59 | #include <linux/module.h> | 59 | #include <linux/module.h> |
@@ -160,7 +160,7 @@ static void ftl_erase_callback(struct erase_info *done); | |||
160 | Scan_header() checks to see if a memory region contains an FTL | 160 | Scan_header() checks to see if a memory region contains an FTL |
161 | partition. build_maps() reads all the erase unit headers, builds | 161 | partition. build_maps() reads all the erase unit headers, builds |
162 | the erase unit map, and then builds the virtual page map. | 162 | the erase unit map, and then builds the virtual page map. |
163 | 163 | ||
164 | ======================================================================*/ | 164 | ======================================================================*/ |
165 | 165 | ||
166 | static int scan_header(partition_t *part) | 166 | static int scan_header(partition_t *part) |
@@ -176,10 +176,10 @@ static int scan_header(partition_t *part) | |||
176 | (offset + sizeof(header)) < max_offset; | 176 | (offset + sizeof(header)) < max_offset; |
177 | offset += part->mbd.mtd->erasesize ? : 0x2000) { | 177 | offset += part->mbd.mtd->erasesize ? : 0x2000) { |
178 | 178 | ||
179 | err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, | 179 | err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, |
180 | (unsigned char *)&header); | 180 | (unsigned char *)&header); |
181 | 181 | ||
182 | if (err) | 182 | if (err) |
183 | return err; | 183 | return err; |
184 | 184 | ||
185 | if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break; | 185 | if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break; |
@@ -232,10 +232,10 @@ static int build_maps(partition_t *part) | |||
232 | for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { | 232 | for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { |
233 | offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) | 233 | offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) |
234 | << part->header.EraseUnitSize); | 234 | << part->header.EraseUnitSize); |
235 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, | 235 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, |
236 | (unsigned char *)&header); | 236 | (unsigned char *)&header); |
237 | 237 | ||
238 | if (ret) | 238 | if (ret) |
239 | goto out_XferInfo; | 239 | goto out_XferInfo; |
240 | 240 | ||
241 | ret = -1; | 241 | ret = -1; |
@@ -274,7 +274,7 @@ static int build_maps(partition_t *part) | |||
274 | "don't add up!\n"); | 274 | "don't add up!\n"); |
275 | goto out_XferInfo; | 275 | goto out_XferInfo; |
276 | } | 276 | } |
277 | 277 | ||
278 | /* Set up virtual page map */ | 278 | /* Set up virtual page map */ |
279 | blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; | 279 | blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; |
280 | part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t)); | 280 | part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t)); |
@@ -296,12 +296,12 @@ static int build_maps(partition_t *part) | |||
296 | part->EUNInfo[i].Free = 0; | 296 | part->EUNInfo[i].Free = 0; |
297 | part->EUNInfo[i].Deleted = 0; | 297 | part->EUNInfo[i].Deleted = 0; |
298 | offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); | 298 | offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); |
299 | 299 | ||
300 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, | 300 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, |
301 | part->BlocksPerUnit * sizeof(u_int32_t), &retval, | 301 | part->BlocksPerUnit * sizeof(u_int32_t), &retval, |
302 | (unsigned char *)part->bam_cache); | 302 | (unsigned char *)part->bam_cache); |
303 | 303 | ||
304 | if (ret) | 304 | if (ret) |
305 | goto out_bam_cache; | 305 | goto out_bam_cache; |
306 | 306 | ||
307 | for (j = 0; j < part->BlocksPerUnit; j++) { | 307 | for (j = 0; j < part->BlocksPerUnit; j++) { |
@@ -316,7 +316,7 @@ static int build_maps(partition_t *part) | |||
316 | part->EUNInfo[i].Deleted++; | 316 | part->EUNInfo[i].Deleted++; |
317 | } | 317 | } |
318 | } | 318 | } |
319 | 319 | ||
320 | ret = 0; | 320 | ret = 0; |
321 | goto out; | 321 | goto out; |
322 | 322 | ||
@@ -336,7 +336,7 @@ out: | |||
336 | 336 | ||
337 | Erase_xfer() schedules an asynchronous erase operation for a | 337 | Erase_xfer() schedules an asynchronous erase operation for a |
338 | transfer unit. | 338 | transfer unit. |
339 | 339 | ||
340 | ======================================================================*/ | 340 | ======================================================================*/ |
341 | 341 | ||
342 | static int erase_xfer(partition_t *part, | 342 | static int erase_xfer(partition_t *part, |
@@ -351,10 +351,10 @@ static int erase_xfer(partition_t *part, | |||
351 | xfer->state = XFER_ERASING; | 351 | xfer->state = XFER_ERASING; |
352 | 352 | ||
353 | /* Is there a free erase slot? Always in MTD. */ | 353 | /* Is there a free erase slot? Always in MTD. */ |
354 | 354 | ||
355 | 355 | ||
356 | erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL); | 356 | erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL); |
357 | if (!erase) | 357 | if (!erase) |
358 | return -ENOMEM; | 358 | return -ENOMEM; |
359 | 359 | ||
360 | erase->mtd = part->mbd.mtd; | 360 | erase->mtd = part->mbd.mtd; |
@@ -362,7 +362,7 @@ static int erase_xfer(partition_t *part, | |||
362 | erase->addr = xfer->Offset; | 362 | erase->addr = xfer->Offset; |
363 | erase->len = 1 << part->header.EraseUnitSize; | 363 | erase->len = 1 << part->header.EraseUnitSize; |
364 | erase->priv = (u_long)part; | 364 | erase->priv = (u_long)part; |
365 | 365 | ||
366 | ret = part->mbd.mtd->erase(part->mbd.mtd, erase); | 366 | ret = part->mbd.mtd->erase(part->mbd.mtd, erase); |
367 | 367 | ||
368 | if (!ret) | 368 | if (!ret) |
@@ -377,7 +377,7 @@ static int erase_xfer(partition_t *part, | |||
377 | 377 | ||
378 | Prepare_xfer() takes a freshly erased transfer unit and gives | 378 | Prepare_xfer() takes a freshly erased transfer unit and gives |
379 | it an appropriate header. | 379 | it an appropriate header. |
380 | 380 | ||
381 | ======================================================================*/ | 381 | ======================================================================*/ |
382 | 382 | ||
383 | static void ftl_erase_callback(struct erase_info *erase) | 383 | static void ftl_erase_callback(struct erase_info *erase) |
@@ -385,7 +385,7 @@ static void ftl_erase_callback(struct erase_info *erase) | |||
385 | partition_t *part; | 385 | partition_t *part; |
386 | struct xfer_info_t *xfer; | 386 | struct xfer_info_t *xfer; |
387 | int i; | 387 | int i; |
388 | 388 | ||
389 | /* Look up the transfer unit */ | 389 | /* Look up the transfer unit */ |
390 | part = (partition_t *)(erase->priv); | 390 | part = (partition_t *)(erase->priv); |
391 | 391 | ||
@@ -422,7 +422,7 @@ static int prepare_xfer(partition_t *part, int i) | |||
422 | 422 | ||
423 | xfer = &part->XferInfo[i]; | 423 | xfer = &part->XferInfo[i]; |
424 | xfer->state = XFER_FAILED; | 424 | xfer->state = XFER_FAILED; |
425 | 425 | ||
426 | DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); | 426 | DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); |
427 | 427 | ||
428 | /* Write the transfer unit header */ | 428 | /* Write the transfer unit header */ |
@@ -446,7 +446,7 @@ static int prepare_xfer(partition_t *part, int i) | |||
446 | 446 | ||
447 | for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { | 447 | for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { |
448 | 448 | ||
449 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), | 449 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), |
450 | &retlen, (u_char *)&ctl); | 450 | &retlen, (u_char *)&ctl); |
451 | 451 | ||
452 | if (ret) | 452 | if (ret) |
@@ -454,7 +454,7 @@ static int prepare_xfer(partition_t *part, int i) | |||
454 | } | 454 | } |
455 | xfer->state = XFER_PREPARED; | 455 | xfer->state = XFER_PREPARED; |
456 | return 0; | 456 | return 0; |
457 | 457 | ||
458 | } /* prepare_xfer */ | 458 | } /* prepare_xfer */ |
459 | 459 | ||
460 | /*====================================================================== | 460 | /*====================================================================== |
@@ -466,7 +466,7 @@ static int prepare_xfer(partition_t *part, int i) | |||
466 | All data blocks are copied to the corresponding blocks in the | 466 | All data blocks are copied to the corresponding blocks in the |
467 | target unit, so the virtual block map does not need to be | 467 | target unit, so the virtual block map does not need to be |
468 | updated. | 468 | updated. |
469 | 469 | ||
470 | ======================================================================*/ | 470 | ======================================================================*/ |
471 | 471 | ||
472 | static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | 472 | static int copy_erase_unit(partition_t *part, u_int16_t srcunit, |
@@ -486,14 +486,14 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
486 | xfer = &part->XferInfo[xferunit]; | 486 | xfer = &part->XferInfo[xferunit]; |
487 | DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", | 487 | DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", |
488 | eun->Offset, xfer->Offset); | 488 | eun->Offset, xfer->Offset); |
489 | 489 | ||
490 | 490 | ||
491 | /* Read current BAM */ | 491 | /* Read current BAM */ |
492 | if (part->bam_index != srcunit) { | 492 | if (part->bam_index != srcunit) { |
493 | 493 | ||
494 | offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); | 494 | offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); |
495 | 495 | ||
496 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, | 496 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, |
497 | part->BlocksPerUnit * sizeof(u_int32_t), | 497 | part->BlocksPerUnit * sizeof(u_int32_t), |
498 | &retlen, (u_char *) (part->bam_cache)); | 498 | &retlen, (u_char *) (part->bam_cache)); |
499 | 499 | ||
@@ -501,11 +501,11 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
501 | part->bam_index = 0xffff; | 501 | part->bam_index = 0xffff; |
502 | 502 | ||
503 | if (ret) { | 503 | if (ret) { |
504 | printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n"); | 504 | printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n"); |
505 | return ret; | 505 | return ret; |
506 | } | 506 | } |
507 | } | 507 | } |
508 | 508 | ||
509 | /* Write the LogicalEUN for the transfer unit */ | 509 | /* Write the LogicalEUN for the transfer unit */ |
510 | xfer->state = XFER_UNKNOWN; | 510 | xfer->state = XFER_UNKNOWN; |
511 | offset = xfer->Offset + 20; /* Bad! */ | 511 | offset = xfer->Offset + 20; /* Bad! */ |
@@ -513,12 +513,12 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
513 | 513 | ||
514 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), | 514 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), |
515 | &retlen, (u_char *) &unit); | 515 | &retlen, (u_char *) &unit); |
516 | 516 | ||
517 | if (ret) { | 517 | if (ret) { |
518 | printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n"); | 518 | printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n"); |
519 | return ret; | 519 | return ret; |
520 | } | 520 | } |
521 | 521 | ||
522 | /* Copy all data blocks from source unit to transfer unit */ | 522 | /* Copy all data blocks from source unit to transfer unit */ |
523 | src = eun->Offset; dest = xfer->Offset; | 523 | src = eun->Offset; dest = xfer->Offset; |
524 | 524 | ||
@@ -558,15 +558,15 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
558 | } | 558 | } |
559 | 559 | ||
560 | /* Write the BAM to the transfer unit */ | 560 | /* Write the BAM to the transfer unit */ |
561 | ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), | 561 | ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), |
562 | part->BlocksPerUnit * sizeof(int32_t), &retlen, | 562 | part->BlocksPerUnit * sizeof(int32_t), &retlen, |
563 | (u_char *)part->bam_cache); | 563 | (u_char *)part->bam_cache); |
564 | if (ret) { | 564 | if (ret) { |
565 | printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n"); | 565 | printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n"); |
566 | return ret; | 566 | return ret; |
567 | } | 567 | } |
568 | 568 | ||
569 | 569 | ||
570 | /* All clear? Then update the LogicalEUN again */ | 570 | /* All clear? Then update the LogicalEUN again */ |
571 | ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), | 571 | ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), |
572 | &retlen, (u_char *)&srcunitswap); | 572 | &retlen, (u_char *)&srcunitswap); |
@@ -574,9 +574,9 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
574 | if (ret) { | 574 | if (ret) { |
575 | printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n"); | 575 | printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n"); |
576 | return ret; | 576 | return ret; |
577 | } | 577 | } |
578 | 578 | ||
579 | 579 | ||
580 | /* Update the maps and usage stats*/ | 580 | /* Update the maps and usage stats*/ |
581 | i = xfer->EraseCount; | 581 | i = xfer->EraseCount; |
582 | xfer->EraseCount = eun->EraseCount; | 582 | xfer->EraseCount = eun->EraseCount; |
@@ -588,10 +588,10 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
588 | part->FreeTotal += free; | 588 | part->FreeTotal += free; |
589 | eun->Free = free; | 589 | eun->Free = free; |
590 | eun->Deleted = 0; | 590 | eun->Deleted = 0; |
591 | 591 | ||
592 | /* Now, the cache should be valid for the new block */ | 592 | /* Now, the cache should be valid for the new block */ |
593 | part->bam_index = srcunit; | 593 | part->bam_index = srcunit; |
594 | 594 | ||
595 | return 0; | 595 | return 0; |
596 | } /* copy_erase_unit */ | 596 | } /* copy_erase_unit */ |
597 | 597 | ||
@@ -608,7 +608,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, | |||
608 | oldest data unit instead. This means that we generally postpone | 608 | oldest data unit instead. This means that we generally postpone |
609 | the next reclaimation as long as possible, but shuffle static | 609 | the next reclaimation as long as possible, but shuffle static |
610 | stuff around a bit for wear leveling. | 610 | stuff around a bit for wear leveling. |
611 | 611 | ||
612 | ======================================================================*/ | 612 | ======================================================================*/ |
613 | 613 | ||
614 | static int reclaim_block(partition_t *part) | 614 | static int reclaim_block(partition_t *part) |
@@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part) | |||
666 | else | 666 | else |
667 | DEBUG(1, "ftl_cs: reclaim failed: no " | 667 | DEBUG(1, "ftl_cs: reclaim failed: no " |
668 | "suitable transfer units!\n"); | 668 | "suitable transfer units!\n"); |
669 | 669 | ||
670 | return -EIO; | 670 | return -EIO; |
671 | } | 671 | } |
672 | } | 672 | } |
@@ -715,7 +715,7 @@ static int reclaim_block(partition_t *part) | |||
715 | returns the block index -- the erase unit is just the currently | 715 | returns the block index -- the erase unit is just the currently |
716 | cached unit. If there are no free blocks, it returns 0 -- this | 716 | cached unit. If there are no free blocks, it returns 0 -- this |
717 | is never a valid data block because it contains the header. | 717 | is never a valid data block because it contains the header. |
718 | 718 | ||
719 | ======================================================================*/ | 719 | ======================================================================*/ |
720 | 720 | ||
721 | #ifdef PSYCHO_DEBUG | 721 | #ifdef PSYCHO_DEBUG |
@@ -737,7 +737,7 @@ static u_int32_t find_free(partition_t *part) | |||
737 | u_int32_t blk; | 737 | u_int32_t blk; |
738 | size_t retlen; | 738 | size_t retlen; |
739 | int ret; | 739 | int ret; |
740 | 740 | ||
741 | /* Find an erase unit with some free space */ | 741 | /* Find an erase unit with some free space */ |
742 | stop = (part->bam_index == 0xffff) ? 0 : part->bam_index; | 742 | stop = (part->bam_index == 0xffff) ? 0 : part->bam_index; |
743 | eun = stop; | 743 | eun = stop; |
@@ -749,17 +749,17 @@ static u_int32_t find_free(partition_t *part) | |||
749 | 749 | ||
750 | if (part->EUNInfo[eun].Free == 0) | 750 | if (part->EUNInfo[eun].Free == 0) |
751 | return 0; | 751 | return 0; |
752 | 752 | ||
753 | /* Is this unit's BAM cached? */ | 753 | /* Is this unit's BAM cached? */ |
754 | if (eun != part->bam_index) { | 754 | if (eun != part->bam_index) { |
755 | /* Invalidate cache */ | 755 | /* Invalidate cache */ |
756 | part->bam_index = 0xffff; | 756 | part->bam_index = 0xffff; |
757 | 757 | ||
758 | ret = part->mbd.mtd->read(part->mbd.mtd, | 758 | ret = part->mbd.mtd->read(part->mbd.mtd, |
759 | part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), | 759 | part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), |
760 | part->BlocksPerUnit * sizeof(u_int32_t), | 760 | part->BlocksPerUnit * sizeof(u_int32_t), |
761 | &retlen, (u_char *) (part->bam_cache)); | 761 | &retlen, (u_char *) (part->bam_cache)); |
762 | 762 | ||
763 | if (ret) { | 763 | if (ret) { |
764 | printk(KERN_WARNING"ftl: Error reading BAM in find_free\n"); | 764 | printk(KERN_WARNING"ftl: Error reading BAM in find_free\n"); |
765 | return 0; | 765 | return 0; |
@@ -781,14 +781,14 @@ static u_int32_t find_free(partition_t *part) | |||
781 | } | 781 | } |
782 | DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); | 782 | DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); |
783 | return blk; | 783 | return blk; |
784 | 784 | ||
785 | } /* find_free */ | 785 | } /* find_free */ |
786 | 786 | ||
787 | 787 | ||
788 | /*====================================================================== | 788 | /*====================================================================== |
789 | 789 | ||
790 | Read a series of sectors from an FTL partition. | 790 | Read a series of sectors from an FTL partition. |
791 | 791 | ||
792 | ======================================================================*/ | 792 | ======================================================================*/ |
793 | 793 | ||
794 | static int ftl_read(partition_t *part, caddr_t buffer, | 794 | static int ftl_read(partition_t *part, caddr_t buffer, |
@@ -798,7 +798,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, | |||
798 | u_long i; | 798 | u_long i; |
799 | int ret; | 799 | int ret; |
800 | size_t offset, retlen; | 800 | size_t offset, retlen; |
801 | 801 | ||
802 | DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", | 802 | DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", |
803 | part, sector, nblocks); | 803 | part, sector, nblocks); |
804 | if (!(part->state & FTL_FORMATTED)) { | 804 | if (!(part->state & FTL_FORMATTED)) { |
@@ -834,7 +834,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, | |||
834 | /*====================================================================== | 834 | /*====================================================================== |
835 | 835 | ||
836 | Write a series of sectors to an FTL partition | 836 | Write a series of sectors to an FTL partition |
837 | 837 | ||
838 | ======================================================================*/ | 838 | ======================================================================*/ |
839 | 839 | ||
840 | static int set_bam_entry(partition_t *part, u_int32_t log_addr, | 840 | static int set_bam_entry(partition_t *part, u_int32_t log_addr, |
@@ -855,7 +855,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, | |||
855 | blk = (log_addr % bsize) / SECTOR_SIZE; | 855 | blk = (log_addr % bsize) / SECTOR_SIZE; |
856 | offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) + | 856 | offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) + |
857 | le32_to_cpu(part->header.BAMOffset)); | 857 | le32_to_cpu(part->header.BAMOffset)); |
858 | 858 | ||
859 | #ifdef PSYCHO_DEBUG | 859 | #ifdef PSYCHO_DEBUG |
860 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), | 860 | ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), |
861 | &retlen, (u_char *)&old_addr); | 861 | &retlen, (u_char *)&old_addr); |
@@ -925,7 +925,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, | |||
925 | if (ret) | 925 | if (ret) |
926 | return ret; | 926 | return ret; |
927 | } | 927 | } |
928 | 928 | ||
929 | bsize = 1 << part->header.EraseUnitSize; | 929 | bsize = 1 << part->header.EraseUnitSize; |
930 | 930 | ||
931 | virt_addr = sector * SECTOR_SIZE | BLOCK_DATA; | 931 | virt_addr = sector * SECTOR_SIZE | BLOCK_DATA; |
@@ -949,12 +949,12 @@ static int ftl_write(partition_t *part, caddr_t buffer, | |||
949 | log_addr = part->bam_index * bsize + blk * SECTOR_SIZE; | 949 | log_addr = part->bam_index * bsize + blk * SECTOR_SIZE; |
950 | part->EUNInfo[part->bam_index].Free--; | 950 | part->EUNInfo[part->bam_index].Free--; |
951 | part->FreeTotal--; | 951 | part->FreeTotal--; |
952 | if (set_bam_entry(part, log_addr, 0xfffffffe)) | 952 | if (set_bam_entry(part, log_addr, 0xfffffffe)) |
953 | return -EIO; | 953 | return -EIO; |
954 | part->EUNInfo[part->bam_index].Deleted++; | 954 | part->EUNInfo[part->bam_index].Deleted++; |
955 | offset = (part->EUNInfo[part->bam_index].Offset + | 955 | offset = (part->EUNInfo[part->bam_index].Offset + |
956 | blk * SECTOR_SIZE); | 956 | blk * SECTOR_SIZE); |
957 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, | 957 | ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, |
958 | buffer); | 958 | buffer); |
959 | 959 | ||
960 | if (ret) { | 960 | if (ret) { |
@@ -964,7 +964,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, | |||
964 | offset); | 964 | offset); |
965 | return -EIO; | 965 | return -EIO; |
966 | } | 966 | } |
967 | 967 | ||
968 | /* Only delete the old entry when the new entry is ready */ | 968 | /* Only delete the old entry when the new entry is ready */ |
969 | old_addr = part->VirtualBlockMap[sector+i]; | 969 | old_addr = part->VirtualBlockMap[sector+i]; |
970 | if (old_addr != 0xffffffff) { | 970 | if (old_addr != 0xffffffff) { |
@@ -979,7 +979,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, | |||
979 | return -EIO; | 979 | return -EIO; |
980 | part->VirtualBlockMap[sector+i] = log_addr; | 980 | part->VirtualBlockMap[sector+i] = log_addr; |
981 | part->EUNInfo[part->bam_index].Deleted--; | 981 | part->EUNInfo[part->bam_index].Deleted--; |
982 | 982 | ||
983 | buffer += SECTOR_SIZE; | 983 | buffer += SECTOR_SIZE; |
984 | virt_addr += SECTOR_SIZE; | 984 | virt_addr += SECTOR_SIZE; |
985 | } | 985 | } |
@@ -1034,20 +1034,20 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
1034 | partition_t *partition; | 1034 | partition_t *partition; |
1035 | 1035 | ||
1036 | partition = kmalloc(sizeof(partition_t), GFP_KERNEL); | 1036 | partition = kmalloc(sizeof(partition_t), GFP_KERNEL); |
1037 | 1037 | ||
1038 | if (!partition) { | 1038 | if (!partition) { |
1039 | printk(KERN_WARNING "No memory to scan for FTL on %s\n", | 1039 | printk(KERN_WARNING "No memory to scan for FTL on %s\n", |
1040 | mtd->name); | 1040 | mtd->name); |
1041 | return; | 1041 | return; |
1042 | } | 1042 | } |
1043 | 1043 | ||
1044 | memset(partition, 0, sizeof(partition_t)); | 1044 | memset(partition, 0, sizeof(partition_t)); |
1045 | 1045 | ||
1046 | partition->mbd.mtd = mtd; | 1046 | partition->mbd.mtd = mtd; |
1047 | 1047 | ||
1048 | if ((scan_header(partition) == 0) && | 1048 | if ((scan_header(partition) == 0) && |
1049 | (build_maps(partition) == 0)) { | 1049 | (build_maps(partition) == 0)) { |
1050 | 1050 | ||
1051 | partition->state = FTL_FORMATTED; | 1051 | partition->state = FTL_FORMATTED; |
1052 | #ifdef PCMCIA_DEBUG | 1052 | #ifdef PCMCIA_DEBUG |
1053 | printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", | 1053 | printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", |
@@ -1086,7 +1086,7 @@ struct mtd_blktrans_ops ftl_tr = { | |||
1086 | 1086 | ||
1087 | int init_ftl(void) | 1087 | int init_ftl(void) |
1088 | { | 1088 | { |
1089 | DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n"); | 1089 | DEBUG(0, "$Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $\n"); |
1090 | 1090 | ||
1091 | return register_mtd_blktrans(&ftl_tr); | 1091 | return register_mtd_blktrans(&ftl_tr); |
1092 | } | 1092 | } |
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 8db65bf029ea..8a544890173d 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) | 2 | * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) |
3 | * | 3 | * |
4 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) | 4 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) |
@@ -7,7 +7,7 @@ | |||
7 | * (c) 1999 Machine Vision Holdings, Inc. | 7 | * (c) 1999 Machine Vision Holdings, Inc. |
8 | * Author: David Woodhouse <dwmw2@infradead.org> | 8 | * Author: David Woodhouse <dwmw2@infradead.org> |
9 | * | 9 | * |
10 | * $Id: inftlcore.c,v 1.18 2004/11/16 18:28:59 dwmw2 Exp $ | 10 | * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $ |
11 | * | 11 | * |
12 | * 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 |
13 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
@@ -113,14 +113,14 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
113 | 113 | ||
114 | if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { | 114 | if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { |
115 | /* | 115 | /* |
116 | Oh no we don't have | 116 | Oh no we don't have |
117 | mbd.size == heads * cylinders * sectors | 117 | mbd.size == heads * cylinders * sectors |
118 | */ | 118 | */ |
119 | printk(KERN_WARNING "INFTL: cannot calculate a geometry to " | 119 | printk(KERN_WARNING "INFTL: cannot calculate a geometry to " |
120 | "match size of 0x%lx.\n", inftl->mbd.size); | 120 | "match size of 0x%lx.\n", inftl->mbd.size); |
121 | printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " | 121 | printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " |
122 | "(== 0x%lx sects)\n", | 122 | "(== 0x%lx sects)\n", |
123 | inftl->cylinders, inftl->heads , inftl->sectors, | 123 | inftl->cylinders, inftl->heads , inftl->sectors, |
124 | (long)inftl->cylinders * (long)inftl->heads * | 124 | (long)inftl->cylinders * (long)inftl->heads * |
125 | (long)inftl->sectors ); | 125 | (long)inftl->sectors ); |
126 | } | 126 | } |
@@ -219,7 +219,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
219 | "Virtual Unit Chain %d!\n", thisVUC); | 219 | "Virtual Unit Chain %d!\n", thisVUC); |
220 | return BLOCK_NIL; | 220 | return BLOCK_NIL; |
221 | } | 221 | } |
222 | 222 | ||
223 | /* | 223 | /* |
224 | * Scan to find the Erase Unit which holds the actual data for each | 224 | * Scan to find the Erase Unit which holds the actual data for each |
225 | * 512-byte block within the Chain. | 225 | * 512-byte block within the Chain. |
@@ -260,7 +260,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
260 | "Unit Chain 0x%x\n", thisVUC); | 260 | "Unit Chain 0x%x\n", thisVUC); |
261 | return BLOCK_NIL; | 261 | return BLOCK_NIL; |
262 | } | 262 | } |
263 | 263 | ||
264 | thisEUN = inftl->PUtable[thisEUN]; | 264 | thisEUN = inftl->PUtable[thisEUN]; |
265 | } | 265 | } |
266 | 266 | ||
@@ -291,15 +291,15 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
291 | */ | 291 | */ |
292 | if (BlockMap[block] == BLOCK_NIL) | 292 | if (BlockMap[block] == BLOCK_NIL) |
293 | continue; | 293 | continue; |
294 | 294 | ||
295 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * | 295 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * |
296 | BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, | 296 | BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, |
297 | &retlen, movebuf); | 297 | &retlen, movebuf); |
298 | if (ret < 0) { | 298 | if (ret < 0) { |
299 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * | 299 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * |
300 | BlockMap[block]) + (block * SECTORSIZE), | 300 | BlockMap[block]) + (block * SECTORSIZE), |
301 | SECTORSIZE, &retlen, movebuf); | 301 | SECTORSIZE, &retlen, movebuf); |
302 | if (ret != -EIO) | 302 | if (ret != -EIO) |
303 | DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " | 303 | DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " |
304 | "away on retry?\n"); | 304 | "away on retry?\n"); |
305 | } | 305 | } |
@@ -351,7 +351,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
351 | static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) | 351 | static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) |
352 | { | 352 | { |
353 | /* | 353 | /* |
354 | * This is the part that needs some cleverness applied. | 354 | * This is the part that needs some cleverness applied. |
355 | * For now, I'm doing the minimum applicable to actually | 355 | * For now, I'm doing the minimum applicable to actually |
356 | * get the thing to work. | 356 | * get the thing to work. |
357 | * Wear-levelling and other clever stuff needs to be implemented | 357 | * Wear-levelling and other clever stuff needs to be implemented |
@@ -410,7 +410,7 @@ static int nrbits(unsigned int val, int bitcount) | |||
410 | } | 410 | } |
411 | 411 | ||
412 | /* | 412 | /* |
413 | * INFTL_findwriteunit: Return the unit number into which we can write | 413 | * INFTL_findwriteunit: Return the unit number into which we can write |
414 | * for this block. Make it available if it isn't already. | 414 | * for this block. Make it available if it isn't already. |
415 | */ | 415 | */ |
416 | static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) | 416 | static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) |
@@ -459,10 +459,10 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) | |||
459 | * Invalid block. Don't use it any more. | 459 | * Invalid block. Don't use it any more. |
460 | * Must implement. | 460 | * Must implement. |
461 | */ | 461 | */ |
462 | break; | 462 | break; |
463 | } | 463 | } |
464 | 464 | ||
465 | if (!silly--) { | 465 | if (!silly--) { |
466 | printk(KERN_WARNING "INFTL: infinite loop in " | 466 | printk(KERN_WARNING "INFTL: infinite loop in " |
467 | "Virtual Unit Chain 0x%x\n", thisVUC); | 467 | "Virtual Unit Chain 0x%x\n", thisVUC); |
468 | return 0xffff; | 468 | return 0xffff; |
@@ -478,7 +478,7 @@ hitused: | |||
478 | 478 | ||
479 | 479 | ||
480 | /* | 480 | /* |
481 | * OK. We didn't find one in the existing chain, or there | 481 | * OK. We didn't find one in the existing chain, or there |
482 | * is no existing chain. Allocate a new one. | 482 | * is no existing chain. Allocate a new one. |
483 | */ | 483 | */ |
484 | writeEUN = INFTL_findfreeblock(inftl, 0); | 484 | writeEUN = INFTL_findfreeblock(inftl, 0); |
@@ -502,8 +502,8 @@ hitused: | |||
502 | if (writeEUN == BLOCK_NIL) { | 502 | if (writeEUN == BLOCK_NIL) { |
503 | /* | 503 | /* |
504 | * Ouch. This should never happen - we should | 504 | * Ouch. This should never happen - we should |
505 | * always be able to make some room somehow. | 505 | * always be able to make some room somehow. |
506 | * If we get here, we've allocated more storage | 506 | * If we get here, we've allocated more storage |
507 | * space than actual media, or our makefreeblock | 507 | * space than actual media, or our makefreeblock |
508 | * routine is missing something. | 508 | * routine is missing something. |
509 | */ | 509 | */ |
@@ -514,7 +514,7 @@ hitused: | |||
514 | INFTL_dumpVUchains(inftl); | 514 | INFTL_dumpVUchains(inftl); |
515 | #endif | 515 | #endif |
516 | return BLOCK_NIL; | 516 | return BLOCK_NIL; |
517 | } | 517 | } |
518 | } | 518 | } |
519 | 519 | ||
520 | /* | 520 | /* |
@@ -539,7 +539,7 @@ hitused: | |||
539 | parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; | 539 | parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; |
540 | parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; | 540 | parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; |
541 | parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; | 541 | parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; |
542 | 542 | ||
543 | oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); | 543 | oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); |
544 | oob.u.a.prevUnitNo = cpu_to_le16(prev_block); | 544 | oob.u.a.prevUnitNo = cpu_to_le16(prev_block); |
545 | oob.u.a.ANAC = anac; | 545 | oob.u.a.ANAC = anac; |
@@ -558,7 +558,7 @@ hitused: | |||
558 | oob.u.b.parityPerField = parity; | 558 | oob.u.b.parityPerField = parity; |
559 | oob.u.b.discarded = 0xaa; | 559 | oob.u.b.discarded = 0xaa; |
560 | 560 | ||
561 | MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + | 561 | MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + |
562 | SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); | 562 | SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); |
563 | 563 | ||
564 | inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; | 564 | inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; |
@@ -598,7 +598,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) | |||
598 | "Virtual Unit Chain %d!\n", thisVUC); | 598 | "Virtual Unit Chain %d!\n", thisVUC); |
599 | return; | 599 | return; |
600 | } | 600 | } |
601 | 601 | ||
602 | /* | 602 | /* |
603 | * Scan through the Erase Units to determine whether any data is in | 603 | * Scan through the Erase Units to determine whether any data is in |
604 | * each of the 512-byte blocks within the Chain. | 604 | * each of the 512-byte blocks within the Chain. |
@@ -638,7 +638,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) | |||
638 | "Unit Chain 0x%x\n", thisVUC); | 638 | "Unit Chain 0x%x\n", thisVUC); |
639 | return; | 639 | return; |
640 | } | 640 | } |
641 | 641 | ||
642 | thisEUN = inftl->PUtable[thisEUN]; | 642 | thisEUN = inftl->PUtable[thisEUN]; |
643 | } | 643 | } |
644 | 644 | ||
@@ -754,7 +754,7 @@ foundit: | |||
754 | return 0; | 754 | return 0; |
755 | } | 755 | } |
756 | 756 | ||
757 | static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, | 757 | static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, |
758 | char *buffer) | 758 | char *buffer) |
759 | { | 759 | { |
760 | struct INFTLrecord *inftl = (void *)mbd; | 760 | struct INFTLrecord *inftl = (void *)mbd; |
@@ -889,7 +889,7 @@ extern char inftlmountrev[]; | |||
889 | 889 | ||
890 | static int __init init_inftl(void) | 890 | static int __init init_inftl(void) |
891 | { | 891 | { |
892 | printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.18 $, " | 892 | printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, " |
893 | "inftlmount.c %s\n", inftlmountrev); | 893 | "inftlmount.c %s\n", inftlmountrev); |
894 | 894 | ||
895 | return register_mtd_blktrans(&inftl_tr); | 895 | return register_mtd_blktrans(&inftl_tr); |
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 3dac53feeee2..43fdc9433882 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c | |||
@@ -1,14 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * inftlmount.c -- INFTL mount code with extensive checks. | 2 | * inftlmount.c -- INFTL mount code with extensive checks. |
3 | * | 3 | * |
4 | * Author: Greg Ungerer (gerg@snapgear.com) | 4 | * Author: Greg Ungerer (gerg@snapgear.com) |
5 | * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com) | 5 | * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com) |
6 | * | 6 | * |
7 | * Based heavily on the nftlmount.c code which is: | 7 | * Based heavily on the nftlmount.c code which is: |
8 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 8 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
9 | * Copyright (C) 2000 Netgem S.A. | 9 | * Copyright (C) 2000 Netgem S.A. |
10 | * | 10 | * |
11 | * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev Exp $ | 11 | * $Id: inftlmount.c,v 1.18 2005/11/07 11:14:20 gleixner Exp $ |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
@@ -41,7 +41,7 @@ | |||
41 | #include <linux/mtd/inftl.h> | 41 | #include <linux/mtd/inftl.h> |
42 | #include <linux/mtd/compatmac.h> | 42 | #include <linux/mtd/compatmac.h> |
43 | 43 | ||
44 | char inftlmountrev[]="$Revision: 1.16 $"; | 44 | char inftlmountrev[]="$Revision: 1.18 $"; |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * find_boot_record: Find the INFTL Media Header and its Spare copy which | 47 | * find_boot_record: Find the INFTL Media Header and its Spare copy which |
@@ -273,7 +273,7 @@ static int find_boot_record(struct INFTLrecord *inftl) | |||
273 | inftl->nb_boot_blocks); | 273 | inftl->nb_boot_blocks); |
274 | return -1; | 274 | return -1; |
275 | } | 275 | } |
276 | 276 | ||
277 | inftl->mbd.size = inftl->numvunits * | 277 | inftl->mbd.size = inftl->numvunits * |
278 | (inftl->EraseSize / SECTORSIZE); | 278 | (inftl->EraseSize / SECTORSIZE); |
279 | 279 | ||
@@ -302,7 +302,7 @@ static int find_boot_record(struct INFTLrecord *inftl) | |||
302 | inftl->nb_blocks * sizeof(u16)); | 302 | inftl->nb_blocks * sizeof(u16)); |
303 | return -ENOMEM; | 303 | return -ENOMEM; |
304 | } | 304 | } |
305 | 305 | ||
306 | /* Mark the blocks before INFTL MediaHeader as reserved */ | 306 | /* Mark the blocks before INFTL MediaHeader as reserved */ |
307 | for (i = 0; i < inftl->nb_boot_blocks; i++) | 307 | for (i = 0; i < inftl->nb_boot_blocks; i++) |
308 | inftl->PUtable[i] = BLOCK_RESERVED; | 308 | inftl->PUtable[i] = BLOCK_RESERVED; |
@@ -380,7 +380,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, | |||
380 | * | 380 | * |
381 | * Return: 0 when succeed, -1 on error. | 381 | * Return: 0 when succeed, -1 on error. |
382 | * | 382 | * |
383 | * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? | 383 | * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? |
384 | */ | 384 | */ |
385 | int INFTL_formatblock(struct INFTLrecord *inftl, int block) | 385 | int INFTL_formatblock(struct INFTLrecord *inftl, int block) |
386 | { | 386 | { |
@@ -563,7 +563,7 @@ int INFTL_mount(struct INFTLrecord *s) | |||
563 | /* Search for INFTL MediaHeader and Spare INFTL Media Header */ | 563 | /* Search for INFTL MediaHeader and Spare INFTL Media Header */ |
564 | if (find_boot_record(s) < 0) { | 564 | if (find_boot_record(s) < 0) { |
565 | printk(KERN_WARNING "INFTL: could not find valid boot record?\n"); | 565 | printk(KERN_WARNING "INFTL: could not find valid boot record?\n"); |
566 | return -1; | 566 | return -ENXIO; |
567 | } | 567 | } |
568 | 568 | ||
569 | /* Init the logical to physical table */ | 569 | /* Init the logical to physical table */ |
@@ -601,7 +601,7 @@ int INFTL_mount(struct INFTLrecord *s) | |||
601 | 601 | ||
602 | for (chain_length = 0; ; chain_length++) { | 602 | for (chain_length = 0; ; chain_length++) { |
603 | 603 | ||
604 | if ((chain_length == 0) && | 604 | if ((chain_length == 0) && |
605 | (s->PUtable[block] != BLOCK_NOTEXPLORED)) { | 605 | (s->PUtable[block] != BLOCK_NOTEXPLORED)) { |
606 | /* Nothing to do here, onto next block */ | 606 | /* Nothing to do here, onto next block */ |
607 | break; | 607 | break; |
@@ -748,7 +748,7 @@ int INFTL_mount(struct INFTLrecord *s) | |||
748 | "in virtual chain %d\n", | 748 | "in virtual chain %d\n", |
749 | s->PUtable[block], logical_block); | 749 | s->PUtable[block], logical_block); |
750 | s->PUtable[block] = BLOCK_NIL; | 750 | s->PUtable[block] = BLOCK_NIL; |
751 | 751 | ||
752 | } | 752 | } |
753 | if (ANACtable[block] != ANAC) { | 753 | if (ANACtable[block] != ANAC) { |
754 | /* | 754 | /* |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 44781a83b2e7..48638c8097a5 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/maps/Kconfig | 1 | # drivers/mtd/maps/Kconfig |
2 | # $Id: Kconfig,v 1.55 2005/07/02 01:53:24 tpoynor Exp $ | 2 | # $Id: Kconfig,v 1.61 2005/11/07 11:14:26 gleixner Exp $ |
3 | 3 | ||
4 | menu "Mapping drivers for chip access" | 4 | menu "Mapping drivers for chip access" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -64,9 +64,9 @@ config MTD_SUN_UFLASH | |||
64 | tristate "Sun Microsystems userflash support" | 64 | tristate "Sun Microsystems userflash support" |
65 | depends on (SPARC32 || SPARC64) && MTD_CFI | 65 | depends on (SPARC32 || SPARC64) && MTD_CFI |
66 | help | 66 | help |
67 | This provides a 'mapping' driver which supports the way in | 67 | This provides a 'mapping' driver which supports the way in |
68 | which user-programmable flash chips are connected on various | 68 | which user-programmable flash chips are connected on various |
69 | Sun Microsystems boardsets. This driver will require CFI support | 69 | Sun Microsystems boardsets. This driver will require CFI support |
70 | in the kernel, so if you did not enable CFI previously, do that now. | 70 | in the kernel, so if you did not enable CFI previously, do that now. |
71 | 71 | ||
72 | config MTD_PNC2000 | 72 | config MTD_PNC2000 |
@@ -89,22 +89,22 @@ config MTD_NETSC520 | |||
89 | depends on X86 && MTD_CFI && MTD_PARTITIONS | 89 | depends on X86 && MTD_CFI && MTD_PARTITIONS |
90 | help | 90 | help |
91 | This enables access routines for the flash chips on the AMD NetSc520 | 91 | This enables access routines for the flash chips on the AMD NetSc520 |
92 | demonstration board. If you have one of these boards and would like | 92 | demonstration board. If you have one of these boards and would like |
93 | to use the flash chips on it, say 'Y'. | 93 | to use the flash chips on it, say 'Y'. |
94 | 94 | ||
95 | config MTD_TS5500 | 95 | config MTD_TS5500 |
96 | tristate "JEDEC Flash device mapped on Technologic Systems TS-5500" | 96 | tristate "JEDEC Flash device mapped on Technologic Systems TS-5500" |
97 | depends on X86 && MTD_JEDECPROBE && MTD_PARTITIONS | 97 | depends on ELAN |
98 | select MTD_PARTITIONS | ||
99 | select MTD_JEDECPROBE | ||
100 | select MTD_CFI_AMDSTD | ||
98 | help | 101 | help |
99 | This provides a driver for the on-board flash of the Technologic | 102 | This provides a driver for the on-board flash of the Technologic |
100 | System's TS-5500 board. The flash is split into 3 partitions | 103 | System's TS-5500 board. The 2MB flash is split into 3 partitions |
101 | which are accessed as separate MTD devices. | 104 | which are accessed as separate MTD devices. |
102 | 105 | ||
103 | mtd0 and mtd2 are the two BIOS drives. Unfortunately the BIOS | 106 | mtd0 and mtd2 are the two BIOS drives, which use the resident |
104 | uses a proprietary flash translation layer from General Software, | 107 | flash disk (RFD) flash translation layer. |
105 | which is not supported (the drives cannot be mounted). You can | ||
106 | create your own file system (jffs for example), but the BIOS | ||
107 | won't be able to boot from it. | ||
108 | 108 | ||
109 | mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL. | 109 | mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL. |
110 | 110 | ||
@@ -212,11 +212,18 @@ config MTD_NETtel | |||
212 | Support for flash chips on NETtel/SecureEdge/SnapGear boards. | 212 | Support for flash chips on NETtel/SecureEdge/SnapGear boards. |
213 | 213 | ||
214 | config MTD_ALCHEMY | 214 | config MTD_ALCHEMY |
215 | tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' | 215 | tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' |
216 | depends on MIPS && SOC_AU1X00 | 216 | depends on SOC_AU1X00 |
217 | help | 217 | help |
218 | Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards | 218 | Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards |
219 | 219 | ||
220 | config MTD_MTX1 | ||
221 | tristate "4G Systems MTX-1 Flash device" | ||
222 | depends on MIPS && MIPS_MTX1 | ||
223 | help | ||
224 | Flash memory access on 4G Systems MTX-1 Board. If you have one of | ||
225 | these boards and would like to use the flash chips on it, say 'Y'. | ||
226 | |||
220 | config MTD_DILNETPC | 227 | config MTD_DILNETPC |
221 | tristate "CFI Flash device mapped on DIL/Net PC" | 228 | tristate "CFI Flash device mapped on DIL/Net PC" |
222 | depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT | 229 | depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT |
@@ -244,14 +251,14 @@ config MTD_L440GX | |||
244 | 251 | ||
245 | config MTD_SBC8240 | 252 | config MTD_SBC8240 |
246 | tristate "Flash device on SBC8240" | 253 | tristate "Flash device on SBC8240" |
247 | depends on PPC32 && MTD_JEDECPROBE && 6xx && 8260 | 254 | depends on MTD_JEDECPROBE && 8260 |
248 | help | 255 | help |
249 | Flash access on the SBC8240 board from Wind River. See | 256 | Flash access on the SBC8240 board from Wind River. See |
250 | <http://www.windriver.com/products/sbc8240/> | 257 | <http://www.windriver.com/products/sbc8240/> |
251 | 258 | ||
252 | config MTD_TQM8XXL | 259 | config MTD_TQM8XXL |
253 | tristate "CFI Flash device mapped on TQM8XXL" | 260 | tristate "CFI Flash device mapped on TQM8XXL" |
254 | depends on MTD_CFI && PPC32 && 8xx && TQM8xxL | 261 | depends on MTD_CFI && TQM8xxL |
255 | help | 262 | help |
256 | The TQM8xxL PowerPC board has up to two banks of CFI-compliant | 263 | The TQM8xxL PowerPC board has up to two banks of CFI-compliant |
257 | chips, currently uses AMD one. This 'mapping' driver supports | 264 | chips, currently uses AMD one. This 'mapping' driver supports |
@@ -261,7 +268,7 @@ config MTD_TQM8XXL | |||
261 | 268 | ||
262 | config MTD_RPXLITE | 269 | config MTD_RPXLITE |
263 | tristate "CFI Flash device mapped on RPX Lite or CLLF" | 270 | tristate "CFI Flash device mapped on RPX Lite or CLLF" |
264 | depends on MTD_CFI && PPC32 && 8xx && (RPXCLASSIC || RPXLITE) | 271 | depends on MTD_CFI && (RPXCLASSIC || RPXLITE) |
265 | help | 272 | help |
266 | The RPXLite PowerPC board has CFI-compliant chips mapped in | 273 | The RPXLite PowerPC board has CFI-compliant chips mapped in |
267 | a strange sparse mapping. This 'mapping' driver supports that | 274 | a strange sparse mapping. This 'mapping' driver supports that |
@@ -271,7 +278,7 @@ config MTD_RPXLITE | |||
271 | 278 | ||
272 | config MTD_MBX860 | 279 | config MTD_MBX860 |
273 | tristate "System flash on MBX860 board" | 280 | tristate "System flash on MBX860 board" |
274 | depends on MTD_CFI && PPC32 && 8xx && MBX | 281 | depends on MTD_CFI && MBX |
275 | help | 282 | help |
276 | This enables access routines for the flash chips on the Motorola | 283 | This enables access routines for the flash chips on the Motorola |
277 | MBX860 board. If you have one of these boards and would like | 284 | MBX860 board. If you have one of these boards and would like |
@@ -279,7 +286,7 @@ config MTD_MBX860 | |||
279 | 286 | ||
280 | config MTD_DBOX2 | 287 | config MTD_DBOX2 |
281 | tristate "CFI Flash device mapped on D-Box2" | 288 | tristate "CFI Flash device mapped on D-Box2" |
282 | depends on PPC32 && 8xx && DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD | 289 | depends on DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD |
283 | help | 290 | help |
284 | This enables access routines for the flash chips on the Nokia/Sagem | 291 | This enables access routines for the flash chips on the Nokia/Sagem |
285 | D-Box 2 board. If you have one of these boards and would like to use | 292 | D-Box 2 board. If you have one of these boards and would like to use |
@@ -287,14 +294,14 @@ config MTD_DBOX2 | |||
287 | 294 | ||
288 | config MTD_CFI_FLAGADM | 295 | config MTD_CFI_FLAGADM |
289 | tristate "CFI Flash device mapping on FlagaDM" | 296 | tristate "CFI Flash device mapping on FlagaDM" |
290 | depends on PPC32 && 8xx && MTD_CFI | 297 | depends on 8xx && MTD_CFI |
291 | help | 298 | help |
292 | Mapping for the Flaga digital module. If you don't have one, ignore | 299 | Mapping for the Flaga digital module. If you don't have one, ignore |
293 | this setting. | 300 | this setting. |
294 | 301 | ||
295 | config MTD_BEECH | 302 | config MTD_BEECH |
296 | tristate "CFI Flash device mapped on IBM 405LP Beech" | 303 | tristate "CFI Flash device mapped on IBM 405LP Beech" |
297 | depends on MTD_CFI && PPC32 && 40x && BEECH | 304 | depends on MTD_CFI && BEECH |
298 | help | 305 | help |
299 | This enables access routines for the flash chips on the IBM | 306 | This enables access routines for the flash chips on the IBM |
300 | 405LP Beech board. If you have one of these boards and would like | 307 | 405LP Beech board. If you have one of these boards and would like |
@@ -302,7 +309,7 @@ config MTD_BEECH | |||
302 | 309 | ||
303 | config MTD_ARCTIC | 310 | config MTD_ARCTIC |
304 | tristate "CFI Flash device mapped on IBM 405LP Arctic" | 311 | tristate "CFI Flash device mapped on IBM 405LP Arctic" |
305 | depends on MTD_CFI && PPC32 && 40x && ARCTIC2 | 312 | depends on MTD_CFI && ARCTIC2 |
306 | help | 313 | help |
307 | This enables access routines for the flash chips on the IBM 405LP | 314 | This enables access routines for the flash chips on the IBM 405LP |
308 | Arctic board. If you have one of these boards and would like to | 315 | Arctic board. If you have one of these boards and would like to |
@@ -310,7 +317,7 @@ config MTD_ARCTIC | |||
310 | 317 | ||
311 | config MTD_WALNUT | 318 | config MTD_WALNUT |
312 | tristate "Flash device mapped on IBM 405GP Walnut" | 319 | tristate "Flash device mapped on IBM 405GP Walnut" |
313 | depends on MTD_JEDECPROBE && PPC32 && 40x && WALNUT | 320 | depends on MTD_JEDECPROBE && WALNUT |
314 | help | 321 | help |
315 | This enables access routines for the flash chips on the IBM 405GP | 322 | This enables access routines for the flash chips on the IBM 405GP |
316 | Walnut board. If you have one of these boards and would like to | 323 | Walnut board. If you have one of these boards and would like to |
@@ -318,7 +325,7 @@ config MTD_WALNUT | |||
318 | 325 | ||
319 | config MTD_EBONY | 326 | config MTD_EBONY |
320 | tristate "Flash devices mapped on IBM 440GP Ebony" | 327 | tristate "Flash devices mapped on IBM 440GP Ebony" |
321 | depends on MTD_JEDECPROBE && PPC32 && 44x && EBONY | 328 | depends on MTD_JEDECPROBE && EBONY |
322 | help | 329 | help |
323 | This enables access routines for the flash chips on the IBM 440GP | 330 | This enables access routines for the flash chips on the IBM 440GP |
324 | Ebony board. If you have one of these boards and would like to | 331 | Ebony board. If you have one of these boards and would like to |
@@ -326,7 +333,7 @@ config MTD_EBONY | |||
326 | 333 | ||
327 | config MTD_OCOTEA | 334 | config MTD_OCOTEA |
328 | tristate "Flash devices mapped on IBM 440GX Ocotea" | 335 | tristate "Flash devices mapped on IBM 440GX Ocotea" |
329 | depends on MTD_CFI && PPC32 && 44x && OCOTEA | 336 | depends on MTD_CFI && OCOTEA |
330 | help | 337 | help |
331 | This enables access routines for the flash chips on the IBM 440GX | 338 | This enables access routines for the flash chips on the IBM 440GX |
332 | Ocotea board. If you have one of these boards and would like to | 339 | Ocotea board. If you have one of these boards and would like to |
@@ -334,12 +341,20 @@ config MTD_OCOTEA | |||
334 | 341 | ||
335 | config MTD_REDWOOD | 342 | config MTD_REDWOOD |
336 | tristate "CFI Flash devices mapped on IBM Redwood" | 343 | tristate "CFI Flash devices mapped on IBM Redwood" |
337 | depends on MTD_CFI && PPC32 && 4xx && 40x && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) | 344 | depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) |
338 | help | 345 | help |
339 | This enables access routines for the flash chips on the IBM | 346 | This enables access routines for the flash chips on the IBM |
340 | Redwood board. If you have one of these boards and would like to | 347 | Redwood board. If you have one of these boards and would like to |
341 | use the flash chips on it, say 'Y'. | 348 | use the flash chips on it, say 'Y'. |
342 | 349 | ||
350 | config MTD_TQM834x | ||
351 | tristate "Flash device mapped on TQ Components TQM834x Boards" | ||
352 | depends on MTD_CFI && TQM834x | ||
353 | help | ||
354 | This enables access routines for the flash chips on the | ||
355 | TQ Components TQM834x boards. If you have one of these boards | ||
356 | and would like to use the flash chips on it, say 'Y'. | ||
357 | |||
343 | config MTD_CSTM_MIPS_IXX | 358 | config MTD_CSTM_MIPS_IXX |
344 | tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board" | 359 | tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board" |
345 | depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS | 360 | depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS |
@@ -362,8 +377,8 @@ config MTD_CSTM_MIPS_IXX_START | |||
362 | default "0x8000000" | 377 | default "0x8000000" |
363 | help | 378 | help |
364 | This is the physical memory location that the MTD driver will | 379 | This is the physical memory location that the MTD driver will |
365 | use for the flash chips on your particular target board. | 380 | use for the flash chips on your particular target board. |
366 | Refer to the memory map which should hopefully be in the | 381 | Refer to the memory map which should hopefully be in the |
367 | documentation for your board. | 382 | documentation for your board. |
368 | 383 | ||
369 | config MTD_CSTM_MIPS_IXX_LEN | 384 | config MTD_CSTM_MIPS_IXX_LEN |
@@ -371,7 +386,7 @@ config MTD_CSTM_MIPS_IXX_LEN | |||
371 | depends on MTD_CSTM_MIPS_IXX | 386 | depends on MTD_CSTM_MIPS_IXX |
372 | default "0x4000000" | 387 | default "0x4000000" |
373 | help | 388 | help |
374 | This is the total length that the MTD driver will use for the | 389 | This is the total length that the MTD driver will use for the |
375 | flash chips on your particular board. Refer to the memory | 390 | flash chips on your particular board. Refer to the memory |
376 | map which should hopefully be in the documentation for your | 391 | map which should hopefully be in the documentation for your |
377 | board. | 392 | board. |
@@ -405,14 +420,14 @@ config MTD_ARM_INTEGRATOR | |||
405 | 420 | ||
406 | config MTD_CDB89712 | 421 | config MTD_CDB89712 |
407 | tristate "Cirrus CDB89712 evaluation board mappings" | 422 | tristate "Cirrus CDB89712 evaluation board mappings" |
408 | depends on ARM && MTD_CFI && ARCH_CDB89712 | 423 | depends on MTD_CFI && ARCH_CDB89712 |
409 | help | 424 | help |
410 | This enables access to the flash or ROM chips on the CDB89712 board. | 425 | This enables access to the flash or ROM chips on the CDB89712 board. |
411 | If you have such a board, say 'Y'. | 426 | If you have such a board, say 'Y'. |
412 | 427 | ||
413 | config MTD_SA1100 | 428 | config MTD_SA1100 |
414 | tristate "CFI Flash device mapped on StrongARM SA11x0" | 429 | tristate "CFI Flash device mapped on StrongARM SA11x0" |
415 | depends on ARM && MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS | 430 | depends on MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS |
416 | help | 431 | help |
417 | This enables access to the flash chips on most platforms based on | 432 | This enables access to the flash chips on most platforms based on |
418 | the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. | 433 | the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. |
@@ -420,13 +435,13 @@ config MTD_SA1100 | |||
420 | 435 | ||
421 | config MTD_IPAQ | 436 | config MTD_IPAQ |
422 | tristate "CFI Flash device mapped on Compaq/HP iPAQ" | 437 | tristate "CFI Flash device mapped on Compaq/HP iPAQ" |
423 | depends on ARM && IPAQ_HANDHELD && MTD_CFI | 438 | depends on IPAQ_HANDHELD && MTD_CFI |
424 | help | 439 | help |
425 | This provides a driver for the on-board flash of the iPAQ. | 440 | This provides a driver for the on-board flash of the iPAQ. |
426 | 441 | ||
427 | config MTD_DC21285 | 442 | config MTD_DC21285 |
428 | tristate "CFI Flash device mapped on DC21285 Footbridge" | 443 | tristate "CFI Flash device mapped on DC21285 Footbridge" |
429 | depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS | 444 | depends on MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS |
430 | help | 445 | help |
431 | This provides a driver for the flash accessed using Intel's | 446 | This provides a driver for the flash accessed using Intel's |
432 | 21285 bridge used with Intel's StrongARM processors. More info at | 447 | 21285 bridge used with Intel's StrongARM processors. More info at |
@@ -434,33 +449,33 @@ config MTD_DC21285 | |||
434 | 449 | ||
435 | config MTD_IQ80310 | 450 | config MTD_IQ80310 |
436 | tristate "CFI Flash device mapped on the XScale IQ80310 board" | 451 | tristate "CFI Flash device mapped on the XScale IQ80310 board" |
437 | depends on ARM && MTD_CFI && ARCH_IQ80310 | 452 | depends on MTD_CFI && ARCH_IQ80310 |
438 | help | 453 | help |
439 | This enables access routines for the flash chips on the Intel XScale | 454 | This enables access routines for the flash chips on the Intel XScale |
440 | IQ80310 evaluation board. If you have one of these boards and would | 455 | IQ80310 evaluation board. If you have one of these boards and would |
441 | like to use the flash chips on it, say 'Y'. | 456 | like to use the flash chips on it, say 'Y'. |
442 | 457 | ||
443 | config MTD_IXP4XX | 458 | config MTD_IXP4XX |
444 | tristate "CFI Flash device mapped on Intel IXP4xx based systems" | 459 | tristate "CFI Flash device mapped on Intel IXP4xx based systems" |
445 | depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX | 460 | depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX |
446 | help | 461 | help |
447 | This enables MTD access to flash devices on platforms based | 462 | This enables MTD access to flash devices on platforms based |
448 | on Intel's IXP4xx family of network processors such as the | 463 | on Intel's IXP4xx family of network processors such as the |
449 | IXDP425 and Coyote. If you have an IXP4xx based board and | 464 | IXDP425 and Coyote. If you have an IXP4xx based board and |
450 | would like to use the flash chips on it, say 'Y'. | 465 | would like to use the flash chips on it, say 'Y'. |
451 | 466 | ||
452 | config MTD_IXP2000 | 467 | config MTD_IXP2000 |
453 | tristate "CFI Flash device mapped on Intel IXP2000 based systems" | 468 | tristate "CFI Flash device mapped on Intel IXP2000 based systems" |
454 | depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 | 469 | depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 |
455 | help | 470 | help |
456 | This enables MTD access to flash devices on platforms based | 471 | This enables MTD access to flash devices on platforms based |
457 | on Intel's IXP2000 family of network processors such as the | 472 | on Intel's IXP2000 family of network processors such as the |
458 | IXDP425 and Coyote. If you have an IXP2000 based board and | 473 | IXDP425 and Coyote. If you have an IXP2000 based board and |
459 | would like to use the flash chips on it, say 'Y'. | 474 | would like to use the flash chips on it, say 'Y'. |
460 | 475 | ||
461 | config MTD_EPXA10DB | 476 | config MTD_EPXA10DB |
462 | tristate "CFI Flash device mapped on Epxa10db" | 477 | tristate "CFI Flash device mapped on Epxa10db" |
463 | depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT | 478 | depends on MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT |
464 | help | 479 | help |
465 | This enables support for the flash devices on the Altera | 480 | This enables support for the flash devices on the Altera |
466 | Excalibur XA10 Development Board. If you are building a kernel | 481 | Excalibur XA10 Development Board. If you are building a kernel |
@@ -468,21 +483,21 @@ config MTD_EPXA10DB | |||
468 | 483 | ||
469 | config MTD_FORTUNET | 484 | config MTD_FORTUNET |
470 | tristate "CFI Flash device mapped on the FortuNet board" | 485 | tristate "CFI Flash device mapped on the FortuNet board" |
471 | depends on ARM && MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET | 486 | depends on MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET |
472 | help | 487 | help |
473 | This enables access to the Flash on the FortuNet board. If you | 488 | This enables access to the Flash on the FortuNet board. If you |
474 | have such a board, say 'Y'. | 489 | have such a board, say 'Y'. |
475 | 490 | ||
476 | config MTD_AUTCPU12 | 491 | config MTD_AUTCPU12 |
477 | tristate "NV-RAM mapping AUTCPU12 board" | 492 | tristate "NV-RAM mapping AUTCPU12 board" |
478 | depends on ARM && ARCH_AUTCPU12 | 493 | depends on ARCH_AUTCPU12 |
479 | help | 494 | help |
480 | This enables access to the NV-RAM on autronix autcpu12 board. | 495 | This enables access to the NV-RAM on autronix autcpu12 board. |
481 | If you have such a board, say 'Y'. | 496 | If you have such a board, say 'Y'. |
482 | 497 | ||
483 | config MTD_EDB7312 | 498 | config MTD_EDB7312 |
484 | tristate "CFI Flash device mapped on EDB7312" | 499 | tristate "CFI Flash device mapped on EDB7312" |
485 | depends on ARM && MTD_CFI | 500 | depends on ARCH_EDB7312 && MTD_CFI |
486 | help | 501 | help |
487 | This enables access to the CFI Flash on the Cogent EDB7312 board. | 502 | This enables access to the CFI Flash on the Cogent EDB7312 board. |
488 | If you have such a board, say 'Y' here. | 503 | If you have such a board, say 'Y' here. |
@@ -496,7 +511,7 @@ config MTD_IMPA7 | |||
496 | 511 | ||
497 | config MTD_CEIVA | 512 | config MTD_CEIVA |
498 | tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" | 513 | tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" |
499 | depends on ARM && MTD_JEDECPROBE && ARCH_CEIVA | 514 | depends on MTD_JEDECPROBE && ARCH_CEIVA |
500 | help | 515 | help |
501 | This enables access to the flash chips on the Ceiva/Polaroid | 516 | This enables access to the flash chips on the Ceiva/Polaroid |
502 | PhotoMax Digital Picture Frame. | 517 | PhotoMax Digital Picture Frame. |
@@ -504,25 +519,31 @@ config MTD_CEIVA | |||
504 | 519 | ||
505 | config MTD_NOR_TOTO | 520 | config MTD_NOR_TOTO |
506 | tristate "NOR Flash device on TOTO board" | 521 | tristate "NOR Flash device on TOTO board" |
507 | depends on ARM && ARCH_OMAP && OMAP_TOTO | 522 | depends on ARCH_OMAP && OMAP_TOTO |
508 | help | 523 | help |
509 | This enables access to the NOR flash on the Texas Instruments | 524 | This enables access to the NOR flash on the Texas Instruments |
510 | TOTO board. | 525 | TOTO board. |
511 | 526 | ||
512 | config MTD_H720X | 527 | config MTD_H720X |
513 | tristate "Hynix evaluation board mappings" | 528 | tristate "Hynix evaluation board mappings" |
514 | depends on ARM && MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) | 529 | depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) |
515 | help | 530 | help |
516 | This enables access to the flash chips on the Hynix evaluation boards. | 531 | This enables access to the flash chips on the Hynix evaluation boards. |
517 | If you have such a board, say 'Y'. | 532 | If you have such a board, say 'Y'. |
518 | 533 | ||
519 | config MTD_MPC1211 | 534 | config MTD_MPC1211 |
520 | tristate "CFI Flash device mapped on Interface MPC-1211" | 535 | tristate "CFI Flash device mapped on Interface MPC-1211" |
521 | depends on SUPERH && SH_MPC1211 && MTD_CFI | 536 | depends on SH_MPC1211 && MTD_CFI |
522 | help | 537 | help |
523 | This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02). | 538 | This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02). |
524 | If you have such a board, say 'Y'. | 539 | If you have such a board, say 'Y'. |
525 | 540 | ||
541 | config MTD_PQ2FADS | ||
542 | tristate "JEDEC flash SIMM mapped on PQ2FADS and 8272ADS boards" | ||
543 | depends on (ADS8272 || PQ2FADS) && MTD_PARTITIONS && MTD_JEDECPROBE && MTD_PHYSMAP && MTD_CFI_GEOMETRY && MTD_CFI_INTELEXT | ||
544 | help | ||
545 | This enables access to flash SIMM on PQ2FADS-like boards | ||
546 | |||
526 | config MTD_OMAP_NOR | 547 | config MTD_OMAP_NOR |
527 | tristate "TI OMAP board mappings" | 548 | tristate "TI OMAP board mappings" |
528 | depends on MTD_CFI && ARCH_OMAP | 549 | depends on MTD_CFI && ARCH_OMAP |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 7bcbc49e329f..7d9e940a1dcd 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # linux/drivers/maps/Makefile | 2 | # linux/drivers/maps/Makefile |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.30 2005/07/02 01:53:24 tpoynor Exp $ | 4 | # $Id: Makefile.common,v 1.34 2005/11/07 11:14:26 gleixner Exp $ |
5 | 5 | ||
6 | ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) | 6 | ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) |
7 | obj-$(CONFIG_MTD) += map_funcs.o | 7 | obj-$(CONFIG_MTD) += map_funcs.o |
@@ -26,7 +26,7 @@ obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o | |||
26 | obj-$(CONFIG_MTD_MBX860) += mbx860.o | 26 | obj-$(CONFIG_MTD_MBX860) += mbx860.o |
27 | obj-$(CONFIG_MTD_CEIVA) += ceiva.o | 27 | obj-$(CONFIG_MTD_CEIVA) += ceiva.o |
28 | obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o | 28 | obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o |
29 | obj-$(CONFIG_MTD_PHYSMAP) += physmap.o | 29 | obj-$(CONFIG_MTD_PHYSMAP) += physmap.o |
30 | obj-$(CONFIG_MTD_PNC2000) += pnc2000.o | 30 | obj-$(CONFIG_MTD_PNC2000) += pnc2000.o |
31 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o | 31 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o |
32 | obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o | 32 | obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o |
@@ -70,3 +70,6 @@ obj-$(CONFIG_MTD_DMV182) += dmv182.o | |||
70 | obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o | 70 | obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o |
71 | obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o | 71 | obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o |
72 | obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o | 72 | obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o |
73 | obj-$(CONFIG_MTD_PQ2FADS) += pq2fads.o | ||
74 | obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o | ||
75 | obj-$(CONFIG_MTD_TQM834x) += tqm834x.o | ||
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index 27fd2a3c3b60..a57791a6ce40 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on AMD Alchemy evaluation boards | 2 | * Flash memory access on AMD Alchemy evaluation boards |
3 | * | 3 | * |
4 | * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $ | 4 | * $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $ |
5 | * | 5 | * |
6 | * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com> | 6 | * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com> |
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
@@ -22,7 +22,7 @@ | |||
22 | #ifdef DEBUG_RW | 22 | #ifdef DEBUG_RW |
23 | #define DBG(x...) printk(x) | 23 | #define DBG(x...) printk(x) |
24 | #else | 24 | #else |
25 | #define DBG(x...) | 25 | #define DBG(x...) |
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #ifdef CONFIG_MIPS_PB1000 | 28 | #ifdef CONFIG_MIPS_PB1000 |
@@ -136,7 +136,7 @@ int __init alchemy_mtd_init(void) | |||
136 | int nb_parts = 0; | 136 | int nb_parts = 0; |
137 | unsigned long window_addr; | 137 | unsigned long window_addr; |
138 | unsigned long window_size; | 138 | unsigned long window_size; |
139 | 139 | ||
140 | /* Default flash buswidth */ | 140 | /* Default flash buswidth */ |
141 | alchemy_map.bankwidth = BOARD_FLASH_WIDTH; | 141 | alchemy_map.bankwidth = BOARD_FLASH_WIDTH; |
142 | 142 | ||
@@ -161,7 +161,7 @@ int __init alchemy_mtd_init(void) | |||
161 | * Now let's probe for the actual flash. Do it here since | 161 | * Now let's probe for the actual flash. Do it here since |
162 | * specific machine settings might have been set above. | 162 | * specific machine settings might have been set above. |
163 | */ | 163 | */ |
164 | printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", | 164 | printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", |
165 | alchemy_map.bankwidth*8); | 165 | alchemy_map.bankwidth*8); |
166 | alchemy_map.virt = ioremap(window_addr, window_size); | 166 | alchemy_map.virt = ioremap(window_addr, window_size); |
167 | mymtd = do_map_probe("cfi_probe", &alchemy_map); | 167 | mymtd = do_map_probe("cfi_probe", &alchemy_map); |
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index 9a64149f431d..c350878d4592 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * amd76xrom.c | 2 | * amd76xrom.c |
3 | * | 3 | * |
4 | * Normal mappings of chips in physical memory | 4 | * Normal mappings of chips in physical memory |
5 | * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $ | 5 | * $Id: amd76xrom.c,v 1.21 2005/11/07 11:14:26 gleixner Exp $ |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
@@ -70,7 +70,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window) | |||
70 | list_del(&map->list); | 70 | list_del(&map->list); |
71 | kfree(map); | 71 | kfree(map); |
72 | } | 72 | } |
73 | if (window->rsrc.parent) | 73 | if (window->rsrc.parent) |
74 | release_resource(&window->rsrc); | 74 | release_resource(&window->rsrc); |
75 | 75 | ||
76 | if (window->virt) { | 76 | if (window->virt) { |
@@ -107,7 +107,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
107 | window->phys = 0xffff0000; /* 64KiB */ | 107 | window->phys = 0xffff0000; /* 64KiB */ |
108 | } | 108 | } |
109 | window->size = 0xffffffffUL - window->phys + 1UL; | 109 | window->size = 0xffffffffUL - window->phys + 1UL; |
110 | 110 | ||
111 | /* | 111 | /* |
112 | * Try to reserve the window mem region. If this fails then | 112 | * Try to reserve the window mem region. If this fails then |
113 | * it is likely due to a fragment of the window being | 113 | * it is likely due to a fragment of the window being |
@@ -138,7 +138,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
138 | /* Enable writes through the rom window */ | 138 | /* Enable writes through the rom window */ |
139 | pci_read_config_byte(pdev, 0x40, &byte); | 139 | pci_read_config_byte(pdev, 0x40, &byte); |
140 | pci_write_config_byte(pdev, 0x40, byte | 1); | 140 | pci_write_config_byte(pdev, 0x40, byte | 1); |
141 | 141 | ||
142 | /* FIXME handle registers 0x80 - 0x8C the bios region locks */ | 142 | /* FIXME handle registers 0x80 - 0x8C the bios region locks */ |
143 | 143 | ||
144 | /* For write accesses caches are useless */ | 144 | /* For write accesses caches are useless */ |
@@ -186,7 +186,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
186 | MOD_NAME, map->map.phys); | 186 | MOD_NAME, map->map.phys); |
187 | 187 | ||
188 | /* There is no generic VPP support */ | 188 | /* There is no generic VPP support */ |
189 | for(map->map.bankwidth = 32; map->map.bankwidth; | 189 | for(map->map.bankwidth = 32; map->map.bankwidth; |
190 | map->map.bankwidth >>= 1) | 190 | map->map.bankwidth >>= 1) |
191 | { | 191 | { |
192 | char **probe_type; | 192 | char **probe_type; |
@@ -239,7 +239,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, | |||
239 | for(i = 0; i < cfi->numchips; i++) { | 239 | for(i = 0; i < cfi->numchips; i++) { |
240 | cfi->chips[i].start += offset; | 240 | cfi->chips[i].start += offset; |
241 | } | 241 | } |
242 | 242 | ||
243 | /* Now that the mtd devices is complete claim and export it */ | 243 | /* Now that the mtd devices is complete claim and export it */ |
244 | map->mtd->owner = THIS_MODULE; | 244 | map->mtd->owner = THIS_MODULE; |
245 | if (add_mtd_device(map->mtd)) { | 245 | if (add_mtd_device(map->mtd)) { |
@@ -277,9 +277,9 @@ static void __devexit amd76xrom_remove_one (struct pci_dev *pdev) | |||
277 | } | 277 | } |
278 | 278 | ||
279 | static struct pci_device_id amd76xrom_pci_tbl[] = { | 279 | static struct pci_device_id amd76xrom_pci_tbl[] = { |
280 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, | 280 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, |
281 | PCI_ANY_ID, PCI_ANY_ID, }, | 281 | PCI_ANY_ID, PCI_ANY_ID, }, |
282 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, | 282 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, |
283 | PCI_ANY_ID, PCI_ANY_ID, }, | 283 | PCI_ANY_ID, PCI_ANY_ID, }, |
284 | { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */ | 284 | { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */ |
285 | { 0, } | 285 | { 0, } |
diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c index 777276fd0e15..d95ae582fbe9 100644 --- a/drivers/mtd/maps/arctic-mtd.c +++ b/drivers/mtd/maps/arctic-mtd.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: arctic-mtd.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: arctic-mtd.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for | 4 | * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for |
5 | * IBM 405LP Arctic boards. | 5 | * IBM 405LP Arctic boards. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index cf362ccc3c8e..7ed3424dd959 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * NV-RAM memory access on autcpu12 | 2 | * NV-RAM memory access on autcpu12 |
3 | * (C) 2002 Thomas Gleixner (gleixner@autronix.de) | 3 | * (C) 2002 Thomas Gleixner (gleixner@autronix.de) |
4 | * | 4 | * |
5 | * $Id: autcpu12-nvram.c,v 1.8 2004/11/04 13:24:14 gleixner Exp $ | 5 | * $Id: autcpu12-nvram.c,v 1.9 2005/11/07 11:14:26 gleixner Exp $ |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -55,10 +55,10 @@ static int __init init_autcpu12_sram (void) | |||
55 | } | 55 | } |
56 | simple_map_init(&autcpu_sram_map); | 56 | simple_map_init(&autcpu_sram_map); |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Check for 32K/128K | 59 | * Check for 32K/128K |
60 | * read ofs 0 | 60 | * read ofs 0 |
61 | * read ofs 0x10000 | 61 | * read ofs 0x10000 |
62 | * Write complement to ofs 0x100000 | 62 | * Write complement to ofs 0x100000 |
63 | * Read and check result on ofs 0x0 | 63 | * Read and check result on ofs 0x0 |
64 | * Restore contents | 64 | * Restore contents |
@@ -66,7 +66,7 @@ static int __init init_autcpu12_sram (void) | |||
66 | save0 = map_read32(&autcpu12_sram_map,0); | 66 | save0 = map_read32(&autcpu12_sram_map,0); |
67 | save1 = map_read32(&autcpu12_sram_map,0x10000); | 67 | save1 = map_read32(&autcpu12_sram_map,0x10000); |
68 | map_write32(&autcpu12_sram_map,~save0,0x10000); | 68 | map_write32(&autcpu12_sram_map,~save0,0x10000); |
69 | /* if we find this pattern on 0x0, we have 32K size | 69 | /* if we find this pattern on 0x0, we have 32K size |
70 | * restore contents and exit | 70 | * restore contents and exit |
71 | */ | 71 | */ |
72 | if ( map_read32(&autcpu12_sram_map,0) != save0) { | 72 | if ( map_read32(&autcpu12_sram_map,0) != save0) { |
@@ -89,7 +89,7 @@ map: | |||
89 | 89 | ||
90 | sram_mtd->owner = THIS_MODULE; | 90 | sram_mtd->owner = THIS_MODULE; |
91 | sram_mtd->erasesize = 16; | 91 | sram_mtd->erasesize = 16; |
92 | 92 | ||
93 | if (add_mtd_device(sram_mtd)) { | 93 | if (add_mtd_device(sram_mtd)) { |
94 | printk("NV-RAM device addition failed\n"); | 94 | printk("NV-RAM device addition failed\n"); |
95 | err = -ENOMEM; | 95 | err = -ENOMEM; |
@@ -97,7 +97,7 @@ map: | |||
97 | } | 97 | } |
98 | 98 | ||
99 | printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); | 99 | printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); |
100 | 100 | ||
101 | return 0; | 101 | return 0; |
102 | 102 | ||
103 | out_probe: | 103 | out_probe: |
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index 8c19d722ac79..b7858eb93534 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * 20-Sep-2004 BJD Initial version | 9 | * 20-Sep-2004 BJD Initial version |
10 | * 17-Jan-2005 BJD Add whole device if no partitions found | 10 | * 17-Jan-2005 BJD Add whole device if no partitions found |
11 | * | 11 | * |
12 | * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $ | 12 | * $Id: bast-flash.c,v 1.5 2005/11/07 11:14:26 gleixner Exp $ |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
@@ -75,7 +75,7 @@ static void bast_flash_setrw(int to) | |||
75 | 75 | ||
76 | local_irq_save(flags); | 76 | local_irq_save(flags); |
77 | val = __raw_readb(BAST_VA_CTRL3); | 77 | val = __raw_readb(BAST_VA_CTRL3); |
78 | 78 | ||
79 | if (to) | 79 | if (to) |
80 | val |= BAST_CPLD_CTRL3_ROMWEN; | 80 | val |= BAST_CPLD_CTRL3_ROMWEN; |
81 | else | 81 | else |
@@ -93,7 +93,7 @@ static int bast_flash_remove(struct device *dev) | |||
93 | 93 | ||
94 | dev_set_drvdata(dev, NULL); | 94 | dev_set_drvdata(dev, NULL); |
95 | 95 | ||
96 | if (info == NULL) | 96 | if (info == NULL) |
97 | return 0; | 97 | return 0; |
98 | 98 | ||
99 | if (info->map.virt != NULL) | 99 | if (info->map.virt != NULL) |
@@ -110,7 +110,7 @@ static int bast_flash_remove(struct device *dev) | |||
110 | release_resource(info->area); | 110 | release_resource(info->area); |
111 | kfree(info->area); | 111 | kfree(info->area); |
112 | } | 112 | } |
113 | 113 | ||
114 | kfree(info); | 114 | kfree(info); |
115 | 115 | ||
116 | return 0; | 116 | return 0; |
@@ -137,15 +137,15 @@ static int bast_flash_probe(struct device *dev) | |||
137 | 137 | ||
138 | info->map.phys = res->start; | 138 | info->map.phys = res->start; |
139 | info->map.size = res->end - res->start + 1; | 139 | info->map.size = res->end - res->start + 1; |
140 | info->map.name = dev->bus_id; | 140 | info->map.name = dev->bus_id; |
141 | info->map.bankwidth = 2; | 141 | info->map.bankwidth = 2; |
142 | 142 | ||
143 | if (info->map.size > AREA_MAXSIZE) | 143 | if (info->map.size > AREA_MAXSIZE) |
144 | info->map.size = AREA_MAXSIZE; | 144 | info->map.size = AREA_MAXSIZE; |
145 | 145 | ||
146 | pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__, | 146 | pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__, |
147 | info->map.phys, info->map.size); | 147 | info->map.phys, info->map.size); |
148 | 148 | ||
149 | info->area = request_mem_region(res->start, info->map.size, | 149 | info->area = request_mem_region(res->start, info->map.size, |
150 | pdev->name); | 150 | pdev->name); |
151 | if (info->area == NULL) { | 151 | if (info->area == NULL) { |
@@ -162,7 +162,7 @@ static int bast_flash_probe(struct device *dev) | |||
162 | err = -EIO; | 162 | err = -EIO; |
163 | goto exit_error; | 163 | goto exit_error; |
164 | } | 164 | } |
165 | 165 | ||
166 | simple_map_init(&info->map); | 166 | simple_map_init(&info->map); |
167 | 167 | ||
168 | /* enable the write to the flash area */ | 168 | /* enable the write to the flash area */ |
@@ -187,7 +187,7 @@ static int bast_flash_probe(struct device *dev) | |||
187 | err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); | 187 | err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); |
188 | if (err > 0) { | 188 | if (err > 0) { |
189 | err = add_mtd_partitions(info->mtd, info->partitions, err); | 189 | err = add_mtd_partitions(info->mtd, info->partitions, err); |
190 | if (err) | 190 | if (err) |
191 | printk(KERN_ERR PFX "cannot add/parse partitions\n"); | 191 | printk(KERN_ERR PFX "cannot add/parse partitions\n"); |
192 | } else { | 192 | } else { |
193 | err = add_mtd_device(info->mtd); | 193 | err = add_mtd_device(info->mtd); |
@@ -205,6 +205,7 @@ static int bast_flash_probe(struct device *dev) | |||
205 | 205 | ||
206 | static struct device_driver bast_flash_driver = { | 206 | static struct device_driver bast_flash_driver = { |
207 | .name = "bast-nor", | 207 | .name = "bast-nor", |
208 | .owner = THIS_MODULE, | ||
208 | .bus = &platform_bus_type, | 209 | .bus = &platform_bus_type, |
209 | .probe = bast_flash_probe, | 210 | .probe = bast_flash_probe, |
210 | .remove = bast_flash_remove, | 211 | .remove = bast_flash_remove, |
diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c index 5e79c9d5da2b..5df7361d1407 100644 --- a/drivers/mtd/maps/beech-mtd.c +++ b/drivers/mtd/maps/beech-mtd.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: beech-mtd.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: beech-mtd.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for | 4 | * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for |
5 | * IBM 405LP Beech boards. | 5 | * IBM 405LP Beech boards. |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
diff --git a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c index ab15dac2f936..9f17bb6c5a9d 100644 --- a/drivers/mtd/maps/cdb89712.c +++ b/drivers/mtd/maps/cdb89712.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Flash on Cirrus CDB89712 | 2 | * Flash on Cirrus CDB89712 |
3 | * | 3 | * |
4 | * $Id: cdb89712.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $ | 4 | * $Id: cdb89712.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $ |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
@@ -37,13 +37,13 @@ struct resource cdb89712_flash_resource = { | |||
37 | static int __init init_cdb89712_flash (void) | 37 | static int __init init_cdb89712_flash (void) |
38 | { | 38 | { |
39 | int err; | 39 | int err; |
40 | 40 | ||
41 | if (request_resource (&ioport_resource, &cdb89712_flash_resource)) { | 41 | if (request_resource (&ioport_resource, &cdb89712_flash_resource)) { |
42 | printk(KERN_NOTICE "Failed to reserve Cdb89712 FLASH space\n"); | 42 | printk(KERN_NOTICE "Failed to reserve Cdb89712 FLASH space\n"); |
43 | err = -EBUSY; | 43 | err = -EBUSY; |
44 | goto out; | 44 | goto out; |
45 | } | 45 | } |
46 | 46 | ||
47 | cdb89712_flash_map.virt = ioremap(FLASH_START, FLASH_SIZE); | 47 | cdb89712_flash_map.virt = ioremap(FLASH_START, FLASH_SIZE); |
48 | if (!cdb89712_flash_map.virt) { | 48 | if (!cdb89712_flash_map.virt) { |
49 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); | 49 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); |
@@ -64,13 +64,13 @@ static int __init init_cdb89712_flash (void) | |||
64 | } | 64 | } |
65 | 65 | ||
66 | flash_mtd->owner = THIS_MODULE; | 66 | flash_mtd->owner = THIS_MODULE; |
67 | 67 | ||
68 | if (add_mtd_device(flash_mtd)) { | 68 | if (add_mtd_device(flash_mtd)) { |
69 | printk("FLASH device addition failed\n"); | 69 | printk("FLASH device addition failed\n"); |
70 | err = -ENOMEM; | 70 | err = -ENOMEM; |
71 | goto out_probe; | 71 | goto out_probe; |
72 | } | 72 | } |
73 | 73 | ||
74 | return 0; | 74 | return 0; |
75 | 75 | ||
76 | out_probe: | 76 | out_probe: |
@@ -107,13 +107,13 @@ struct resource cdb89712_sram_resource = { | |||
107 | static int __init init_cdb89712_sram (void) | 107 | static int __init init_cdb89712_sram (void) |
108 | { | 108 | { |
109 | int err; | 109 | int err; |
110 | 110 | ||
111 | if (request_resource (&ioport_resource, &cdb89712_sram_resource)) { | 111 | if (request_resource (&ioport_resource, &cdb89712_sram_resource)) { |
112 | printk(KERN_NOTICE "Failed to reserve Cdb89712 SRAM space\n"); | 112 | printk(KERN_NOTICE "Failed to reserve Cdb89712 SRAM space\n"); |
113 | err = -EBUSY; | 113 | err = -EBUSY; |
114 | goto out; | 114 | goto out; |
115 | } | 115 | } |
116 | 116 | ||
117 | cdb89712_sram_map.virt = ioremap(SRAM_START, SRAM_SIZE); | 117 | cdb89712_sram_map.virt = ioremap(SRAM_START, SRAM_SIZE); |
118 | if (!cdb89712_sram_map.virt) { | 118 | if (!cdb89712_sram_map.virt) { |
119 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); | 119 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); |
@@ -130,13 +130,13 @@ static int __init init_cdb89712_sram (void) | |||
130 | 130 | ||
131 | sram_mtd->owner = THIS_MODULE; | 131 | sram_mtd->owner = THIS_MODULE; |
132 | sram_mtd->erasesize = 16; | 132 | sram_mtd->erasesize = 16; |
133 | 133 | ||
134 | if (add_mtd_device(sram_mtd)) { | 134 | if (add_mtd_device(sram_mtd)) { |
135 | printk("SRAM device addition failed\n"); | 135 | printk("SRAM device addition failed\n"); |
136 | err = -ENOMEM; | 136 | err = -ENOMEM; |
137 | goto out_probe; | 137 | goto out_probe; |
138 | } | 138 | } |
139 | 139 | ||
140 | return 0; | 140 | return 0; |
141 | 141 | ||
142 | out_probe: | 142 | out_probe: |
@@ -175,13 +175,13 @@ struct resource cdb89712_bootrom_resource = { | |||
175 | static int __init init_cdb89712_bootrom (void) | 175 | static int __init init_cdb89712_bootrom (void) |
176 | { | 176 | { |
177 | int err; | 177 | int err; |
178 | 178 | ||
179 | if (request_resource (&ioport_resource, &cdb89712_bootrom_resource)) { | 179 | if (request_resource (&ioport_resource, &cdb89712_bootrom_resource)) { |
180 | printk(KERN_NOTICE "Failed to reserve Cdb89712 BOOTROM space\n"); | 180 | printk(KERN_NOTICE "Failed to reserve Cdb89712 BOOTROM space\n"); |
181 | err = -EBUSY; | 181 | err = -EBUSY; |
182 | goto out; | 182 | goto out; |
183 | } | 183 | } |
184 | 184 | ||
185 | cdb89712_bootrom_map.virt = ioremap(BOOTROM_START, BOOTROM_SIZE); | 185 | cdb89712_bootrom_map.virt = ioremap(BOOTROM_START, BOOTROM_SIZE); |
186 | if (!cdb89712_bootrom_map.virt) { | 186 | if (!cdb89712_bootrom_map.virt) { |
187 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); | 187 | printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); |
@@ -198,13 +198,13 @@ static int __init init_cdb89712_bootrom (void) | |||
198 | 198 | ||
199 | bootrom_mtd->owner = THIS_MODULE; | 199 | bootrom_mtd->owner = THIS_MODULE; |
200 | bootrom_mtd->erasesize = 0x10000; | 200 | bootrom_mtd->erasesize = 0x10000; |
201 | 201 | ||
202 | if (add_mtd_device(bootrom_mtd)) { | 202 | if (add_mtd_device(bootrom_mtd)) { |
203 | printk("BootROM device addition failed\n"); | 203 | printk("BootROM device addition failed\n"); |
204 | err = -ENOMEM; | 204 | err = -ENOMEM; |
205 | goto out_probe; | 205 | goto out_probe; |
206 | } | 206 | } |
207 | 207 | ||
208 | return 0; | 208 | return 0; |
209 | 209 | ||
210 | out_probe: | 210 | out_probe: |
@@ -225,16 +225,16 @@ out: | |||
225 | static int __init init_cdb89712_maps(void) | 225 | static int __init init_cdb89712_maps(void) |
226 | { | 226 | { |
227 | 227 | ||
228 | printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n Flash 0x%x at 0x%x\n SRAM 0x%x at 0x%x\n BootROM 0x%x at 0x%x\n", | 228 | printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n Flash 0x%x at 0x%x\n SRAM 0x%x at 0x%x\n BootROM 0x%x at 0x%x\n", |
229 | FLASH_SIZE, FLASH_START, SRAM_SIZE, SRAM_START, BOOTROM_SIZE, BOOTROM_START); | 229 | FLASH_SIZE, FLASH_START, SRAM_SIZE, SRAM_START, BOOTROM_SIZE, BOOTROM_START); |
230 | 230 | ||
231 | init_cdb89712_flash(); | 231 | init_cdb89712_flash(); |
232 | init_cdb89712_sram(); | 232 | init_cdb89712_sram(); |
233 | init_cdb89712_bootrom(); | 233 | init_cdb89712_bootrom(); |
234 | 234 | ||
235 | return 0; | 235 | return 0; |
236 | } | 236 | } |
237 | 237 | ||
238 | 238 | ||
239 | static void __exit cleanup_cdb89712_maps(void) | 239 | static void __exit cleanup_cdb89712_maps(void) |
240 | { | 240 | { |
@@ -244,7 +244,7 @@ static void __exit cleanup_cdb89712_maps(void) | |||
244 | iounmap((void *)cdb89712_sram_map.virt); | 244 | iounmap((void *)cdb89712_sram_map.virt); |
245 | release_resource (&cdb89712_sram_resource); | 245 | release_resource (&cdb89712_sram_resource); |
246 | } | 246 | } |
247 | 247 | ||
248 | if (flash_mtd) { | 248 | if (flash_mtd) { |
249 | del_mtd_device(flash_mtd); | 249 | del_mtd_device(flash_mtd); |
250 | map_destroy(flash_mtd); | 250 | map_destroy(flash_mtd); |
diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index f72e4f894b32..6a8c0415bde8 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is> | 2 | * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is> |
3 | * | 3 | * |
4 | * $Id: cfi_flagadm.c,v 1.14 2004/11/04 13:24:14 gleixner Exp $ | 4 | * $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 gleixner Exp $ |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
8 | * Free Software Foundation; either version 2 of the License, or (at your | 8 | * Free Software Foundation; either version 2 of the License, or (at your |
@@ -42,7 +42,7 @@ | |||
42 | */ | 42 | */ |
43 | 43 | ||
44 | #define FLASH_PHYS_ADDR 0x40000000 | 44 | #define FLASH_PHYS_ADDR 0x40000000 |
45 | #define FLASH_SIZE 0x400000 | 45 | #define FLASH_SIZE 0x400000 |
46 | 46 | ||
47 | #define FLASH_PARTITION0_ADDR 0x00000000 | 47 | #define FLASH_PARTITION0_ADDR 0x00000000 |
48 | #define FLASH_PARTITION0_SIZE 0x00020000 | 48 | #define FLASH_PARTITION0_SIZE 0x00020000 |
@@ -79,7 +79,7 @@ struct mtd_partition flagadm_parts[] = { | |||
79 | .offset = FLASH_PARTITION2_ADDR, | 79 | .offset = FLASH_PARTITION2_ADDR, |
80 | .size = FLASH_PARTITION2_SIZE | 80 | .size = FLASH_PARTITION2_SIZE |
81 | }, | 81 | }, |
82 | { | 82 | { |
83 | .name = "Persistant storage", | 83 | .name = "Persistant storage", |
84 | .offset = FLASH_PARTITION3_ADDR, | 84 | .offset = FLASH_PARTITION3_ADDR, |
85 | .size = FLASH_PARTITION3_SIZE | 85 | .size = FLASH_PARTITION3_SIZE |
@@ -91,10 +91,10 @@ struct mtd_partition flagadm_parts[] = { | |||
91 | static struct mtd_info *mymtd; | 91 | static struct mtd_info *mymtd; |
92 | 92 | ||
93 | int __init init_flagadm(void) | 93 | int __init init_flagadm(void) |
94 | { | 94 | { |
95 | printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", | 95 | printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", |
96 | FLASH_SIZE, FLASH_PHYS_ADDR); | 96 | FLASH_SIZE, FLASH_PHYS_ADDR); |
97 | 97 | ||
98 | flagadm_map.phys = FLASH_PHYS_ADDR; | 98 | flagadm_map.phys = FLASH_PHYS_ADDR; |
99 | flagadm_map.virt = ioremap(FLASH_PHYS_ADDR, | 99 | flagadm_map.virt = ioremap(FLASH_PHYS_ADDR, |
100 | FLASH_SIZE); | 100 | FLASH_SIZE); |
diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c index ae9252fbf176..a370953c1513 100644 --- a/drivers/mtd/maps/cstm_mips_ixx.c +++ b/drivers/mtd/maps/cstm_mips_ixx.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: cstm_mips_ixx.c,v 1.12 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: cstm_mips_ixx.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. | 4 | * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. |
5 | * Config with both CFI and JEDEC device support. | 5 | * Config with both CFI and JEDEC device support. |
6 | * | 6 | * |
7 | * Basically physmap.c with the addition of partitions and | 7 | * Basically physmap.c with the addition of partitions and |
8 | * an array of mapping info to accomodate more than one flash type per board. | 8 | * an array of mapping info to accomodate more than one flash type per board. |
9 | * | 9 | * |
10 | * Copyright 2000 MontaVista Software Inc. | 10 | * Copyright 2000 MontaVista Software Inc. |
@@ -69,7 +69,7 @@ void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) | |||
69 | __u16 data; | 69 | __u16 data; |
70 | __u8 data1; | 70 | __u8 data1; |
71 | static u8 first = 1; | 71 | static u8 first = 1; |
72 | 72 | ||
73 | // Set GPIO port B pin3 to high | 73 | // Set GPIO port B pin3 to high |
74 | data = *(__u16 *)(CC_GPBCR); | 74 | data = *(__u16 *)(CC_GPBCR); |
75 | data = (data & 0xff0f) | 0x0040; | 75 | data = (data & 0xff0f) | 0x0040; |
@@ -85,7 +85,7 @@ void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) | |||
85 | } else { | 85 | } else { |
86 | if (!--vpp_count) { | 86 | if (!--vpp_count) { |
87 | __u16 data; | 87 | __u16 data; |
88 | 88 | ||
89 | // Set GPIO port B pin3 to high | 89 | // Set GPIO port B pin3 to high |
90 | data = *(__u16 *)(CC_GPBCR); | 90 | data = *(__u16 *)(CC_GPBCR); |
91 | data = (data & 0xff3f) | 0x0040; | 91 | data = (data & 0xff3f) | 0x0040; |
@@ -109,8 +109,8 @@ struct cstm_mips_ixx_info { | |||
109 | }; | 109 | }; |
110 | 110 | ||
111 | #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) | 111 | #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) |
112 | #define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type | 112 | #define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type |
113 | const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = | 113 | const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = |
114 | { | 114 | { |
115 | { // 28F128J3A in 2x16 configuration | 115 | { // 28F128J3A in 2x16 configuration |
116 | "big flash", // name | 116 | "big flash", // name |
@@ -131,10 +131,10 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP | |||
131 | }, | 131 | }, |
132 | }; | 132 | }; |
133 | #else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ | 133 | #else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ |
134 | #define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type | 134 | #define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type |
135 | const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = | 135 | const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = |
136 | { | 136 | { |
137 | { | 137 | { |
138 | "MTD flash", // name | 138 | "MTD flash", // name |
139 | CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr | 139 | CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr |
140 | CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size | 140 | CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size |
@@ -144,7 +144,7 @@ const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = | |||
144 | 144 | ||
145 | }; | 145 | }; |
146 | static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { | 146 | static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { |
147 | { | 147 | { |
148 | { | 148 | { |
149 | .name = "main partition", | 149 | .name = "main partition", |
150 | .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, | 150 | .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, |
@@ -165,7 +165,7 @@ int __init init_cstm_mips_ixx(void) | |||
165 | 165 | ||
166 | /* Initialize mapping */ | 166 | /* Initialize mapping */ |
167 | for (i=0;i<PHYSMAP_NUMBER;i++) { | 167 | for (i=0;i<PHYSMAP_NUMBER;i++) { |
168 | printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", | 168 | printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", |
169 | cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); | 169 | cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); |
170 | 170 | ||
171 | 171 | ||
@@ -235,7 +235,7 @@ void PCISetULongByOffset(__u32 DevNumber, __u32 FuncNumber, __u32 Offset, __u32 | |||
235 | 235 | ||
236 | offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ; | 236 | offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ; |
237 | 237 | ||
238 | *(__u32 *)CC_CONFADDR = offset; | 238 | *(__u32 *)CC_CONFADDR = offset; |
239 | *(__u32 *)CC_CONFDATA = data; | 239 | *(__u32 *)CC_CONFDATA = data; |
240 | } | 240 | } |
241 | void setup_ITE_IVR_flash() | 241 | void setup_ITE_IVR_flash() |
diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index d850a27a4b59..49d90542fc75 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: dbox2-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: dbox2-flash.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * D-Box 2 flash driver | 4 | * D-Box 2 flash driver |
5 | */ | 5 | */ |
@@ -21,38 +21,38 @@ | |||
21 | static struct mtd_partition partition_info[]= { | 21 | static struct mtd_partition partition_info[]= { |
22 | { | 22 | { |
23 | .name = "BR bootloader", | 23 | .name = "BR bootloader", |
24 | .size = 128 * 1024, | 24 | .size = 128 * 1024, |
25 | .offset = 0, | 25 | .offset = 0, |
26 | .mask_flags = MTD_WRITEABLE | 26 | .mask_flags = MTD_WRITEABLE |
27 | }, | 27 | }, |
28 | { | 28 | { |
29 | .name = "FLFS (U-Boot)", | 29 | .name = "FLFS (U-Boot)", |
30 | .size = 128 * 1024, | 30 | .size = 128 * 1024, |
31 | .offset = MTDPART_OFS_APPEND, | 31 | .offset = MTDPART_OFS_APPEND, |
32 | .mask_flags = 0 | 32 | .mask_flags = 0 |
33 | }, | 33 | }, |
34 | { | 34 | { |
35 | .name = "Root (SquashFS)", | 35 | .name = "Root (SquashFS)", |
36 | .size = 7040 * 1024, | 36 | .size = 7040 * 1024, |
37 | .offset = MTDPART_OFS_APPEND, | 37 | .offset = MTDPART_OFS_APPEND, |
38 | .mask_flags = 0 | 38 | .mask_flags = 0 |
39 | }, | 39 | }, |
40 | { | 40 | { |
41 | .name = "var (JFFS2)", | 41 | .name = "var (JFFS2)", |
42 | .size = 896 * 1024, | 42 | .size = 896 * 1024, |
43 | .offset = MTDPART_OFS_APPEND, | 43 | .offset = MTDPART_OFS_APPEND, |
44 | .mask_flags = 0 | 44 | .mask_flags = 0 |
45 | }, | 45 | }, |
46 | { | 46 | { |
47 | .name = "Flash without bootloader", | 47 | .name = "Flash without bootloader", |
48 | .size = MTDPART_SIZ_FULL, | 48 | .size = MTDPART_SIZ_FULL, |
49 | .offset = 128 * 1024, | 49 | .offset = 128 * 1024, |
50 | .mask_flags = 0 | 50 | .mask_flags = 0 |
51 | }, | 51 | }, |
52 | { | 52 | { |
53 | .name = "Complete Flash", | 53 | .name = "Complete Flash", |
54 | .size = MTDPART_SIZ_FULL, | 54 | .size = MTDPART_SIZ_FULL, |
55 | .offset = 0, | 55 | .offset = 0, |
56 | .mask_flags = MTD_WRITEABLE | 56 | .mask_flags = MTD_WRITEABLE |
57 | } | 57 | } |
58 | }; | 58 | }; |
@@ -88,16 +88,16 @@ int __init init_dbox2_flash(void) | |||
88 | if (!mymtd) { | 88 | if (!mymtd) { |
89 | // Probe for single Intel 28F640 | 89 | // Probe for single Intel 28F640 |
90 | dbox2_flash_map.bankwidth = 2; | 90 | dbox2_flash_map.bankwidth = 2; |
91 | 91 | ||
92 | mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); | 92 | mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); |
93 | } | 93 | } |
94 | 94 | ||
95 | if (mymtd) { | 95 | if (mymtd) { |
96 | mymtd->owner = THIS_MODULE; | 96 | mymtd->owner = THIS_MODULE; |
97 | 97 | ||
98 | /* Create MTD devices for each partition. */ | 98 | /* Create MTD devices for each partition. */ |
99 | add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); | 99 | add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); |
100 | 100 | ||
101 | return 0; | 101 | return 0; |
102 | } | 102 | } |
103 | 103 | ||
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index e5b74169fde6..701620b6baed 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c | |||
@@ -4,8 +4,8 @@ | |||
4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
5 | * | 5 | * |
6 | * This code is GPL | 6 | * This code is GPL |
7 | * | 7 | * |
8 | * $Id: dc21285.c,v 1.22 2004/11/01 13:39:21 rmk Exp $ | 8 | * $Id: dc21285.c,v 1.24 2005/11/07 11:14:26 gleixner Exp $ |
9 | */ | 9 | */ |
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
@@ -27,9 +27,9 @@ | |||
27 | static struct mtd_info *dc21285_mtd; | 27 | static struct mtd_info *dc21285_mtd; |
28 | 28 | ||
29 | #ifdef CONFIG_ARCH_NETWINDER | 29 | #ifdef CONFIG_ARCH_NETWINDER |
30 | /* | 30 | /* |
31 | * This is really ugly, but it seams to be the only | 31 | * This is really ugly, but it seams to be the only |
32 | * realiable way to do it, as the cpld state machine | 32 | * realiable way to do it, as the cpld state machine |
33 | * is unpredictible. So we have a 25us penalty per | 33 | * is unpredictible. So we have a 25us penalty per |
34 | * write access. | 34 | * write access. |
35 | */ | 35 | */ |
@@ -150,7 +150,7 @@ static struct map_info dc21285_map = { | |||
150 | static struct mtd_partition *dc21285_parts; | 150 | static struct mtd_partition *dc21285_parts; |
151 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; | 151 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; |
152 | #endif | 152 | #endif |
153 | 153 | ||
154 | static int __init init_dc21285(void) | 154 | static int __init init_dc21285(void) |
155 | { | 155 | { |
156 | 156 | ||
@@ -160,20 +160,20 @@ static int __init init_dc21285(void) | |||
160 | 160 | ||
161 | /* Determine bankwidth */ | 161 | /* Determine bankwidth */ |
162 | switch (*CSR_SA110_CNTL & (3<<14)) { | 162 | switch (*CSR_SA110_CNTL & (3<<14)) { |
163 | case SA110_CNTL_ROMWIDTH_8: | 163 | case SA110_CNTL_ROMWIDTH_8: |
164 | dc21285_map.bankwidth = 1; | 164 | dc21285_map.bankwidth = 1; |
165 | dc21285_map.read = dc21285_read8; | 165 | dc21285_map.read = dc21285_read8; |
166 | dc21285_map.write = dc21285_write8; | 166 | dc21285_map.write = dc21285_write8; |
167 | dc21285_map.copy_to = dc21285_copy_to_8; | 167 | dc21285_map.copy_to = dc21285_copy_to_8; |
168 | break; | 168 | break; |
169 | case SA110_CNTL_ROMWIDTH_16: | 169 | case SA110_CNTL_ROMWIDTH_16: |
170 | dc21285_map.bankwidth = 2; | 170 | dc21285_map.bankwidth = 2; |
171 | dc21285_map.read = dc21285_read16; | 171 | dc21285_map.read = dc21285_read16; |
172 | dc21285_map.write = dc21285_write16; | 172 | dc21285_map.write = dc21285_write16; |
173 | dc21285_map.copy_to = dc21285_copy_to_16; | 173 | dc21285_map.copy_to = dc21285_copy_to_16; |
174 | break; | 174 | break; |
175 | case SA110_CNTL_ROMWIDTH_32: | 175 | case SA110_CNTL_ROMWIDTH_32: |
176 | dc21285_map.bankwidth = 4; | 176 | dc21285_map.bankwidth = 4; |
177 | dc21285_map.read = dc21285_read32; | 177 | dc21285_map.read = dc21285_read32; |
178 | dc21285_map.write = dc21285_write32; | 178 | dc21285_map.write = dc21285_write32; |
179 | dc21285_map.copy_to = dc21285_copy_to_32; | 179 | dc21285_map.copy_to = dc21285_copy_to_32; |
@@ -201,20 +201,20 @@ static int __init init_dc21285(void) | |||
201 | if (!dc21285_mtd) { | 201 | if (!dc21285_mtd) { |
202 | iounmap(dc21285_map.virt); | 202 | iounmap(dc21285_map.virt); |
203 | return -ENXIO; | 203 | return -ENXIO; |
204 | } | 204 | } |
205 | 205 | ||
206 | dc21285_mtd->owner = THIS_MODULE; | 206 | dc21285_mtd->owner = THIS_MODULE; |
207 | 207 | ||
208 | #ifdef CONFIG_MTD_PARTITIONS | 208 | #ifdef CONFIG_MTD_PARTITIONS |
209 | nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); | 209 | nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); |
210 | if (nrparts > 0) | 210 | if (nrparts > 0) |
211 | add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts); | 211 | add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts); |
212 | else | 212 | else |
213 | #endif | 213 | #endif |
214 | add_mtd_device(dc21285_mtd); | 214 | add_mtd_device(dc21285_mtd); |
215 | 215 | ||
216 | if(machine_is_ebsa285()) { | 216 | if(machine_is_ebsa285()) { |
217 | /* | 217 | /* |
218 | * Flash timing is determined with bits 19-16 of the | 218 | * Flash timing is determined with bits 19-16 of the |
219 | * CSR_SA110_CNTL. The value is the number of wait cycles, or | 219 | * CSR_SA110_CNTL. The value is the number of wait cycles, or |
220 | * 0 for 16 cycles (the default). Cycles are 20 ns. | 220 | * 0 for 16 cycles (the default). Cycles are 20 ns. |
@@ -227,7 +227,7 @@ static int __init init_dc21285(void) | |||
227 | /* tristate time */ | 227 | /* tristate time */ |
228 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); | 228 | *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); |
229 | } | 229 | } |
230 | 230 | ||
231 | return 0; | 231 | return 0; |
232 | } | 232 | } |
233 | 233 | ||
diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index f99519692cb7..b51c757817d8 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c | |||
@@ -14,7 +14,7 @@ | |||
14 | * along with this program; if not, write to the Free Software | 14 | * along with this program; if not, write to the Free Software |
15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
16 | * | 16 | * |
17 | * $Id: dilnetpc.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $ | 17 | * $Id: dilnetpc.c,v 1.20 2005/11/07 11:14:26 gleixner Exp $ |
18 | * | 18 | * |
19 | * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems | 19 | * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems |
20 | * featuring the AMD Elan SC410 processor. There are two variants of this | 20 | * featuring the AMD Elan SC410 processor. There are two variants of this |
@@ -272,13 +272,13 @@ static struct map_info dnpc_map = { | |||
272 | 272 | ||
273 | static struct mtd_partition partition_info[]= | 273 | static struct mtd_partition partition_info[]= |
274 | { | 274 | { |
275 | { | 275 | { |
276 | .name = "ADNP boot", | 276 | .name = "ADNP boot", |
277 | .offset = 0, | 277 | .offset = 0, |
278 | .size = 0xf0000, | 278 | .size = 0xf0000, |
279 | }, | 279 | }, |
280 | { | 280 | { |
281 | .name = "ADNP system BIOS", | 281 | .name = "ADNP system BIOS", |
282 | .offset = MTDPART_OFS_NXTBLK, | 282 | .offset = MTDPART_OFS_NXTBLK, |
283 | .size = 0x10000, | 283 | .size = 0x10000, |
284 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED | 284 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED |
@@ -291,7 +291,7 @@ static struct mtd_partition partition_info[]= | |||
291 | .size = 0x2f0000, | 291 | .size = 0x2f0000, |
292 | }, | 292 | }, |
293 | { | 293 | { |
294 | .name = "ADNP system BIOS entry", | 294 | .name = "ADNP system BIOS entry", |
295 | .offset = MTDPART_OFS_NXTBLK, | 295 | .offset = MTDPART_OFS_NXTBLK, |
296 | .size = MTDPART_SIZ_FULL, | 296 | .size = MTDPART_SIZ_FULL, |
297 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED | 297 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED |
@@ -325,9 +325,9 @@ static struct mtd_info *merged_mtd; | |||
325 | 325 | ||
326 | static struct mtd_partition higlvl_partition_info[]= | 326 | static struct mtd_partition higlvl_partition_info[]= |
327 | { | 327 | { |
328 | { | 328 | { |
329 | .name = "ADNP boot block", | 329 | .name = "ADNP boot block", |
330 | .offset = 0, | 330 | .offset = 0, |
331 | .size = CONFIG_MTD_DILNETPC_BOOTSIZE, | 331 | .size = CONFIG_MTD_DILNETPC_BOOTSIZE, |
332 | }, | 332 | }, |
333 | { | 333 | { |
@@ -335,8 +335,8 @@ static struct mtd_partition higlvl_partition_info[]= | |||
335 | .offset = MTDPART_OFS_NXTBLK, | 335 | .offset = MTDPART_OFS_NXTBLK, |
336 | .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, | 336 | .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, |
337 | }, | 337 | }, |
338 | { | 338 | { |
339 | .name = "ADNP system BIOS + BIOS Entry", | 339 | .name = "ADNP system BIOS + BIOS Entry", |
340 | .offset = MTDPART_OFS_NXTBLK, | 340 | .offset = MTDPART_OFS_NXTBLK, |
341 | .size = MTDPART_SIZ_FULL, | 341 | .size = MTDPART_SIZ_FULL, |
342 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED | 342 | #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED |
@@ -371,7 +371,7 @@ static int __init init_dnpc(void) | |||
371 | 371 | ||
372 | /* | 372 | /* |
373 | ** determine hardware (DNP/ADNP/invalid) | 373 | ** determine hardware (DNP/ADNP/invalid) |
374 | */ | 374 | */ |
375 | if((is_dnp = dnp_adnp_probe()) < 0) | 375 | if((is_dnp = dnp_adnp_probe()) < 0) |
376 | return -ENXIO; | 376 | return -ENXIO; |
377 | 377 | ||
@@ -397,13 +397,13 @@ static int __init init_dnpc(void) | |||
397 | ++dnpc_map.name; | 397 | ++dnpc_map.name; |
398 | for(i = 0; i < NUM_PARTITIONS; i++) | 398 | for(i = 0; i < NUM_PARTITIONS; i++) |
399 | ++partition_info[i].name; | 399 | ++partition_info[i].name; |
400 | higlvl_partition_info[1].size = DNP_WINDOW_SIZE - | 400 | higlvl_partition_info[1].size = DNP_WINDOW_SIZE - |
401 | CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; | 401 | CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; |
402 | for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) | 402 | for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) |
403 | ++higlvl_partition_info[i].name; | 403 | ++higlvl_partition_info[i].name; |
404 | } | 404 | } |
405 | 405 | ||
406 | printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", | 406 | printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", |
407 | is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); | 407 | is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); |
408 | 408 | ||
409 | dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); | 409 | dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); |
@@ -436,7 +436,7 @@ static int __init init_dnpc(void) | |||
436 | iounmap(dnpc_map.virt); | 436 | iounmap(dnpc_map.virt); |
437 | return -ENXIO; | 437 | return -ENXIO; |
438 | } | 438 | } |
439 | 439 | ||
440 | mymtd->owner = THIS_MODULE; | 440 | mymtd->owner = THIS_MODULE; |
441 | 441 | ||
442 | /* | 442 | /* |
diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c index b9bc63503e26..b993ac01a9a5 100644 --- a/drivers/mtd/maps/dmv182.c +++ b/drivers/mtd/maps/dmv182.c | |||
@@ -1,10 +1,10 @@ | |||
1 | 1 | ||
2 | /* | 2 | /* |
3 | * drivers/mtd/maps/svme182.c | 3 | * drivers/mtd/maps/svme182.c |
4 | * | 4 | * |
5 | * Flash map driver for the Dy4 SVME182 board | 5 | * Flash map driver for the Dy4 SVME182 board |
6 | * | 6 | * |
7 | * $Id: dmv182.c,v 1.5 2004/11/04 13:24:14 gleixner Exp $ | 7 | * $Id: dmv182.c,v 1.6 2005/11/07 11:14:26 gleixner Exp $ |
8 | * | 8 | * |
9 | * Copyright 2003-2004, TimeSys Corporation | 9 | * Copyright 2003-2004, TimeSys Corporation |
10 | * | 10 | * |
@@ -104,7 +104,7 @@ static int __init init_svme182(void) | |||
104 | partitions = svme182_partitions; | 104 | partitions = svme182_partitions; |
105 | 105 | ||
106 | svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size); | 106 | svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size); |
107 | 107 | ||
108 | if (svme182_map.virt == 0) { | 108 | if (svme182_map.virt == 0) { |
109 | printk("Failed to ioremap FLASH memory area.\n"); | 109 | printk("Failed to ioremap FLASH memory area.\n"); |
110 | return -EIO; | 110 | return -EIO; |
diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c index b9d9cf4854b6..c0daf58357ca 100644 --- a/drivers/mtd/maps/ebony.c +++ b/drivers/mtd/maps/ebony.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ebony.c,v 1.15 2004/12/09 18:39:54 holindho Exp $ | 2 | * $Id: ebony.c,v 1.16 2005/11/07 11:14:26 gleixner Exp $ |
3 | * | 3 | * |
4 | * Mapping for Ebony user flash | 4 | * Mapping for Ebony user flash |
5 | * | 5 | * |
6 | * Matt Porter <mporter@kernel.crashing.org> | 6 | * Matt Porter <mporter@kernel.crashing.org> |
@@ -85,7 +85,7 @@ int __init init_ebony(void) | |||
85 | small_flash_base = EBONY_SMALL_FLASH_LOW2; | 85 | small_flash_base = EBONY_SMALL_FLASH_LOW2; |
86 | else | 86 | else |
87 | small_flash_base = EBONY_SMALL_FLASH_LOW1; | 87 | small_flash_base = EBONY_SMALL_FLASH_LOW1; |
88 | 88 | ||
89 | if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && | 89 | if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && |
90 | !EBONY_ONBRD_FLASH_EN(fpga0_reg)) | 90 | !EBONY_ONBRD_FLASH_EN(fpga0_reg)) |
91 | large_flash_base = EBONY_LARGE_FLASH_LOW; | 91 | large_flash_base = EBONY_LARGE_FLASH_LOW; |
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 8b0da394f3fa..b48a3473ffc1 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: edb7312.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: edb7312.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Handle mapping of the NOR flash on Cogent EDB7312 boards | 4 | * Handle mapping of the NOR flash on Cogent EDB7312 boards |
5 | * | 5 | * |
6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -46,7 +46,7 @@ struct map_info edb7312nor_map = { | |||
46 | #ifdef CONFIG_MTD_PARTITIONS | 46 | #ifdef CONFIG_MTD_PARTITIONS |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * MTD partitioning stuff | 49 | * MTD partitioning stuff |
50 | */ | 50 | */ |
51 | static struct mtd_partition static_partitions[3] = | 51 | static struct mtd_partition static_partitions[3] = |
52 | { | 52 | { |
@@ -80,7 +80,7 @@ int __init init_edb7312nor(void) | |||
80 | const char **type; | 80 | const char **type; |
81 | const char *part_type = 0; | 81 | const char *part_type = 0; |
82 | 82 | ||
83 | printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", | 83 | printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", |
84 | WINDOW_SIZE, WINDOW_ADDR); | 84 | WINDOW_SIZE, WINDOW_ADDR); |
85 | edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); | 85 | edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); |
86 | 86 | ||
@@ -88,7 +88,7 @@ int __init init_edb7312nor(void) | |||
88 | printk(MSG_PREFIX "failed to ioremap\n"); | 88 | printk(MSG_PREFIX "failed to ioremap\n"); |
89 | return -EIO; | 89 | return -EIO; |
90 | } | 90 | } |
91 | 91 | ||
92 | simple_map_init(&edb7312nor_map); | 92 | simple_map_init(&edb7312nor_map); |
93 | 93 | ||
94 | mymtd = 0; | 94 | mymtd = 0; |
diff --git a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c index 1df6188926b3..265b079fe934 100644 --- a/drivers/mtd/maps/epxa10db-flash.c +++ b/drivers/mtd/maps/epxa10db-flash.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * Copyright (C) 2001 Altera Corporation | 5 | * Copyright (C) 2001 Altera Corporation |
6 | * Copyright (C) 2001 Red Hat, Inc. | 6 | * Copyright (C) 2001 Red Hat, Inc. |
7 | * | 7 | * |
8 | * $Id: epxa10db-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 8 | * $Id: epxa10db-flash.c,v 1.15 2005/11/07 11:14:27 gleixner Exp $ |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -62,7 +62,7 @@ static const char *probes[] = { "RedBoot", "afs", NULL }; | |||
62 | static int __init epxa_mtd_init(void) | 62 | static int __init epxa_mtd_init(void) |
63 | { | 63 | { |
64 | int i; | 64 | int i; |
65 | 65 | ||
66 | printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); | 66 | printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); |
67 | 67 | ||
68 | epxa_map.virt = ioremap(FLASH_START, FLASH_SIZE); | 68 | epxa_map.virt = ioremap(FLASH_START, FLASH_SIZE); |
@@ -126,8 +126,8 @@ static void __exit epxa_mtd_cleanup(void) | |||
126 | } | 126 | } |
127 | 127 | ||
128 | 128 | ||
129 | /* | 129 | /* |
130 | * This will do for now, once we decide which bootldr we're finally | 130 | * This will do for now, once we decide which bootldr we're finally |
131 | * going to use then we'll remove this function and do it properly | 131 | * going to use then we'll remove this function and do it properly |
132 | * | 132 | * |
133 | * Partions are currently (as offsets from base of flash): | 133 | * Partions are currently (as offsets from base of flash): |
@@ -140,7 +140,7 @@ static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_pa | |||
140 | struct mtd_partition *parts; | 140 | struct mtd_partition *parts; |
141 | int ret, i; | 141 | int ret, i; |
142 | int npartitions = 0; | 142 | int npartitions = 0; |
143 | char *names; | 143 | char *names; |
144 | const char *name = "jffs"; | 144 | const char *name = "jffs"; |
145 | 145 | ||
146 | printk("Using default partitions for %s\n",BOARD_NAME); | 146 | printk("Using default partitions for %s\n",BOARD_NAME); |
@@ -152,7 +152,7 @@ static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_pa | |||
152 | goto out; | 152 | goto out; |
153 | } | 153 | } |
154 | i=0; | 154 | i=0; |
155 | names = (char *)&parts[npartitions]; | 155 | names = (char *)&parts[npartitions]; |
156 | parts[i].name = names; | 156 | parts[i].name = names; |
157 | names += strlen(name) + 1; | 157 | names += strlen(name) + 1; |
158 | strcpy(parts[i].name, name); | 158 | strcpy(parts[i].name, name); |
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index 00f7bbe5479e..c6bf4e1219ef 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* fortunet.c memory map | 1 | /* fortunet.c memory map |
2 | * | 2 | * |
3 | * $Id: fortunet.c,v 1.9 2004/11/04 13:24:14 gleixner Exp $ | 3 | * $Id: fortunet.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $ |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
@@ -212,7 +212,7 @@ int __init init_fortunet(void) | |||
212 | 212 | ||
213 | map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, | 213 | map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, |
214 | 214 | ||
215 | map_regions[ix].map_info.virt = | 215 | map_regions[ix].map_info.virt = |
216 | ioremap_nocache( | 216 | ioremap_nocache( |
217 | map_regions[ix].window_addr_physical, | 217 | map_regions[ix].window_addr_physical, |
218 | map_regions[ix].map_info.size); | 218 | map_regions[ix].map_info.size); |
diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index c73828171d9b..319094821101 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on Hynix GMS30C7201/HMS30C7202 based | 2 | * Flash memory access on Hynix GMS30C7201/HMS30C7202 based |
3 | * evaluation boards | 3 | * evaluation boards |
4 | * | 4 | * |
5 | * $Id: h720x-flash.c,v 1.11 2004/11/04 13:24:14 gleixner Exp $ | 5 | * $Id: h720x-flash.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ |
6 | * | 6 | * |
7 | * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> | 7 | * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> |
8 | * 2003 Thomas Gleixner <tglx@linutronix.de> | 8 | * 2003 Thomas Gleixner <tglx@linutronix.de> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
@@ -72,7 +72,7 @@ int __init h720x_mtd_init(void) | |||
72 | { | 72 | { |
73 | 73 | ||
74 | char *part_type = NULL; | 74 | char *part_type = NULL; |
75 | 75 | ||
76 | h720x_map.virt = ioremap(FLASH_PHYS, FLASH_SIZE); | 76 | h720x_map.virt = ioremap(FLASH_PHYS, FLASH_SIZE); |
77 | 77 | ||
78 | if (!h720x_map.virt) { | 78 | if (!h720x_map.virt) { |
@@ -91,7 +91,7 @@ int __init h720x_mtd_init(void) | |||
91 | h720x_map.bankwidth = 2; | 91 | h720x_map.bankwidth = 2; |
92 | mymtd = do_map_probe("cfi_probe", &h720x_map); | 92 | mymtd = do_map_probe("cfi_probe", &h720x_map); |
93 | } | 93 | } |
94 | 94 | ||
95 | if (mymtd) { | 95 | if (mymtd) { |
96 | mymtd->owner = THIS_MODULE; | 96 | mymtd->owner = THIS_MODULE; |
97 | 97 | ||
@@ -124,11 +124,11 @@ static void __exit h720x_mtd_cleanup(void) | |||
124 | del_mtd_partitions(mymtd); | 124 | del_mtd_partitions(mymtd); |
125 | map_destroy(mymtd); | 125 | map_destroy(mymtd); |
126 | } | 126 | } |
127 | 127 | ||
128 | /* Free partition info, if commandline partition was used */ | 128 | /* Free partition info, if commandline partition was used */ |
129 | if (mtd_parts && (mtd_parts != h720x_partitions)) | 129 | if (mtd_parts && (mtd_parts != h720x_partitions)) |
130 | kfree (mtd_parts); | 130 | kfree (mtd_parts); |
131 | 131 | ||
132 | if (h720x_map.virt) { | 132 | if (h720x_map.virt) { |
133 | iounmap((void *)h720x_map.virt); | 133 | iounmap((void *)h720x_map.virt); |
134 | h720x_map.virt = 0; | 134 | h720x_map.virt = 0; |
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index c5e2111ba146..ea5073781b3a 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * ichxrom.c | 2 | * ichxrom.c |
3 | * | 3 | * |
4 | * Normal mappings of chips in physical memory | 4 | * Normal mappings of chips in physical memory |
5 | * $Id: ichxrom.c,v 1.18 2005/07/07 10:26:20 dwmw2 Exp $ | 5 | * $Id: ichxrom.c,v 1.19 2005/11/07 11:14:27 gleixner Exp $ |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
@@ -101,7 +101,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
101 | * you can only really attach a FWH to an ICHX there | 101 | * you can only really attach a FWH to an ICHX there |
102 | * a number of simplifications you can make. | 102 | * a number of simplifications you can make. |
103 | * | 103 | * |
104 | * Also you can page firmware hubs if an 8MB window isn't enough | 104 | * Also you can page firmware hubs if an 8MB window isn't enough |
105 | * but don't currently handle that case either. | 105 | * but don't currently handle that case either. |
106 | */ | 106 | */ |
107 | window->pdev = pdev; | 107 | window->pdev = pdev; |
@@ -144,7 +144,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
144 | window->phys = 0xfff00000; | 144 | window->phys = 0xfff00000; |
145 | } | 145 | } |
146 | else if ((byte & 0x80) == 0x80) { | 146 | else if ((byte & 0x80) == 0x80) { |
147 | window->phys = 0xfff80000; | 147 | window->phys = 0xfff80000; |
148 | } | 148 | } |
149 | 149 | ||
150 | if (window->phys == 0) { | 150 | if (window->phys == 0) { |
@@ -233,7 +233,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
233 | * in a factory setting. So in-place programming | 233 | * in a factory setting. So in-place programming |
234 | * needs to use a different method. | 234 | * needs to use a different method. |
235 | */ | 235 | */ |
236 | for(map->map.bankwidth = 32; map->map.bankwidth; | 236 | for(map->map.bankwidth = 32; map->map.bankwidth; |
237 | map->map.bankwidth >>= 1) | 237 | map->map.bankwidth >>= 1) |
238 | { | 238 | { |
239 | char **probe_type; | 239 | char **probe_type; |
@@ -286,7 +286,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, | |||
286 | for(i = 0; i < cfi->numchips; i++) { | 286 | for(i = 0; i < cfi->numchips; i++) { |
287 | cfi->chips[i].start += offset; | 287 | cfi->chips[i].start += offset; |
288 | } | 288 | } |
289 | 289 | ||
290 | /* Now that the mtd devices is complete claim and export it */ | 290 | /* Now that the mtd devices is complete claim and export it */ |
291 | map->mtd->owner = THIS_MODULE; | 291 | map->mtd->owner = THIS_MODULE; |
292 | if (add_mtd_device(map->mtd)) { | 292 | if (add_mtd_device(map->mtd)) { |
@@ -324,11 +324,11 @@ static void __devexit ichxrom_remove_one (struct pci_dev *pdev) | |||
324 | } | 324 | } |
325 | 325 | ||
326 | static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { | 326 | static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { |
327 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, | 327 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, |
328 | PCI_ANY_ID, PCI_ANY_ID, }, | 328 | PCI_ANY_ID, PCI_ANY_ID, }, |
329 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, | 329 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, |
330 | PCI_ANY_ID, PCI_ANY_ID, }, | 330 | PCI_ANY_ID, PCI_ANY_ID, }, |
331 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, | 331 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, |
332 | PCI_ANY_ID, PCI_ANY_ID, }, | 332 | PCI_ANY_ID, PCI_ANY_ID, }, |
333 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, | 333 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, |
334 | PCI_ANY_ID, PCI_ANY_ID, }, | 334 | PCI_ANY_ID, PCI_ANY_ID, }, |
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index cb39172c81d2..ba7f40311a7e 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: impa7.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ | 2 | * $Id: impa7.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Handle mapping of the NOR flash on implementa A7 boards | 4 | * Handle mapping of the NOR flash on implementa A7 boards |
5 | * | 5 | * |
6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH | 6 | * Copyright 2002 SYSGO Real-Time Solutions GmbH |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
@@ -55,7 +55,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = { | |||
55 | #ifdef CONFIG_MTD_PARTITIONS | 55 | #ifdef CONFIG_MTD_PARTITIONS |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * MTD partitioning stuff | 58 | * MTD partitioning stuff |
59 | */ | 59 | */ |
60 | static struct mtd_partition static_partitions[] = | 60 | static struct mtd_partition static_partitions[] = |
61 | { | 61 | { |
@@ -108,9 +108,9 @@ int __init init_impa7(void) | |||
108 | impa7_mtd[i]->owner = THIS_MODULE; | 108 | impa7_mtd[i]->owner = THIS_MODULE; |
109 | devicesfound++; | 109 | devicesfound++; |
110 | #ifdef CONFIG_MTD_PARTITIONS | 110 | #ifdef CONFIG_MTD_PARTITIONS |
111 | mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], | 111 | mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], |
112 | probes, | 112 | probes, |
113 | &mtd_parts[i], | 113 | &mtd_parts[i], |
114 | 0); | 114 | 0); |
115 | if (mtd_parts_nb[i] > 0) { | 115 | if (mtd_parts_nb[i] > 0) { |
116 | part_type = "command line"; | 116 | part_type = "command line"; |
@@ -121,16 +121,16 @@ int __init init_impa7(void) | |||
121 | } | 121 | } |
122 | 122 | ||
123 | printk(KERN_NOTICE MSG_PREFIX | 123 | printk(KERN_NOTICE MSG_PREFIX |
124 | "using %s partition definition\n", | 124 | "using %s partition definition\n", |
125 | part_type); | 125 | part_type); |
126 | add_mtd_partitions(impa7_mtd[i], | 126 | add_mtd_partitions(impa7_mtd[i], |
127 | mtd_parts[i], mtd_parts_nb[i]); | 127 | mtd_parts[i], mtd_parts_nb[i]); |
128 | #else | 128 | #else |
129 | add_mtd_device(impa7_mtd[i]); | 129 | add_mtd_device(impa7_mtd[i]); |
130 | 130 | ||
131 | #endif | 131 | #endif |
132 | } | 132 | } |
133 | else | 133 | else |
134 | iounmap((void *)impa7_map[i].virt); | 134 | iounmap((void *)impa7_map[i].virt); |
135 | } | 135 | } |
136 | return devicesfound == 0 ? -ENXIO : 0; | 136 | return devicesfound == 0 ? -ENXIO : 0; |
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 93f50d6d5488..fe738fd8d6f8 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c | |||
@@ -1,28 +1,28 @@ | |||
1 | /*====================================================================== | 1 | /*====================================================================== |
2 | 2 | ||
3 | drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver | 3 | drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver |
4 | 4 | ||
5 | Copyright (C) 2000 ARM Limited | 5 | Copyright (C) 2000 ARM Limited |
6 | Copyright (C) 2003 Deep Blue Solutions Ltd. | 6 | Copyright (C) 2003 Deep Blue Solutions Ltd. |
7 | 7 | ||
8 | This program is free software; you can redistribute it and/or modify | 8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | 9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2 of the License, or | 10 | the Free Software Foundation; either version 2 of the License, or |
11 | (at your option) any later version. | 11 | (at your option) any later version. |
12 | 12 | ||
13 | This program is distributed in the hope that it will be useful, | 13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. | 16 | GNU General Public License for more details. |
17 | 17 | ||
18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software | 19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | 21 | ||
22 | This is access code for flashes using ARM's flash partitioning | 22 | This is access code for flashes using ARM's flash partitioning |
23 | standards. | 23 | standards. |
24 | 24 | ||
25 | $Id: integrator-flash.c,v 1.18 2004/11/01 13:26:15 rmk Exp $ | 25 | $Id: integrator-flash.c,v 1.20 2005/11/07 11:14:27 gleixner Exp $ |
26 | 26 | ||
27 | ======================================================================*/ | 27 | ======================================================================*/ |
28 | 28 | ||
diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c index 70b0e0b82c34..35097c9bbf50 100644 --- a/drivers/mtd/maps/ipaq-flash.c +++ b/drivers/mtd/maps/ipaq-flash.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based) | 2 | * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based) |
3 | * | 3 | * |
4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
5 | * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> | 5 | * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> |
6 | * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes | 6 | * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes |
7 | * | 7 | * |
8 | * $Id: ipaq-flash.c,v 1.3 2004/11/04 13:24:15 gleixner Exp $ | 8 | * $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
@@ -107,7 +107,7 @@ static struct mtd_partition h3xxx_partitions[] = { | |||
107 | #ifndef CONFIG_LAB | 107 | #ifndef CONFIG_LAB |
108 | mask_flags: MTD_WRITEABLE, /* force read-only */ | 108 | mask_flags: MTD_WRITEABLE, /* force read-only */ |
109 | #endif | 109 | #endif |
110 | }, | 110 | }, |
111 | { | 111 | { |
112 | name: "H3XXX root jffs2", | 112 | name: "H3XXX root jffs2", |
113 | #ifndef CONFIG_LAB | 113 | #ifndef CONFIG_LAB |
@@ -148,7 +148,7 @@ static DEFINE_SPINLOCK(ipaq_vpp_lock); | |||
148 | static void h3xxx_set_vpp(struct map_info *map, int vpp) | 148 | static void h3xxx_set_vpp(struct map_info *map, int vpp) |
149 | { | 149 | { |
150 | static int nest = 0; | 150 | static int nest = 0; |
151 | 151 | ||
152 | spin_lock(&ipaq_vpp_lock); | 152 | spin_lock(&ipaq_vpp_lock); |
153 | if (vpp) | 153 | if (vpp) |
154 | nest++; | 154 | nest++; |
@@ -191,7 +191,7 @@ static unsigned long cs_phys[] = { | |||
191 | SA1100_CS3_PHYS, | 191 | SA1100_CS3_PHYS, |
192 | SA1100_CS4_PHYS, | 192 | SA1100_CS4_PHYS, |
193 | SA1100_CS5_PHYS, | 193 | SA1100_CS5_PHYS, |
194 | #else | 194 | #else |
195 | PXA_CS0_PHYS, | 195 | PXA_CS0_PHYS, |
196 | PXA_CS1_PHYS, | 196 | PXA_CS1_PHYS, |
197 | PXA_CS2_PHYS, | 197 | PXA_CS2_PHYS, |
@@ -216,7 +216,7 @@ int __init ipaq_mtd_init(void) | |||
216 | 216 | ||
217 | /* Default flash bankwidth */ | 217 | /* Default flash bankwidth */ |
218 | // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4; | 218 | // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4; |
219 | 219 | ||
220 | if (machine_is_h1900()) | 220 | if (machine_is_h1900()) |
221 | { | 221 | { |
222 | /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */ | 222 | /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */ |
@@ -229,7 +229,7 @@ int __init ipaq_mtd_init(void) | |||
229 | else | 229 | else |
230 | for(i=0; i<MAX_IPAQ_CS; i++) | 230 | for(i=0; i<MAX_IPAQ_CS; i++) |
231 | ipaq_map[i].bankwidth = 4; | 231 | ipaq_map[i].bankwidth = 4; |
232 | 232 | ||
233 | /* | 233 | /* |
234 | * Static partition definition selection | 234 | * Static partition definition selection |
235 | */ | 235 | */ |
@@ -309,7 +309,7 @@ int __init ipaq_mtd_init(void) | |||
309 | return -ENXIO; | 309 | return -ENXIO; |
310 | } else | 310 | } else |
311 | printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size); | 311 | printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size); |
312 | 312 | ||
313 | /* do we really need this debugging? --joshua 20030703 */ | 313 | /* do we really need this debugging? --joshua 20030703 */ |
314 | // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]); | 314 | // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]); |
315 | my_sub_mtd[i]->owner = THIS_MODULE; | 315 | my_sub_mtd[i]->owner = THIS_MODULE; |
@@ -333,11 +333,11 @@ int __init ipaq_mtd_init(void) | |||
333 | #else | 333 | #else |
334 | mymtd = my_sub_mtd[0]; | 334 | mymtd = my_sub_mtd[0]; |
335 | 335 | ||
336 | /* | 336 | /* |
337 | *In the very near future, command line partition parsing | 337 | *In the very near future, command line partition parsing |
338 | * will use the device name as 'mtd-id' instead of a value | 338 | * will use the device name as 'mtd-id' instead of a value |
339 | * passed to the parse_cmdline_partitions() routine. Since | 339 | * passed to the parse_cmdline_partitions() routine. Since |
340 | * the bootldr says 'ipaq', make sure it continues to work. | 340 | * the bootldr says 'ipaq', make sure it continues to work. |
341 | */ | 341 | */ |
342 | mymtd->name = "ipaq"; | 342 | mymtd->name = "ipaq"; |
343 | 343 | ||
@@ -385,7 +385,7 @@ int __init ipaq_mtd_init(void) | |||
385 | */ | 385 | */ |
386 | 386 | ||
387 | i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0); | 387 | i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0); |
388 | 388 | ||
389 | if (i > 0) { | 389 | if (i > 0) { |
390 | nb_parts = parsed_nr_parts = i; | 390 | nb_parts = parsed_nr_parts = i; |
391 | parts = parsed_parts; | 391 | parts = parsed_parts; |
@@ -423,10 +423,10 @@ static void __exit ipaq_mtd_cleanup(void) | |||
423 | #endif | 423 | #endif |
424 | map_destroy(mymtd); | 424 | map_destroy(mymtd); |
425 | #ifdef CONFIG_MTD_CONCAT | 425 | #ifdef CONFIG_MTD_CONCAT |
426 | for(i=0; i<MAX_IPAQ_CS; i++) | 426 | for(i=0; i<MAX_IPAQ_CS; i++) |
427 | #else | 427 | #else |
428 | for(i=1; i<MAX_IPAQ_CS; i++) | 428 | for(i=1; i<MAX_IPAQ_CS; i++) |
429 | #endif | 429 | #endif |
430 | { | 430 | { |
431 | if (my_sub_mtd[i]) | 431 | if (my_sub_mtd[i]) |
432 | map_destroy(my_sub_mtd[i]); | 432 | map_destroy(my_sub_mtd[i]); |
@@ -444,14 +444,14 @@ static int __init h1900_special_case(void) | |||
444 | ipaq_map[0].phys = 0x0; | 444 | ipaq_map[0].phys = 0x0; |
445 | ipaq_map[0].virt = __ioremap(0x0, 0x04000000, 0, 1); | 445 | ipaq_map[0].virt = __ioremap(0x0, 0x04000000, 0, 1); |
446 | ipaq_map[0].bankwidth = 2; | 446 | ipaq_map[0].bankwidth = 2; |
447 | 447 | ||
448 | printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt); | 448 | printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt); |
449 | mymtd = do_map_probe("jedec_probe", &ipaq_map[0]); | 449 | mymtd = do_map_probe("jedec_probe", &ipaq_map[0]); |
450 | if (!mymtd) | 450 | if (!mymtd) |
451 | return -ENODEV; | 451 | return -ENODEV; |
452 | add_mtd_device(mymtd); | 452 | add_mtd_device(mymtd); |
453 | printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n"); | 453 | printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n"); |
454 | 454 | ||
455 | return 0; | 455 | return 0; |
456 | } | 456 | } |
457 | 457 | ||
diff --git a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c index 2e7577492a2c..62d9e87d84e2 100644 --- a/drivers/mtd/maps/iq80310.c +++ b/drivers/mtd/maps/iq80310.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: iq80310.c,v 1.20 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: iq80310.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Mapping for the Intel XScale IQ80310 evaluation board | 4 | * Mapping for the Intel XScale IQ80310 evaluation board |
5 | * | 5 | * |
6 | * Author: Nicolas Pitre | 6 | * Author: Nicolas Pitre |
7 | * Copyright: (C) 2001 MontaVista Software Inc. | 7 | * Copyright: (C) 2001 MontaVista Software Inc. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 6f36497022d1..641eb2b55e9f 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $ | 2 | * $Id: ixp2000.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/ixp2000.c | 4 | * drivers/mtd/maps/ixp2000.c |
5 | * | 5 | * |
@@ -14,7 +14,7 @@ | |||
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License version 2 as | 15 | * it under the terms of the GNU General Public License version 2 as |
16 | * published by the Free Software Foundation. | 16 | * published by the Free Software Foundation. |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
@@ -46,8 +46,8 @@ struct ixp2000_flash_info { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) | 48 | static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) |
49 | { | 49 | { |
50 | unsigned long (*set_bank)(unsigned long) = | 50 | unsigned long (*set_bank)(unsigned long) = |
51 | (unsigned long(*)(unsigned long))map->map_priv_2; | 51 | (unsigned long(*)(unsigned long))map->map_priv_2; |
52 | 52 | ||
53 | return (set_bank ? set_bank(ofs) : ofs); | 53 | return (set_bank ? set_bank(ofs) : ofs); |
@@ -55,8 +55,8 @@ static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long | |||
55 | 55 | ||
56 | #ifdef __ARMEB__ | 56 | #ifdef __ARMEB__ |
57 | /* | 57 | /* |
58 | * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which | 58 | * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which |
59 | * causes the lower address bits to be XORed with 0x11 on 8 bit accesses | 59 | * causes the lower address bits to be XORed with 0x11 on 8 bit accesses |
60 | * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44. | 60 | * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44. |
61 | */ | 61 | */ |
62 | static int erratum44_workaround = 0; | 62 | static int erratum44_workaround = 0; |
@@ -90,7 +90,7 @@ static void ixp2000_flash_copy_from(struct map_info *map, void *to, | |||
90 | unsigned long from, ssize_t len) | 90 | unsigned long from, ssize_t len) |
91 | { | 91 | { |
92 | from = flash_bank_setup(map, from); | 92 | from = flash_bank_setup(map, from); |
93 | while(len--) | 93 | while(len--) |
94 | *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); | 94 | *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); |
95 | } | 95 | } |
96 | 96 | ||
@@ -148,11 +148,11 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
148 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; | 148 | static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; |
149 | struct platform_device *dev = to_platform_device(_dev); | 149 | struct platform_device *dev = to_platform_device(_dev); |
150 | struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; | 150 | struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; |
151 | struct flash_platform_data *plat; | 151 | struct flash_platform_data *plat; |
152 | struct ixp2000_flash_info *info; | 152 | struct ixp2000_flash_info *info; |
153 | unsigned long window_size; | 153 | unsigned long window_size; |
154 | int err = -1; | 154 | int err = -1; |
155 | 155 | ||
156 | if (!ixp_data) | 156 | if (!ixp_data) |
157 | return -ENODEV; | 157 | return -ENODEV; |
158 | 158 | ||
@@ -161,7 +161,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
161 | return -ENODEV; | 161 | return -ENODEV; |
162 | 162 | ||
163 | window_size = dev->resource->end - dev->resource->start + 1; | 163 | window_size = dev->resource->end - dev->resource->start + 1; |
164 | dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", | 164 | dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", |
165 | ixp_data->nr_banks, ((u32)window_size >> 20)); | 165 | ixp_data->nr_banks, ((u32)window_size >> 20)); |
166 | 166 | ||
167 | if (plat->width != 1) { | 167 | if (plat->width != 1) { |
@@ -174,7 +174,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
174 | if(!info) { | 174 | if(!info) { |
175 | err = -ENOMEM; | 175 | err = -ENOMEM; |
176 | goto Error; | 176 | goto Error; |
177 | } | 177 | } |
178 | memzero(info, sizeof(struct ixp2000_flash_info)); | 178 | memzero(info, sizeof(struct ixp2000_flash_info)); |
179 | 179 | ||
180 | dev_set_drvdata(&dev->dev, info); | 180 | dev_set_drvdata(&dev->dev, info); |
@@ -184,7 +184,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
184 | * not attempt to do a direct access on us. | 184 | * not attempt to do a direct access on us. |
185 | */ | 185 | */ |
186 | info->map.phys = NO_XIP; | 186 | info->map.phys = NO_XIP; |
187 | 187 | ||
188 | info->nr_banks = ixp_data->nr_banks; | 188 | info->nr_banks = ixp_data->nr_banks; |
189 | info->map.size = ixp_data->nr_banks * window_size; | 189 | info->map.size = ixp_data->nr_banks * window_size; |
190 | info->map.bankwidth = 1; | 190 | info->map.bankwidth = 1; |
@@ -192,7 +192,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
192 | /* | 192 | /* |
193 | * map_priv_2 is used to store a ptr to to the bank_setup routine | 193 | * map_priv_2 is used to store a ptr to to the bank_setup routine |
194 | */ | 194 | */ |
195 | info->map.map_priv_2 = (void __iomem *) ixp_data->bank_setup; | 195 | info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup; |
196 | 196 | ||
197 | info->map.name = dev->dev.bus_id; | 197 | info->map.name = dev->dev.bus_id; |
198 | info->map.read = ixp2000_flash_read8; | 198 | info->map.read = ixp2000_flash_read8; |
@@ -200,8 +200,8 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
200 | info->map.copy_from = ixp2000_flash_copy_from; | 200 | info->map.copy_from = ixp2000_flash_copy_from; |
201 | info->map.copy_to = ixp2000_flash_copy_to; | 201 | info->map.copy_to = ixp2000_flash_copy_to; |
202 | 202 | ||
203 | info->res = request_mem_region(dev->resource->start, | 203 | info->res = request_mem_region(dev->resource->start, |
204 | dev->resource->end - dev->resource->start + 1, | 204 | dev->resource->end - dev->resource->start + 1, |
205 | dev->dev.bus_id); | 205 | dev->dev.bus_id); |
206 | if (!info->res) { | 206 | if (!info->res) { |
207 | dev_err(_dev, "Could not reserve memory region\n"); | 207 | dev_err(_dev, "Could not reserve memory region\n"); |
@@ -209,7 +209,7 @@ static int ixp2000_flash_probe(struct device *_dev) | |||
209 | goto Error; | 209 | goto Error; |
210 | } | 210 | } |
211 | 211 | ||
212 | info->map.map_priv_1 = ioremap(dev->resource->start, | 212 | info->map.map_priv_1 = (unsigned long) ioremap(dev->resource->start, |
213 | dev->resource->end - dev->resource->start + 1); | 213 | dev->resource->end - dev->resource->start + 1); |
214 | if (!info->map.map_priv_1) { | 214 | if (!info->map.map_priv_1) { |
215 | dev_err(_dev, "Failed to ioremap flash region\n"); | 215 | dev_err(_dev, "Failed to ioremap flash region\n"); |
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 0d87c02dee04..56b3a355bf7b 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ixp4xx.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: ixp4xx.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/ixp4xx.c | 4 | * drivers/mtd/maps/ixp4xx.c |
5 | * | 5 | * |
@@ -45,7 +45,7 @@ | |||
45 | static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) | 45 | static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) |
46 | { | 46 | { |
47 | map_word val; | 47 | map_word val; |
48 | val.x[0] = *(__u16 *) (map->map_priv_1 + ofs); | 48 | val.x[0] = le16_to_cpu(readw(map->virt + ofs)); |
49 | return val; | 49 | return val; |
50 | } | 50 | } |
51 | 51 | ||
@@ -59,35 +59,35 @@ static void ixp4xx_copy_from(struct map_info *map, void *to, | |||
59 | { | 59 | { |
60 | int i; | 60 | int i; |
61 | u8 *dest = (u8 *) to; | 61 | u8 *dest = (u8 *) to; |
62 | u16 *src = (u16 *) (map->map_priv_1 + from); | 62 | void __iomem *src = map->virt + from; |
63 | u16 data; | 63 | u16 data; |
64 | 64 | ||
65 | for (i = 0; i < (len / 2); i++) { | 65 | for (i = 0; i < (len / 2); i++) { |
66 | data = src[i]; | 66 | data = le16_to_cpu(readw(src + 2*i)); |
67 | dest[i * 2] = BYTE0(data); | 67 | dest[i * 2] = BYTE0(data); |
68 | dest[i * 2 + 1] = BYTE1(data); | 68 | dest[i * 2 + 1] = BYTE1(data); |
69 | } | 69 | } |
70 | 70 | ||
71 | if (len & 1) | 71 | if (len & 1) |
72 | dest[len - 1] = BYTE0(src[i]); | 72 | dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i))); |
73 | } | 73 | } |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * Unaligned writes are ignored, causing the 8-bit | 76 | * Unaligned writes are ignored, causing the 8-bit |
77 | * probe to fail and proceed to the 16-bit probe (which succeeds). | 77 | * probe to fail and proceed to the 16-bit probe (which succeeds). |
78 | */ | 78 | */ |
79 | static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) | 79 | static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) |
80 | { | 80 | { |
81 | if (!(adr & 1)) | 81 | if (!(adr & 1)) |
82 | *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; | 82 | writew(cpu_to_le16(d.x[0]), map->virt + adr); |
83 | } | 83 | } |
84 | 84 | ||
85 | /* | 85 | /* |
86 | * Fast write16 function without the probing check above | 86 | * Fast write16 function without the probing check above |
87 | */ | 87 | */ |
88 | static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) | 88 | static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) |
89 | { | 89 | { |
90 | *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; | 90 | writew(cpu_to_le16(d.x[0]), map->virt + adr); |
91 | } | 91 | } |
92 | 92 | ||
93 | struct ixp4xx_flash_info { | 93 | struct ixp4xx_flash_info { |
@@ -104,25 +104,18 @@ static int ixp4xx_flash_remove(struct device *_dev) | |||
104 | struct platform_device *dev = to_platform_device(_dev); | 104 | struct platform_device *dev = to_platform_device(_dev); |
105 | struct flash_platform_data *plat = dev->dev.platform_data; | 105 | struct flash_platform_data *plat = dev->dev.platform_data; |
106 | struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); | 106 | struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); |
107 | map_word d; | ||
108 | 107 | ||
109 | dev_set_drvdata(&dev->dev, NULL); | 108 | dev_set_drvdata(&dev->dev, NULL); |
110 | 109 | ||
111 | if(!info) | 110 | if(!info) |
112 | return 0; | 111 | return 0; |
113 | 112 | ||
114 | /* | ||
115 | * This is required for a soft reboot to work. | ||
116 | */ | ||
117 | d.x[0] = 0xff; | ||
118 | ixp4xx_write16(&info->map, d, 0x55 * 0x2); | ||
119 | |||
120 | if (info->mtd) { | 113 | if (info->mtd) { |
121 | del_mtd_partitions(info->mtd); | 114 | del_mtd_partitions(info->mtd); |
122 | map_destroy(info->mtd); | 115 | map_destroy(info->mtd); |
123 | } | 116 | } |
124 | if (info->map.map_priv_1) | 117 | if (info->map.virt) |
125 | iounmap((void *) info->map.map_priv_1); | 118 | iounmap(info->map.virt); |
126 | 119 | ||
127 | kfree(info->partitions); | 120 | kfree(info->partitions); |
128 | 121 | ||
@@ -134,9 +127,6 @@ static int ixp4xx_flash_remove(struct device *_dev) | |||
134 | if (plat->exit) | 127 | if (plat->exit) |
135 | plat->exit(); | 128 | plat->exit(); |
136 | 129 | ||
137 | /* Disable flash write */ | ||
138 | *IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE; | ||
139 | |||
140 | return 0; | 130 | return 0; |
141 | } | 131 | } |
142 | 132 | ||
@@ -160,17 +150,11 @@ static int ixp4xx_flash_probe(struct device *_dev) | |||
160 | if(!info) { | 150 | if(!info) { |
161 | err = -ENOMEM; | 151 | err = -ENOMEM; |
162 | goto Error; | 152 | goto Error; |
163 | } | 153 | } |
164 | memzero(info, sizeof(struct ixp4xx_flash_info)); | 154 | memzero(info, sizeof(struct ixp4xx_flash_info)); |
165 | 155 | ||
166 | dev_set_drvdata(&dev->dev, info); | 156 | dev_set_drvdata(&dev->dev, info); |
167 | 157 | ||
168 | /* | ||
169 | * Enable flash write | ||
170 | * TODO: Move this out to board specific code | ||
171 | */ | ||
172 | *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; | ||
173 | |||
174 | /* | 158 | /* |
175 | * Tell the MTD layer we're not 1:1 mapped so that it does | 159 | * Tell the MTD layer we're not 1:1 mapped so that it does |
176 | * not attempt to do a direct access on us. | 160 | * not attempt to do a direct access on us. |
@@ -189,8 +173,8 @@ static int ixp4xx_flash_probe(struct device *_dev) | |||
189 | info->map.write = ixp4xx_probe_write16, | 173 | info->map.write = ixp4xx_probe_write16, |
190 | info->map.copy_from = ixp4xx_copy_from, | 174 | info->map.copy_from = ixp4xx_copy_from, |
191 | 175 | ||
192 | info->res = request_mem_region(dev->resource->start, | 176 | info->res = request_mem_region(dev->resource->start, |
193 | dev->resource->end - dev->resource->start + 1, | 177 | dev->resource->end - dev->resource->start + 1, |
194 | "IXP4XXFlash"); | 178 | "IXP4XXFlash"); |
195 | if (!info->res) { | 179 | if (!info->res) { |
196 | printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); | 180 | printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); |
@@ -198,9 +182,9 @@ static int ixp4xx_flash_probe(struct device *_dev) | |||
198 | goto Error; | 182 | goto Error; |
199 | } | 183 | } |
200 | 184 | ||
201 | info->map.map_priv_1 = ioremap(dev->resource->start, | 185 | info->map.virt = ioremap(dev->resource->start, |
202 | dev->resource->end - dev->resource->start + 1); | 186 | dev->resource->end - dev->resource->start + 1); |
203 | if (!info->map.map_priv_1) { | 187 | if (!info->map.virt) { |
204 | printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); | 188 | printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); |
205 | err = -EIO; | 189 | err = -EIO; |
206 | goto Error; | 190 | goto Error; |
@@ -213,7 +197,7 @@ static int ixp4xx_flash_probe(struct device *_dev) | |||
213 | goto Error; | 197 | goto Error; |
214 | } | 198 | } |
215 | info->mtd->owner = THIS_MODULE; | 199 | info->mtd->owner = THIS_MODULE; |
216 | 200 | ||
217 | /* Use the fast version */ | 201 | /* Use the fast version */ |
218 | info->map.write = ixp4xx_write16, | 202 | info->map.write = ixp4xx_write16, |
219 | 203 | ||
@@ -258,4 +242,3 @@ module_exit(ixp4xx_flash_exit); | |||
258 | MODULE_LICENSE("GPL"); | 242 | MODULE_LICENSE("GPL"); |
259 | MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems"); | 243 | MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems"); |
260 | MODULE_AUTHOR("Deepak Saxena"); | 244 | MODULE_AUTHOR("Deepak Saxena"); |
261 | |||
diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c index b08668212ab7..851bf9576052 100644 --- a/drivers/mtd/maps/l440gx.c +++ b/drivers/mtd/maps/l440gx.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $ | 2 | * $Id: l440gx.c,v 1.18 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * BIOS Flash chip on Intel 440GX board. | 4 | * BIOS Flash chip on Intel 440GX board. |
5 | * | 5 | * |
@@ -49,7 +49,7 @@ static struct map_info l440gx_map = { | |||
49 | .bankwidth = BUSWIDTH, | 49 | .bankwidth = BUSWIDTH, |
50 | .phys = WINDOW_ADDR, | 50 | .phys = WINDOW_ADDR, |
51 | #if 0 | 51 | #if 0 |
52 | /* FIXME verify that this is the | 52 | /* FIXME verify that this is the |
53 | * appripriate code for vpp enable/disable | 53 | * appripriate code for vpp enable/disable |
54 | */ | 54 | */ |
55 | .set_vpp = l440gx_set_vpp | 55 | .set_vpp = l440gx_set_vpp |
@@ -62,10 +62,10 @@ static int __init init_l440gx(void) | |||
62 | struct resource *pm_iobase; | 62 | struct resource *pm_iobase; |
63 | __u16 word; | 63 | __u16 word; |
64 | 64 | ||
65 | dev = pci_find_device(PCI_VENDOR_ID_INTEL, | 65 | dev = pci_find_device(PCI_VENDOR_ID_INTEL, |
66 | PCI_DEVICE_ID_INTEL_82371AB_0, NULL); | 66 | PCI_DEVICE_ID_INTEL_82371AB_0, NULL); |
67 | 67 | ||
68 | pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, | 68 | pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, |
69 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL); | 69 | PCI_DEVICE_ID_INTEL_82371AB_3, NULL); |
70 | 70 | ||
71 | if (!dev || !pm_dev) { | 71 | if (!dev || !pm_dev) { |
@@ -82,10 +82,10 @@ static int __init init_l440gx(void) | |||
82 | simple_map_init(&l440gx_map); | 82 | simple_map_init(&l440gx_map); |
83 | printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt); | 83 | printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt); |
84 | 84 | ||
85 | /* Setup the pm iobase resource | 85 | /* Setup the pm iobase resource |
86 | * This code should move into some kind of generic bridge | 86 | * This code should move into some kind of generic bridge |
87 | * driver but for the moment I'm content with getting the | 87 | * driver but for the moment I'm content with getting the |
88 | * allocation correct. | 88 | * allocation correct. |
89 | */ | 89 | */ |
90 | pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; | 90 | pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; |
91 | if (!(pm_iobase->flags & IORESOURCE_IO)) { | 91 | if (!(pm_iobase->flags & IORESOURCE_IO)) { |
@@ -110,7 +110,7 @@ static int __init init_l440gx(void) | |||
110 | /* Set the iobase */ | 110 | /* Set the iobase */ |
111 | iobase = pm_iobase->start; | 111 | iobase = pm_iobase->start; |
112 | pci_write_config_dword(pm_dev, 0x40, iobase | 1); | 112 | pci_write_config_dword(pm_dev, 0x40, iobase | 1); |
113 | 113 | ||
114 | 114 | ||
115 | /* Set XBCS# */ | 115 | /* Set XBCS# */ |
116 | pci_read_config_word(dev, 0x4e, &word); | 116 | pci_read_config_word(dev, 0x4e, &word); |
@@ -122,7 +122,7 @@ static int __init init_l440gx(void) | |||
122 | 122 | ||
123 | /* Enable the gate on the WE line */ | 123 | /* Enable the gate on the WE line */ |
124 | outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); | 124 | outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); |
125 | 125 | ||
126 | printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); | 126 | printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); |
127 | 127 | ||
128 | mymtd = do_map_probe("jedec_probe", &l440gx_map); | 128 | mymtd = do_map_probe("jedec_probe", &l440gx_map); |
@@ -145,7 +145,7 @@ static void __exit cleanup_l440gx(void) | |||
145 | { | 145 | { |
146 | del_mtd_device(mymtd); | 146 | del_mtd_device(mymtd); |
147 | map_destroy(mymtd); | 147 | map_destroy(mymtd); |
148 | 148 | ||
149 | iounmap(l440gx_map.virt); | 149 | iounmap(l440gx_map.virt); |
150 | } | 150 | } |
151 | 151 | ||
diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c index 2b4c5058787d..1aa0447c5e66 100644 --- a/drivers/mtd/maps/lubbock-flash.c +++ b/drivers/mtd/maps/lubbock-flash.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: lubbock-flash.c,v 1.19 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Map driver for the Lubbock developer platform. | 4 | * Map driver for the Lubbock developer platform. |
5 | * | 5 | * |
6 | * Author: Nicolas Pitre | 6 | * Author: Nicolas Pitre |
7 | * Copyright: (C) 2001 MontaVista Software Inc. | 7 | * Copyright: (C) 2001 MontaVista Software Inc. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -76,7 +76,7 @@ static int __init init_lubbock(void) | |||
76 | int flashboot = (LUB_CONF_SWITCHES & 1); | 76 | int flashboot = (LUB_CONF_SWITCHES & 1); |
77 | int ret = 0, i; | 77 | int ret = 0, i; |
78 | 78 | ||
79 | lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = | 79 | lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = |
80 | (BOOT_DEF & 1) ? 2 : 4; | 80 | (BOOT_DEF & 1) ? 2 : 4; |
81 | 81 | ||
82 | /* Compensate for the nROMBT switch which swaps the flash banks */ | 82 | /* Compensate for the nROMBT switch which swaps the flash banks */ |
@@ -100,11 +100,11 @@ static int __init init_lubbock(void) | |||
100 | simple_map_init(&lubbock_maps[i]); | 100 | simple_map_init(&lubbock_maps[i]); |
101 | 101 | ||
102 | printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n", | 102 | printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n", |
103 | lubbock_maps[i].name, lubbock_maps[i].phys, | 103 | lubbock_maps[i].name, lubbock_maps[i].phys, |
104 | lubbock_maps[i].bankwidth * 8); | 104 | lubbock_maps[i].bankwidth * 8); |
105 | 105 | ||
106 | mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); | 106 | mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); |
107 | 107 | ||
108 | if (!mymtds[i]) { | 108 | if (!mymtds[i]) { |
109 | iounmap((void *)lubbock_maps[i].virt); | 109 | iounmap((void *)lubbock_maps[i].virt); |
110 | if (lubbock_maps[i].cached) | 110 | if (lubbock_maps[i].cached) |
@@ -124,7 +124,7 @@ static int __init init_lubbock(void) | |||
124 | 124 | ||
125 | if (!mymtds[0] && !mymtds[1]) | 125 | if (!mymtds[0] && !mymtds[1]) |
126 | return ret; | 126 | return ret; |
127 | 127 | ||
128 | for (i = 0; i < 2; i++) { | 128 | for (i = 0; i < 2; i++) { |
129 | if (!mymtds[i]) { | 129 | if (!mymtds[i]) { |
130 | printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); | 130 | printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); |
@@ -151,7 +151,7 @@ static void __exit cleanup_lubbock(void) | |||
151 | if (nr_parsed_parts[i] || !i) | 151 | if (nr_parsed_parts[i] || !i) |
152 | del_mtd_partitions(mymtds[i]); | 152 | del_mtd_partitions(mymtds[i]); |
153 | else | 153 | else |
154 | del_mtd_device(mymtds[i]); | 154 | del_mtd_device(mymtds[i]); |
155 | 155 | ||
156 | map_destroy(mymtds[i]); | 156 | map_destroy(mymtds[i]); |
157 | iounmap((void *)lubbock_maps[i].virt); | 157 | iounmap((void *)lubbock_maps[i].virt); |
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c index da0f8a692628..eaa4bbb868a3 100644 --- a/drivers/mtd/maps/mainstone-flash.c +++ b/drivers/mtd/maps/mainstone-flash.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Author: Nicolas Pitre | 6 | * Author: Nicolas Pitre |
7 | * Copyright: (C) 2001 MontaVista Software Inc. | 7 | * Copyright: (C) 2001 MontaVista Software Inc. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -91,27 +91,27 @@ static int __init init_mainstone(void) | |||
91 | mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys, | 91 | mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys, |
92 | WINDOW_SIZE); | 92 | WINDOW_SIZE); |
93 | if (!mainstone_maps[i].virt) { | 93 | if (!mainstone_maps[i].virt) { |
94 | printk(KERN_WARNING "Failed to ioremap %s\n", | 94 | printk(KERN_WARNING "Failed to ioremap %s\n", |
95 | mainstone_maps[i].name); | 95 | mainstone_maps[i].name); |
96 | if (!ret) | 96 | if (!ret) |
97 | ret = -ENOMEM; | 97 | ret = -ENOMEM; |
98 | continue; | 98 | continue; |
99 | } | 99 | } |
100 | mainstone_maps[i].cached = | 100 | mainstone_maps[i].cached = |
101 | ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE); | 101 | ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE); |
102 | if (!mainstone_maps[i].cached) | 102 | if (!mainstone_maps[i].cached) |
103 | printk(KERN_WARNING "Failed to ioremap cached %s\n", | 103 | printk(KERN_WARNING "Failed to ioremap cached %s\n", |
104 | mainstone_maps[i].name); | 104 | mainstone_maps[i].name); |
105 | simple_map_init(&mainstone_maps[i]); | 105 | simple_map_init(&mainstone_maps[i]); |
106 | 106 | ||
107 | printk(KERN_NOTICE | 107 | printk(KERN_NOTICE |
108 | "Probing %s at physical address 0x%08lx" | 108 | "Probing %s at physical address 0x%08lx" |
109 | " (%d-bit bankwidth)\n", | 109 | " (%d-bit bankwidth)\n", |
110 | mainstone_maps[i].name, mainstone_maps[i].phys, | 110 | mainstone_maps[i].name, mainstone_maps[i].phys, |
111 | mainstone_maps[i].bankwidth * 8); | 111 | mainstone_maps[i].bankwidth * 8); |
112 | 112 | ||
113 | mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]); | 113 | mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]); |
114 | 114 | ||
115 | if (!mymtds[i]) { | 115 | if (!mymtds[i]) { |
116 | iounmap((void *)mainstone_maps[i].virt); | 116 | iounmap((void *)mainstone_maps[i].virt); |
117 | if (mainstone_maps[i].cached) | 117 | if (mainstone_maps[i].cached) |
@@ -131,21 +131,21 @@ static int __init init_mainstone(void) | |||
131 | 131 | ||
132 | if (!mymtds[0] && !mymtds[1]) | 132 | if (!mymtds[0] && !mymtds[1]) |
133 | return ret; | 133 | return ret; |
134 | 134 | ||
135 | for (i = 0; i < 2; i++) { | 135 | for (i = 0; i < 2; i++) { |
136 | if (!mymtds[i]) { | 136 | if (!mymtds[i]) { |
137 | printk(KERN_WARNING "%s is absent. Skipping\n", | 137 | printk(KERN_WARNING "%s is absent. Skipping\n", |
138 | mainstone_maps[i].name); | 138 | mainstone_maps[i].name); |
139 | } else if (nr_parsed_parts[i]) { | 139 | } else if (nr_parsed_parts[i]) { |
140 | add_mtd_partitions(mymtds[i], parsed_parts[i], | 140 | add_mtd_partitions(mymtds[i], parsed_parts[i], |
141 | nr_parsed_parts[i]); | 141 | nr_parsed_parts[i]); |
142 | } else if (!i) { | 142 | } else if (!i) { |
143 | printk("Using static partitions on %s\n", | 143 | printk("Using static partitions on %s\n", |
144 | mainstone_maps[i].name); | 144 | mainstone_maps[i].name); |
145 | add_mtd_partitions(mymtds[i], mainstone_partitions, | 145 | add_mtd_partitions(mymtds[i], mainstone_partitions, |
146 | ARRAY_SIZE(mainstone_partitions)); | 146 | ARRAY_SIZE(mainstone_partitions)); |
147 | } else { | 147 | } else { |
148 | printk("Registering %s as whole device\n", | 148 | printk("Registering %s as whole device\n", |
149 | mainstone_maps[i].name); | 149 | mainstone_maps[i].name); |
150 | add_mtd_device(mymtds[i]); | 150 | add_mtd_device(mymtds[i]); |
151 | } | 151 | } |
diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c index c5c6901a4763..06b118727846 100644 --- a/drivers/mtd/maps/mbx860.c +++ b/drivers/mtd/maps/mbx860.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mbx860.c,v 1.8 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: mbx860.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Handle mapping of the flash on MBX860 boards | 4 | * Handle mapping of the flash on MBX860 boards |
5 | * | 5 | * |
6 | * Author: Anton Todorov | 6 | * Author: Anton Todorov |
7 | * Copyright: (C) 2001 Emness Technology | 7 | * Copyright: (C) 2001 Emness Technology |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
@@ -46,7 +46,7 @@ static struct mtd_partition partition_info[]={ | |||
46 | { .name = "MBX flash APPLICATION partition", | 46 | { .name = "MBX flash APPLICATION partition", |
47 | .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } | 47 | .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } |
48 | }; | 48 | }; |
49 | 49 | ||
50 | 50 | ||
51 | static struct mtd_info *mymtd; | 51 | static struct mtd_info *mymtd; |
52 | 52 | ||
diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c new file mode 100644 index 000000000000..d1e66e186746 --- /dev/null +++ b/drivers/mtd/maps/mtx-1_flash.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Flash memory access on 4G Systems MTX-1 boards | ||
3 | * | ||
4 | * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $ | ||
5 | * | ||
6 | * (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz> | ||
7 | * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de> | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/kernel.h> | ||
16 | |||
17 | #include <linux/mtd/mtd.h> | ||
18 | #include <linux/mtd/map.h> | ||
19 | #include <linux/mtd/partitions.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | |||
23 | static struct map_info mtx1_map = { | ||
24 | .name = "MTX-1 flash", | ||
25 | .bankwidth = 4, | ||
26 | .size = 0x2000000, | ||
27 | .phys = 0x1E000000, | ||
28 | }; | ||
29 | |||
30 | static struct mtd_partition mtx1_partitions[] = { | ||
31 | { | ||
32 | .name = "filesystem", | ||
33 | .size = 0x01C00000, | ||
34 | .offset = 0, | ||
35 | },{ | ||
36 | .name = "yamon", | ||
37 | .size = 0x00100000, | ||
38 | .offset = MTDPART_OFS_APPEND, | ||
39 | .mask_flags = MTD_WRITEABLE, | ||
40 | },{ | ||
41 | .name = "kernel", | ||
42 | .size = 0x002c0000, | ||
43 | .offset = MTDPART_OFS_APPEND, | ||
44 | },{ | ||
45 | .name = "yamon env", | ||
46 | .size = 0x00040000, | ||
47 | .offset = MTDPART_OFS_APPEND, | ||
48 | } | ||
49 | }; | ||
50 | |||
51 | static struct mtd_info *mtx1_mtd; | ||
52 | |||
53 | int __init mtx1_mtd_init(void) | ||
54 | { | ||
55 | int ret = -ENXIO; | ||
56 | |||
57 | simple_map_init(&mtx1_map); | ||
58 | |||
59 | mtx1_map.virt = ioremap(mtx1_map.phys, mtx1_map.size); | ||
60 | if (!mtx1_map.virt) | ||
61 | return -EIO; | ||
62 | |||
63 | mtx1_mtd = do_map_probe("cfi_probe", &mtx1_map); | ||
64 | if (!mtx1_mtd) | ||
65 | goto err; | ||
66 | |||
67 | mtx1_mtd->owner = THIS_MODULE; | ||
68 | |||
69 | ret = add_mtd_partitions(mtx1_mtd, mtx1_partitions, | ||
70 | ARRAY_SIZE(mtx1_partitions)); | ||
71 | if (ret) | ||
72 | goto err; | ||
73 | |||
74 | return 0; | ||
75 | |||
76 | err: | ||
77 | iounmap(mtx1_map.virt); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | static void __exit mtx1_mtd_cleanup(void) | ||
82 | { | ||
83 | if (mtx1_mtd) { | ||
84 | del_mtd_partitions(mtx1_mtd); | ||
85 | map_destroy(mtx1_mtd); | ||
86 | } | ||
87 | if (mtx1_map.virt) | ||
88 | iounmap(mtx1_map.virt); | ||
89 | } | ||
90 | |||
91 | module_init(mtx1_mtd_init); | ||
92 | module_exit(mtx1_mtd_cleanup); | ||
93 | |||
94 | MODULE_AUTHOR("Bruno Randolf <bruno.randolf@4g-systems.biz>"); | ||
95 | MODULE_DESCRIPTION("MTX-1 flash map"); | ||
96 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index ab7e6358d281..33060a315722 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) | 3 | * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) |
4 | * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH | 4 | * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH |
5 | * | 5 | * |
6 | * $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 Exp $ | 6 | * $Id: netsc520.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -38,7 +38,7 @@ | |||
38 | ** The single, 16 megabyte flash bank is divided into four virtual | 38 | ** The single, 16 megabyte flash bank is divided into four virtual |
39 | ** partitions. The first partition is 768 KiB and is intended to | 39 | ** partitions. The first partition is 768 KiB and is intended to |
40 | ** store the kernel image loaded by the bootstrap loader. The second | 40 | ** store the kernel image loaded by the bootstrap loader. The second |
41 | ** partition is 256 KiB and holds the BIOS image. The third | 41 | ** partition is 256 KiB and holds the BIOS image. The third |
42 | ** partition is 14.5 MiB and is intended for the flash file system | 42 | ** partition is 14.5 MiB and is intended for the flash file system |
43 | ** image. The last partition is 512 KiB and contains another copy | 43 | ** image. The last partition is 512 KiB and contains another copy |
44 | ** of the BIOS image and the reset vector. | 44 | ** of the BIOS image and the reset vector. |
@@ -51,28 +51,28 @@ | |||
51 | ** recoverable afterwards. | 51 | ** recoverable afterwards. |
52 | */ | 52 | */ |
53 | 53 | ||
54 | /* partition_info gives details on the logical partitions that the split the | 54 | /* partition_info gives details on the logical partitions that the split the |
55 | * single flash device into. If the size if zero we use up to the end of the | 55 | * single flash device into. If the size if zero we use up to the end of the |
56 | * device. */ | 56 | * device. */ |
57 | static struct mtd_partition partition_info[]={ | 57 | static struct mtd_partition partition_info[]={ |
58 | { | 58 | { |
59 | .name = "NetSc520 boot kernel", | 59 | .name = "NetSc520 boot kernel", |
60 | .offset = 0, | 60 | .offset = 0, |
61 | .size = 0xc0000 | 61 | .size = 0xc0000 |
62 | }, | 62 | }, |
63 | { | 63 | { |
64 | .name = "NetSc520 Low BIOS", | 64 | .name = "NetSc520 Low BIOS", |
65 | .offset = 0xc0000, | 65 | .offset = 0xc0000, |
66 | .size = 0x40000 | 66 | .size = 0x40000 |
67 | }, | 67 | }, |
68 | { | 68 | { |
69 | .name = "NetSc520 file system", | 69 | .name = "NetSc520 file system", |
70 | .offset = 0x100000, | 70 | .offset = 0x100000, |
71 | .size = 0xe80000 | 71 | .size = 0xe80000 |
72 | }, | 72 | }, |
73 | { | 73 | { |
74 | .name = "NetSc520 High BIOS", | 74 | .name = "NetSc520 High BIOS", |
75 | .offset = 0xf80000, | 75 | .offset = 0xf80000, |
76 | .size = 0x80000 | 76 | .size = 0x80000 |
77 | }, | 77 | }, |
78 | }; | 78 | }; |
@@ -114,7 +114,7 @@ static int __init init_netsc520(void) | |||
114 | iounmap(netsc520_map.virt); | 114 | iounmap(netsc520_map.virt); |
115 | return -ENXIO; | 115 | return -ENXIO; |
116 | } | 116 | } |
117 | 117 | ||
118 | mymtd->owner = THIS_MODULE; | 118 | mymtd->owner = THIS_MODULE; |
119 | add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS ); | 119 | add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS ); |
120 | return 0; | 120 | return 0; |
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 61be5a4148c9..f00ee7e54dba 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) | 6 | * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) |
7 | * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) | 7 | * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) |
8 | * | 8 | * |
9 | * $Id: nettel.c,v 1.10 2005/01/05 17:11:29 dwmw2 Exp $ | 9 | * $Id: nettel.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $ |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /****************************************************************************/ | 12 | /****************************************************************************/ |
@@ -143,7 +143,7 @@ static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, | |||
143 | { | 143 | { |
144 | struct cfi_private *cfi = nettel_intel_map.fldrv_priv; | 144 | struct cfi_private *cfi = nettel_intel_map.fldrv_priv; |
145 | unsigned long b; | 145 | unsigned long b; |
146 | 146 | ||
147 | /* Make sure all FLASH chips are put back into read mode */ | 147 | /* Make sure all FLASH chips are put back into read mode */ |
148 | for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) { | 148 | for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) { |
149 | cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi, | 149 | cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi, |
@@ -199,7 +199,7 @@ int nettel_eraseconfig(void) | |||
199 | 199 | ||
200 | schedule(); /* Wait for erase to finish. */ | 200 | schedule(); /* Wait for erase to finish. */ |
201 | remove_wait_queue(&wait_q, &wait); | 201 | remove_wait_queue(&wait_q, &wait); |
202 | 202 | ||
203 | put_mtd_device(mtd); | 203 | put_mtd_device(mtd); |
204 | } | 204 | } |
205 | 205 | ||
@@ -430,7 +430,7 @@ int __init nettel_init(void) | |||
430 | nettel_intel_partitions[1].size = (intel0size + intel1size) - | 430 | nettel_intel_partitions[1].size = (intel0size + intel1size) - |
431 | (1024*1024 + intel_mtd->erasesize); | 431 | (1024*1024 + intel_mtd->erasesize); |
432 | nettel_intel_partitions[3].size = intel0size + intel1size; | 432 | nettel_intel_partitions[3].size = intel0size + intel1size; |
433 | nettel_intel_partitions[4].offset = | 433 | nettel_intel_partitions[4].offset = |
434 | (intel0size + intel1size) - intel_mtd->erasesize; | 434 | (intel0size + intel1size) - intel_mtd->erasesize; |
435 | nettel_intel_partitions[4].size = intel_mtd->erasesize; | 435 | nettel_intel_partitions[4].size = intel_mtd->erasesize; |
436 | nettel_intel_partitions[5].offset = | 436 | nettel_intel_partitions[5].offset = |
diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c index 82c3070678c5..6977963d7897 100644 --- a/drivers/mtd/maps/ocelot.c +++ b/drivers/mtd/maps/ocelot.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ocelot.c,v 1.16 2005/01/05 18:05:13 dwmw2 Exp $ | 2 | * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $ |
3 | * | 3 | * |
4 | * Flash on Momenco Ocelot | 4 | * Flash on Momenco Ocelot |
5 | */ | 5 | */ |
@@ -31,7 +31,7 @@ static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t | |||
31 | struct map_info *map = mtd->priv; | 31 | struct map_info *map = mtd->priv; |
32 | size_t done = 0; | 32 | size_t done = 0; |
33 | 33 | ||
34 | /* If we use memcpy, it does word-wide writes. Even though we told the | 34 | /* If we use memcpy, it does word-wide writes. Even though we told the |
35 | GT64120A that it's an 8-bit wide region, word-wide writes don't work. | 35 | GT64120A that it's an 8-bit wide region, word-wide writes don't work. |
36 | We end up just writing the first byte of the four to all four bytes. | 36 | We end up just writing the first byte of the four to all four bytes. |
37 | So we have this loop instead */ | 37 | So we have this loop instead */ |
@@ -68,7 +68,7 @@ static int __init init_ocelot_maps(void) | |||
68 | int nr_parts; | 68 | int nr_parts; |
69 | unsigned char brd_status; | 69 | unsigned char brd_status; |
70 | 70 | ||
71 | printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", | 71 | printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", |
72 | FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR); | 72 | FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR); |
73 | 73 | ||
74 | /* First check whether the flash jumper is present */ | 74 | /* First check whether the flash jumper is present */ |
@@ -138,8 +138,8 @@ static int __init init_ocelot_maps(void) | |||
138 | add_mtd_device(flash_mtd); | 138 | add_mtd_device(flash_mtd); |
139 | 139 | ||
140 | return 0; | 140 | return 0; |
141 | 141 | ||
142 | fail3: | 142 | fail3: |
143 | iounmap((void *)ocelot_flash_map.virt); | 143 | iounmap((void *)ocelot_flash_map.virt); |
144 | if (ocelot_flash_map.cached) | 144 | if (ocelot_flash_map.cached) |
145 | iounmap((void *)ocelot_flash_map.cached); | 145 | iounmap((void *)ocelot_flash_map.cached); |
diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c index e5ff83de420e..a6642db3d325 100644 --- a/drivers/mtd/maps/octagon-5066.c +++ b/drivers/mtd/maps/octagon-5066.c | |||
@@ -1,12 +1,12 @@ | |||
1 | // $Id: octagon-5066.c,v 1.26 2004/07/12 22:38:29 dwmw2 Exp $ | 1 | // $Id: octagon-5066.c,v 1.28 2005/11/07 11:14:27 gleixner Exp $ |
2 | /* ###################################################################### | 2 | /* ###################################################################### |
3 | 3 | ||
4 | Octagon 5066 MTD Driver. | 4 | Octagon 5066 MTD Driver. |
5 | 5 | ||
6 | The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It | 6 | The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It |
7 | comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that | 7 | comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that |
8 | is replacable by flash. Both units are mapped through a multiplexer | 8 | is replacable by flash. Both units are mapped through a multiplexer |
9 | into a 32k memory window at 0xe8000. The control register for the | 9 | into a 32k memory window at 0xe8000. The control register for the |
10 | multiplexing unit is located at IO 0x208 with a bit map of | 10 | multiplexing unit is located at IO 0x208 with a bit map of |
11 | 0-5 Page Selection in 32k increments | 11 | 0-5 Page Selection in 32k increments |
12 | 6-7 Device selection: | 12 | 6-7 Device selection: |
@@ -14,14 +14,14 @@ | |||
14 | 01 SSD 0 (Socket) | 14 | 01 SSD 0 (Socket) |
15 | 10 SSD 1 (Flash chip) | 15 | 10 SSD 1 (Flash chip) |
16 | 11 undefined | 16 | 11 undefined |
17 | 17 | ||
18 | On each SSD, the first 128k is reserved for use by the bios | 18 | On each SSD, the first 128k is reserved for use by the bios |
19 | (actually it IS the bios..) This only matters if you are booting off the | 19 | (actually it IS the bios..) This only matters if you are booting off the |
20 | flash, you must not put a file system starting there. | 20 | flash, you must not put a file system starting there. |
21 | 21 | ||
22 | The driver tries to do a detection algorithm to guess what sort of devices | 22 | The driver tries to do a detection algorithm to guess what sort of devices |
23 | are plugged into the sockets. | 23 | are plugged into the sockets. |
24 | 24 | ||
25 | ##################################################################### */ | 25 | ##################################################################### */ |
26 | 26 | ||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
@@ -56,7 +56,7 @@ static void __oct5066_page(struct map_info *map, __u8 byte) | |||
56 | static inline void oct5066_page(struct map_info *map, unsigned long ofs) | 56 | static inline void oct5066_page(struct map_info *map, unsigned long ofs) |
57 | { | 57 | { |
58 | __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT); | 58 | __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT); |
59 | 59 | ||
60 | if (page_n_dev != byte) | 60 | if (page_n_dev != byte) |
61 | __oct5066_page(map, byte); | 61 | __oct5066_page(map, byte); |
62 | } | 62 | } |
@@ -78,7 +78,7 @@ static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from | |||
78 | unsigned long thislen = len; | 78 | unsigned long thislen = len; |
79 | if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) | 79 | if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) |
80 | thislen = WINDOW_LENGTH-(from & WINDOW_MASK); | 80 | thislen = WINDOW_LENGTH-(from & WINDOW_MASK); |
81 | 81 | ||
82 | spin_lock(&oct5066_spin); | 82 | spin_lock(&oct5066_spin); |
83 | oct5066_page(map, from); | 83 | oct5066_page(map, from); |
84 | memcpy_fromio(to, iomapadr + from, thislen); | 84 | memcpy_fromio(to, iomapadr + from, thislen); |
@@ -103,7 +103,7 @@ static void oct5066_copy_to(struct map_info *map, unsigned long to, const void * | |||
103 | unsigned long thislen = len; | 103 | unsigned long thislen = len; |
104 | if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) | 104 | if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) |
105 | thislen = WINDOW_LENGTH-(to & WINDOW_MASK); | 105 | thislen = WINDOW_LENGTH-(to & WINDOW_MASK); |
106 | 106 | ||
107 | spin_lock(&oct5066_spin); | 107 | spin_lock(&oct5066_spin); |
108 | oct5066_page(map, to); | 108 | oct5066_page(map, to); |
109 | memcpy_toio(iomapadr + to, from, thislen); | 109 | memcpy_toio(iomapadr + to, from, thislen); |
@@ -144,7 +144,7 @@ static struct mtd_info *oct5066_mtd[2] = {NULL, NULL}; | |||
144 | // OctProbe - Sense if this is an octagon card | 144 | // OctProbe - Sense if this is an octagon card |
145 | // --------------------------------------------------------------------- | 145 | // --------------------------------------------------------------------- |
146 | /* Perform a simple validity test, we map the window select SSD0 and | 146 | /* Perform a simple validity test, we map the window select SSD0 and |
147 | change pages while monitoring the window. A change in the window, | 147 | change pages while monitoring the window. A change in the window, |
148 | controlled by the PAGE_IO port is a functioning 5066 board. This will | 148 | controlled by the PAGE_IO port is a functioning 5066 board. This will |
149 | fail if the thing in the socket is set to a uniform value. */ | 149 | fail if the thing in the socket is set to a uniform value. */ |
150 | static int __init OctProbe(void) | 150 | static int __init OctProbe(void) |
@@ -161,13 +161,13 @@ static int __init OctProbe(void) | |||
161 | Values[I%10] = readl(iomapadr); | 161 | Values[I%10] = readl(iomapadr); |
162 | if (I > 0 && Values[I%10] == Values[0]) | 162 | if (I > 0 && Values[I%10] == Values[0]) |
163 | return -EAGAIN; | 163 | return -EAGAIN; |
164 | } | 164 | } |
165 | else | 165 | else |
166 | { | 166 | { |
167 | // Make sure we get the same values on the second pass | 167 | // Make sure we get the same values on the second pass |
168 | if (Values[I%10] != readl(iomapadr)) | 168 | if (Values[I%10] != readl(iomapadr)) |
169 | return -EAGAIN; | 169 | return -EAGAIN; |
170 | } | 170 | } |
171 | } | 171 | } |
172 | return 0; | 172 | return 0; |
173 | } | 173 | } |
@@ -207,11 +207,11 @@ int __init init_oct5066(void) | |||
207 | ret = -EAGAIN; | 207 | ret = -EAGAIN; |
208 | goto out_unmap; | 208 | goto out_unmap; |
209 | } | 209 | } |
210 | 210 | ||
211 | // Print out our little header.. | 211 | // Print out our little header.. |
212 | printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START, | 212 | printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START, |
213 | WINDOW_START+WINDOW_LENGTH); | 213 | WINDOW_START+WINDOW_LENGTH); |
214 | 214 | ||
215 | for (i=0; i<2; i++) { | 215 | for (i=0; i<2; i++) { |
216 | oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]); | 216 | oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]); |
217 | if (!oct5066_mtd[i]) | 217 | if (!oct5066_mtd[i]) |
@@ -225,11 +225,11 @@ int __init init_oct5066(void) | |||
225 | add_mtd_device(oct5066_mtd[i]); | 225 | add_mtd_device(oct5066_mtd[i]); |
226 | } | 226 | } |
227 | } | 227 | } |
228 | 228 | ||
229 | if (!oct5066_mtd[0] && !oct5066_mtd[1]) { | 229 | if (!oct5066_mtd[0] && !oct5066_mtd[1]) { |
230 | cleanup_oct5066(); | 230 | cleanup_oct5066(); |
231 | return -ENXIO; | 231 | return -ENXIO; |
232 | } | 232 | } |
233 | 233 | ||
234 | return 0; | 234 | return 0; |
235 | 235 | ||
diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c index 763304154a92..dc3765270057 100644 --- a/drivers/mtd/maps/omap-toto-flash.c +++ b/drivers/mtd/maps/omap-toto-flash.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * (C) 2002 MontVista Software, Inc. | 6 | * (C) 2002 MontVista Software, Inc. |
7 | * | 7 | * |
8 | * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $ | 8 | * $Id: omap-toto-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
@@ -38,7 +38,7 @@ static struct map_info omap_toto_map_flash = { | |||
38 | .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE, | 38 | .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | 41 | ||
42 | static struct mtd_partition toto_flash_partitions[] = { | 42 | static struct mtd_partition toto_flash_partitions[] = { |
43 | { | 43 | { |
44 | .name = "BootLoader", | 44 | .name = "BootLoader", |
@@ -54,21 +54,21 @@ static struct mtd_partition toto_flash_partitions[] = { | |||
54 | .name = "EnvArea", /* bottom 64KiB for env vars */ | 54 | .name = "EnvArea", /* bottom 64KiB for env vars */ |
55 | .size = MTDPART_SIZ_FULL, | 55 | .size = MTDPART_SIZ_FULL, |
56 | .offset = MTDPART_OFS_APPEND, | 56 | .offset = MTDPART_OFS_APPEND, |
57 | } | 57 | } |
58 | }; | 58 | }; |
59 | 59 | ||
60 | static struct mtd_partition *parsed_parts; | 60 | static struct mtd_partition *parsed_parts; |
61 | 61 | ||
62 | static struct mtd_info *flash_mtd; | 62 | static struct mtd_info *flash_mtd; |
63 | 63 | ||
64 | static int __init init_flash (void) | 64 | static int __init init_flash (void) |
65 | { | 65 | { |
66 | 66 | ||
67 | struct mtd_partition *parts; | 67 | struct mtd_partition *parts; |
68 | int nb_parts = 0; | 68 | int nb_parts = 0; |
69 | int parsed_nr_parts = 0; | 69 | int parsed_nr_parts = 0; |
70 | const char *part_type; | 70 | const char *part_type; |
71 | 71 | ||
72 | /* | 72 | /* |
73 | * Static partition definition selection | 73 | * Static partition definition selection |
74 | */ | 74 | */ |
@@ -89,7 +89,7 @@ static int __init init_flash (void) | |||
89 | flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); | 89 | flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); |
90 | if (!flash_mtd) | 90 | if (!flash_mtd) |
91 | return -ENXIO; | 91 | return -ENXIO; |
92 | 92 | ||
93 | if (parsed_nr_parts > 0) { | 93 | if (parsed_nr_parts > 0) { |
94 | parts = parsed_parts; | 94 | parts = parsed_parts; |
95 | nb_parts = parsed_nr_parts; | 95 | nb_parts = parsed_nr_parts; |
@@ -108,8 +108,8 @@ static int __init init_flash (void) | |||
108 | } | 108 | } |
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | int __init omap_toto_mtd_init(void) | 112 | int __init omap_toto_mtd_init(void) |
113 | { | 113 | { |
114 | int status; | 114 | int status; |
115 | 115 | ||
@@ -119,7 +119,7 @@ int __init omap_toto_mtd_init(void) | |||
119 | return status; | 119 | return status; |
120 | } | 120 | } |
121 | 121 | ||
122 | static void __exit omap_toto_mtd_cleanup(void) | 122 | static void __exit omap_toto_mtd_cleanup(void) |
123 | { | 123 | { |
124 | if (flash_mtd) { | 124 | if (flash_mtd) { |
125 | del_mtd_partitions(flash_mtd); | 125 | del_mtd_partitions(flash_mtd); |
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index 7f370bb794fe..fd3b4a5fc207 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2001-2002 MontaVista Software Inc. | 4 | * Copyright (C) 2001-2002 MontaVista Software Inc. |
5 | * Copyright (C) 2003-2004 Texas Instruments | 5 | * Copyright (C) 2003-2004 Texas Instruments |
6 | * Copyright (C) 2004 Nokia Corporation | 6 | * Copyright (C) 2004 Nokia Corporation |
7 | * | 7 | * |
8 | * Assembled using driver code copyright the companies above | 8 | * Assembled using driver code copyright the companies above |
9 | * and written by David Brownell, Jian Zhang <jzhang@ti.com>, | 9 | * and written by David Brownell, Jian Zhang <jzhang@ti.com>, |
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index d9c64e99ee32..8b3570b09095 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c | |||
@@ -7,8 +7,8 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $ | 10 | * $Id: pci.c,v 1.13 2005/11/07 11:14:27 gleixner Exp $ |
11 | * | 11 | * |
12 | * Generic PCI memory map driver. We support the following boards: | 12 | * Generic PCI memory map driver. We support the following boards: |
13 | * - Intel IQ80310 ATU. | 13 | * - Intel IQ80310 ATU. |
14 | * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 | 14 | * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 |
@@ -38,7 +38,7 @@ struct map_pci_info { | |||
38 | void (*exit)(struct pci_dev *dev, struct map_pci_info *map); | 38 | void (*exit)(struct pci_dev *dev, struct map_pci_info *map); |
39 | unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); | 39 | unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); |
40 | struct pci_dev *dev; | 40 | struct pci_dev *dev; |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs) | 43 | static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs) |
44 | { | 44 | { |
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index ff7c50d10180..af24216a0626 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: pcmciamtd.c,v 1.51 2004/07/12 22:38:29 dwmw2 Exp $ | 2 | * $Id: pcmciamtd.c,v 1.55 2005/11/07 11:14:28 gleixner Exp $ |
3 | * | 3 | * |
4 | * pcmciamtd.c - MTD driver for PCMCIA flash memory cards | 4 | * pcmciamtd.c - MTD driver for PCMCIA flash memory cards |
5 | * | 5 | * |
@@ -48,7 +48,7 @@ static const int debug = 0; | |||
48 | 48 | ||
49 | 49 | ||
50 | #define DRIVER_DESC "PCMCIA Flash memory card driver" | 50 | #define DRIVER_DESC "PCMCIA Flash memory card driver" |
51 | #define DRIVER_VERSION "$Revision: 1.51 $" | 51 | #define DRIVER_VERSION "$Revision: 1.55 $" |
52 | 52 | ||
53 | /* Size of the PCMCIA address space: 26 bits = 64 MB */ | 53 | /* Size of the PCMCIA address space: 26 bits = 64 MB */ |
54 | #define MAX_PCMCIA_ADDR 0x4000000 | 54 | #define MAX_PCMCIA_ADDR 0x4000000 |
@@ -176,7 +176,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long | |||
176 | 176 | ||
177 | if(toread > len) | 177 | if(toread > len) |
178 | toread = len; | 178 | toread = len; |
179 | 179 | ||
180 | addr = remap_window(map, from); | 180 | addr = remap_window(map, from); |
181 | if(!addr) | 181 | if(!addr) |
182 | return; | 182 | return; |
@@ -386,7 +386,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
386 | cs_error(link->handle, ParseTuple, rc); | 386 | cs_error(link->handle, ParseTuple, rc); |
387 | break; | 387 | break; |
388 | } | 388 | } |
389 | 389 | ||
390 | switch(tuple.TupleCode) { | 390 | switch(tuple.TupleCode) { |
391 | case CISTPL_FORMAT: { | 391 | case CISTPL_FORMAT: { |
392 | cistpl_format_t *t = &parse.format; | 392 | cistpl_format_t *t = &parse.format; |
@@ -394,9 +394,9 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
394 | DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", | 394 | DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", |
395 | t->type, t->edc, t->offset, t->length); | 395 | t->type, t->edc, t->offset, t->length); |
396 | break; | 396 | break; |
397 | 397 | ||
398 | } | 398 | } |
399 | 399 | ||
400 | case CISTPL_DEVICE: { | 400 | case CISTPL_DEVICE: { |
401 | cistpl_device_t *t = &parse.device; | 401 | cistpl_device_t *t = &parse.device; |
402 | int i; | 402 | int i; |
@@ -410,7 +410,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
410 | } | 410 | } |
411 | break; | 411 | break; |
412 | } | 412 | } |
413 | 413 | ||
414 | case CISTPL_VERS_1: { | 414 | case CISTPL_VERS_1: { |
415 | cistpl_vers_1_t *t = &parse.version_1; | 415 | cistpl_vers_1_t *t = &parse.version_1; |
416 | int i; | 416 | int i; |
@@ -425,7 +425,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
425 | DEBUG(2, "Found name: %s", dev->mtd_name); | 425 | DEBUG(2, "Found name: %s", dev->mtd_name); |
426 | break; | 426 | break; |
427 | } | 427 | } |
428 | 428 | ||
429 | case CISTPL_JEDEC_C: { | 429 | case CISTPL_JEDEC_C: { |
430 | cistpl_jedec_t *t = &parse.jedec; | 430 | cistpl_jedec_t *t = &parse.jedec; |
431 | int i; | 431 | int i; |
@@ -434,7 +434,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
434 | } | 434 | } |
435 | break; | 435 | break; |
436 | } | 436 | } |
437 | 437 | ||
438 | case CISTPL_DEVICE_GEO: { | 438 | case CISTPL_DEVICE_GEO: { |
439 | cistpl_device_geo_t *t = &parse.device_geo; | 439 | cistpl_device_geo_t *t = &parse.device_geo; |
440 | int i; | 440 | int i; |
@@ -449,11 +449,11 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
449 | } | 449 | } |
450 | break; | 450 | break; |
451 | } | 451 | } |
452 | 452 | ||
453 | default: | 453 | default: |
454 | DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); | 454 | DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); |
455 | } | 455 | } |
456 | 456 | ||
457 | rc = pcmcia_get_next_tuple(link->handle, &tuple); | 457 | rc = pcmcia_get_next_tuple(link->handle, &tuple); |
458 | } | 458 | } |
459 | if(!dev->pcmcia_map.size) | 459 | if(!dev->pcmcia_map.size) |
@@ -470,7 +470,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ | |||
470 | if(bankwidth) { | 470 | if(bankwidth) { |
471 | dev->pcmcia_map.bankwidth = bankwidth; | 471 | dev->pcmcia_map.bankwidth = bankwidth; |
472 | DEBUG(2, "bankwidth forced to %d", bankwidth); | 472 | DEBUG(2, "bankwidth forced to %d", bankwidth); |
473 | } | 473 | } |
474 | 474 | ||
475 | dev->pcmcia_map.name = dev->mtd_name; | 475 | dev->pcmcia_map.name = dev->mtd_name; |
476 | if(!dev->mtd_name[0]) { | 476 | if(!dev->mtd_name[0]) { |
@@ -568,7 +568,7 @@ static void pcmciamtd_config(dev_link_t *link) | |||
568 | return; | 568 | return; |
569 | } | 569 | } |
570 | DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); | 570 | DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); |
571 | 571 | ||
572 | /* Get write protect status */ | 572 | /* Get write protect status */ |
573 | CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status)); | 573 | CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status)); |
574 | DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", | 574 | DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", |
@@ -624,11 +624,11 @@ static void pcmciamtd_config(dev_link_t *link) | |||
624 | mtd = do_map_probe(probes[i], &dev->pcmcia_map); | 624 | mtd = do_map_probe(probes[i], &dev->pcmcia_map); |
625 | if(mtd) | 625 | if(mtd) |
626 | break; | 626 | break; |
627 | 627 | ||
628 | DEBUG(1, "FAILED: %s", probes[i]); | 628 | DEBUG(1, "FAILED: %s", probes[i]); |
629 | } | 629 | } |
630 | } | 630 | } |
631 | 631 | ||
632 | if(!mtd) { | 632 | if(!mtd) { |
633 | DEBUG(1, "Cant find an MTD"); | 633 | DEBUG(1, "Cant find an MTD"); |
634 | pcmciamtd_release(link); | 634 | pcmciamtd_release(link); |
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index b853670bfb81..9ee760f97bc6 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $ | 2 | * $Id: physmap.c,v 1.38 2005/11/07 11:14:28 gleixner Exp $ |
3 | * | 3 | * |
4 | * Normal mappings of chips in physical memory | 4 | * Normal mappings of chips in physical memory |
5 | * | 5 | * |
@@ -69,7 +69,7 @@ static int __init init_physmap(void) | |||
69 | mymtd->owner = THIS_MODULE; | 69 | mymtd->owner = THIS_MODULE; |
70 | 70 | ||
71 | #ifdef CONFIG_MTD_PARTITIONS | 71 | #ifdef CONFIG_MTD_PARTITIONS |
72 | mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, | 72 | mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, |
73 | &mtd_parts, 0); | 73 | &mtd_parts, 0); |
74 | 74 | ||
75 | if (mtd_parts_nb > 0) | 75 | if (mtd_parts_nb > 0) |
@@ -78,9 +78,9 @@ static int __init init_physmap(void) | |||
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
80 | 80 | ||
81 | if (num_physmap_partitions != 0) | 81 | if (num_physmap_partitions != 0) |
82 | { | 82 | { |
83 | printk(KERN_NOTICE | 83 | printk(KERN_NOTICE |
84 | "Using physmap partition definition\n"); | 84 | "Using physmap partition definition\n"); |
85 | add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions); | 85 | add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions); |
86 | return 0; | 86 | return 0; |
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 104576b5be34..a02eed94a231 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Generic platfrom device based RAM map | 7 | * Generic platfrom device based RAM map |
8 | * | 8 | * |
9 | * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $ | 9 | * $Id: plat-ram.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -91,7 +91,7 @@ static int platram_remove(struct device *dev) | |||
91 | 91 | ||
92 | dev_dbg(dev, "removing device\n"); | 92 | dev_dbg(dev, "removing device\n"); |
93 | 93 | ||
94 | if (info == NULL) | 94 | if (info == NULL) |
95 | return 0; | 95 | return 0; |
96 | 96 | ||
97 | if (info->mtd) { | 97 | if (info->mtd) { |
@@ -118,7 +118,7 @@ static int platram_remove(struct device *dev) | |||
118 | 118 | ||
119 | if (info->map.virt != NULL) | 119 | if (info->map.virt != NULL) |
120 | iounmap(info->map.virt); | 120 | iounmap(info->map.virt); |
121 | 121 | ||
122 | kfree(info); | 122 | kfree(info); |
123 | 123 | ||
124 | return 0; | 124 | return 0; |
@@ -139,7 +139,7 @@ static int platram_probe(struct device *dev) | |||
139 | int err = 0; | 139 | int err = 0; |
140 | 140 | ||
141 | dev_dbg(dev, "probe entered\n"); | 141 | dev_dbg(dev, "probe entered\n"); |
142 | 142 | ||
143 | if (dev->platform_data == NULL) { | 143 | if (dev->platform_data == NULL) { |
144 | dev_err(dev, "no platform data supplied\n"); | 144 | dev_err(dev, "no platform data supplied\n"); |
145 | err = -ENOENT; | 145 | err = -ENOENT; |
@@ -177,7 +177,7 @@ static int platram_probe(struct device *dev) | |||
177 | 177 | ||
178 | info->map.phys = res->start; | 178 | info->map.phys = res->start; |
179 | info->map.size = (res->end - res->start) + 1; | 179 | info->map.size = (res->end - res->start) + 1; |
180 | info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name; | 180 | info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pd->name; |
181 | info->map.bankwidth = pdata->bankwidth; | 181 | info->map.bankwidth = pdata->bankwidth; |
182 | 182 | ||
183 | /* register our usage of the memory area */ | 183 | /* register our usage of the memory area */ |
@@ -240,7 +240,7 @@ static int platram_probe(struct device *dev) | |||
240 | dev_err(dev, "add_mtd_device() failed\n"); | 240 | dev_err(dev, "add_mtd_device() failed\n"); |
241 | err = -ENOMEM; | 241 | err = -ENOMEM; |
242 | } | 242 | } |
243 | 243 | ||
244 | dev_info(dev, "registered mtd device\n"); | 244 | dev_info(dev, "registered mtd device\n"); |
245 | return err; | 245 | return err; |
246 | 246 | ||
@@ -254,6 +254,7 @@ static int platram_probe(struct device *dev) | |||
254 | 254 | ||
255 | static struct device_driver platram_driver = { | 255 | static struct device_driver platram_driver = { |
256 | .name = "mtd-ram", | 256 | .name = "mtd-ram", |
257 | .owner = THIS_MODULE, | ||
257 | .bus = &platform_bus_type, | 258 | .bus = &platform_bus_type, |
258 | .probe = platram_probe, | 259 | .probe = platram_probe, |
259 | .remove = platram_remove, | 260 | .remove = platram_remove, |
diff --git a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c index a0f43dad8985..d7e16c2d5c44 100644 --- a/drivers/mtd/maps/pnc2000.c +++ b/drivers/mtd/maps/pnc2000.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * This code is GPL | 6 | * This code is GPL |
7 | * | 7 | * |
8 | * $Id: pnc2000.c,v 1.17 2004/11/16 18:29:02 dwmw2 Exp $ | 8 | * $Id: pnc2000.c,v 1.18 2005/11/07 11:14:28 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
@@ -21,7 +21,7 @@ | |||
21 | #define WINDOW_ADDR 0xbf000000 | 21 | #define WINDOW_ADDR 0xbf000000 |
22 | #define WINDOW_SIZE 0x00400000 | 22 | #define WINDOW_SIZE 0x00400000 |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * MAP DRIVER STUFF | 25 | * MAP DRIVER STUFF |
26 | */ | 26 | */ |
27 | 27 | ||
@@ -36,7 +36,7 @@ static struct map_info pnc_map = { | |||
36 | 36 | ||
37 | 37 | ||
38 | /* | 38 | /* |
39 | * MTD 'PARTITIONING' STUFF | 39 | * MTD 'PARTITIONING' STUFF |
40 | */ | 40 | */ |
41 | static struct mtd_partition pnc_partitions[3] = { | 41 | static struct mtd_partition pnc_partitions[3] = { |
42 | { | 42 | { |
@@ -56,7 +56,7 @@ static struct mtd_partition pnc_partitions[3] = { | |||
56 | } | 56 | } |
57 | }; | 57 | }; |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * This is the master MTD device for which all the others are just | 60 | * This is the master MTD device for which all the others are just |
61 | * auto-relocating aliases. | 61 | * auto-relocating aliases. |
62 | */ | 62 | */ |
diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c new file mode 100644 index 000000000000..fb78d87cc130 --- /dev/null +++ b/drivers/mtd/maps/pq2fads.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * drivers/mtd/maps/pq2fads.c | ||
3 | * | ||
4 | * Mapping for the flash SIMM on 8272ADS and PQ2FADS board | ||
5 | * | ||
6 | * Author: Vitaly Bordug <vbordug@ru.mvista.com> | ||
7 | * | ||
8 | * 2005 (c) MontaVista Software, Inc. This file is licensed under | ||
9 | * the terms of the GNU General Public License version 2. This program | ||
10 | * is licensed "as is" without any warranty of any kind, whether express | ||
11 | * or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/ppcboot.h> | ||
20 | #include <linux/mtd/mtd.h> | ||
21 | #include <linux/mtd/map.h> | ||
22 | #include <linux/mtd/partitions.h> | ||
23 | #include <linux/mtd/physmap.h> | ||
24 | |||
25 | /* | ||
26 | NOTE: bank width and interleave relative to the installed flash | ||
27 | should have been chosen within MTD_CFI_GEOMETRY options. | ||
28 | */ | ||
29 | #define PQ2FADS_BANK_WIDTH 4 | ||
30 | |||
31 | static struct mtd_partition pq2fads_partitions[] = { | ||
32 | { | ||
33 | #ifdef CONFIG_ADS8272 | ||
34 | .name = "HRCW", | ||
35 | .size = 0x40000, | ||
36 | .offset = 0, | ||
37 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
38 | }, { | ||
39 | .name = "User FS", | ||
40 | .size = 0x5c0000, | ||
41 | .offset = 0x40000, | ||
42 | #else | ||
43 | .name = "User FS", | ||
44 | .size = 0x600000, | ||
45 | .offset = 0, | ||
46 | #endif | ||
47 | }, { | ||
48 | .name = "uImage", | ||
49 | .size = 0x100000, | ||
50 | .offset = 0x600000, | ||
51 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
52 | }, { | ||
53 | .name = "bootloader", | ||
54 | .size = 0x40000, | ||
55 | .offset = 0x700000, | ||
56 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
57 | }, { | ||
58 | .name = "bootloader env", | ||
59 | .size = 0x40000, | ||
60 | .offset = 0x740000, | ||
61 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
62 | } | ||
63 | }; | ||
64 | |||
65 | |||
66 | /* pointer to MPC885ADS board info data */ | ||
67 | extern unsigned char __res[]; | ||
68 | |||
69 | static int __init init_pq2fads_mtd(void) | ||
70 | { | ||
71 | bd_t *bd = (bd_t *)__res; | ||
72 | physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL); | ||
73 | |||
74 | physmap_set_partitions(pq2fads_partitions, | ||
75 | sizeof (pq2fads_partitions) / | ||
76 | sizeof (pq2fads_partitions[0])); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static void __exit cleanup_pq2fads_mtd(void) | ||
81 | { | ||
82 | } | ||
83 | |||
84 | module_init(init_pq2fads_mtd); | ||
85 | module_exit(cleanup_pq2fads_mtd); | ||
86 | |||
87 | MODULE_LICENSE("GPL"); | ||
88 | MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards"); | ||
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index edd01ee4f90b..5b76ed886185 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: redwood.c,v 1.10 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: redwood.c,v 1.11 2005/11/07 11:14:28 gleixner Exp $ |
3 | * | 3 | * |
4 | * drivers/mtd/maps/redwood.c | 4 | * drivers/mtd/maps/redwood.c |
5 | * | 5 | * |
@@ -79,7 +79,7 @@ static struct mtd_partition redwood_flash_partitions[] = { | |||
79 | 79 | ||
80 | #define RW_PART0_OF 0 | 80 | #define RW_PART0_OF 0 |
81 | #define RW_PART0_SZ 0x400000 /* 4 MiB data */ | 81 | #define RW_PART0_SZ 0x400000 /* 4 MiB data */ |
82 | #define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ | 82 | #define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ |
83 | #define RW_PART1_SZ 0x10000 /* 64K VPD */ | 83 | #define RW_PART1_SZ 0x10000 /* 64K VPD */ |
84 | #define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ | 84 | #define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ |
85 | #define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) | 85 | #define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) |
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index a31f6ee8a4be..9e8bb1782be0 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on SA11x0 based devices | 2 | * Flash memory access on SA11x0 based devices |
3 | * | 3 | * |
4 | * (C) 2000 Nicolas Pitre <nico@cam.org> | 4 | * (C) 2000 Nicolas Pitre <nico@cam.org> |
5 | * | 5 | * |
6 | * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $ | 6 | * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $ |
7 | */ | 7 | */ |
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index da684d3384e9..225cdd9ba5b2 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * This code is GPLed | 6 | * This code is GPLed |
7 | * | 7 | * |
8 | * $Id: sbc8240.c,v 1.4 2004/07/12 22:38:29 dwmw2 Exp $ | 8 | * $Id: sbc8240.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
@@ -205,7 +205,7 @@ int __init init_sbc8240_mtd (void) | |||
205 | } else { | 205 | } else { |
206 | printk (KERN_NOTICE MSG_PREFIX | 206 | printk (KERN_NOTICE MSG_PREFIX |
207 | "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name); | 207 | "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name); |
208 | add_mtd_partitions (sbc8240_mtd[i], | 208 | add_mtd_partitions (sbc8240_mtd[i], |
209 | sbc8240_part_banks[i].mtd_part, | 209 | sbc8240_part_banks[i].mtd_part, |
210 | sbc8240_part_banks[i].nums); | 210 | sbc8240_part_banks[i].nums); |
211 | } | 211 | } |
diff --git a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c index 65add28bde14..7cc4041d096d 100644 --- a/drivers/mtd/maps/sbc_gxx.c +++ b/drivers/mtd/maps/sbc_gxx.c | |||
@@ -1,35 +1,35 @@ | |||
1 | /* sbc_gxx.c -- MTD map driver for Arcom Control Systems SBC-MediaGX, | 1 | /* sbc_gxx.c -- MTD map driver for Arcom Control Systems SBC-MediaGX, |
2 | SBC-GXm and SBC-GX1 series boards. | 2 | SBC-GXm and SBC-GX1 series boards. |
3 | 3 | ||
4 | Copyright (C) 2001 Arcom Control System Ltd | 4 | Copyright (C) 2001 Arcom Control System Ltd |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by | 7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 2 of the License, or | 8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. | 9 | (at your option) any later version. |
10 | 10 | ||
11 | This program is distributed in the hope that it will be useful, | 11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. | 14 | GNU General Public License for more details. |
15 | 15 | ||
16 | You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License |
17 | along with this program; if not, write to the Free Software | 17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
19 | 19 | ||
20 | $Id: sbc_gxx.c,v 1.33 2004/11/28 09:40:40 dwmw2 Exp $ | 20 | $Id: sbc_gxx.c,v 1.35 2005/11/07 11:14:28 gleixner Exp $ |
21 | 21 | ||
22 | The SBC-MediaGX / SBC-GXx has up to 16 MiB of | 22 | The SBC-MediaGX / SBC-GXx has up to 16 MiB of |
23 | Intel StrataFlash (28F320/28F640) in x8 mode. | 23 | Intel StrataFlash (28F320/28F640) in x8 mode. |
24 | 24 | ||
25 | This driver uses the CFI probe and Intel Extended Command Set drivers. | 25 | This driver uses the CFI probe and Intel Extended Command Set drivers. |
26 | 26 | ||
27 | The flash is accessed as follows: | 27 | The flash is accessed as follows: |
28 | 28 | ||
29 | 16 KiB memory window at 0xdc000-0xdffff | 29 | 16 KiB memory window at 0xdc000-0xdffff |
30 | 30 | ||
31 | Two IO address locations for paging | 31 | Two IO address locations for paging |
32 | 32 | ||
33 | 0x258 | 33 | 0x258 |
34 | bit 0-7: address bit 14-21 | 34 | bit 0-7: address bit 14-21 |
35 | 0x259 | 35 | 0x259 |
@@ -37,7 +37,7 @@ The flash is accessed as follows: | |||
37 | bit 7: 0 - reset/powered down | 37 | bit 7: 0 - reset/powered down |
38 | 1 - device enabled | 38 | 1 - device enabled |
39 | 39 | ||
40 | The single flash device is divided into 3 partition which appear as | 40 | The single flash device is divided into 3 partition which appear as |
41 | separate MTD devices. | 41 | separate MTD devices. |
42 | 42 | ||
43 | 25/04/2001 AJL (Arcom) Modified signon strings and partition sizes | 43 | 25/04/2001 AJL (Arcom) Modified signon strings and partition sizes |
@@ -87,17 +87,17 @@ static volatile int page_in_window = -1; // Current page in window. | |||
87 | static void __iomem *iomapadr; | 87 | static void __iomem *iomapadr; |
88 | static DEFINE_SPINLOCK(sbc_gxx_spin); | 88 | static DEFINE_SPINLOCK(sbc_gxx_spin); |
89 | 89 | ||
90 | /* partition_info gives details on the logical partitions that the split the | 90 | /* partition_info gives details on the logical partitions that the split the |
91 | * single flash device into. If the size if zero we use up to the end of the | 91 | * single flash device into. If the size if zero we use up to the end of the |
92 | * device. */ | 92 | * device. */ |
93 | static struct mtd_partition partition_info[]={ | 93 | static struct mtd_partition partition_info[]={ |
94 | { .name = "SBC-GXx flash boot partition", | 94 | { .name = "SBC-GXx flash boot partition", |
95 | .offset = 0, | 95 | .offset = 0, |
96 | .size = BOOT_PARTITION_SIZE_KiB*1024 }, | 96 | .size = BOOT_PARTITION_SIZE_KiB*1024 }, |
97 | { .name = "SBC-GXx flash data partition", | 97 | { .name = "SBC-GXx flash data partition", |
98 | .offset = BOOT_PARTITION_SIZE_KiB*1024, | 98 | .offset = BOOT_PARTITION_SIZE_KiB*1024, |
99 | .size = (DATA_PARTITION_SIZE_KiB)*1024 }, | 99 | .size = (DATA_PARTITION_SIZE_KiB)*1024 }, |
100 | { .name = "SBC-GXx flash application partition", | 100 | { .name = "SBC-GXx flash application partition", |
101 | .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } | 101 | .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } |
102 | }; | 102 | }; |
103 | 103 | ||
@@ -130,7 +130,7 @@ static void sbc_gxx_copy_from(struct map_info *map, void *to, unsigned long from | |||
130 | unsigned long thislen = len; | 130 | unsigned long thislen = len; |
131 | if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) | 131 | if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) |
132 | thislen = WINDOW_LENGTH-(from & WINDOW_MASK); | 132 | thislen = WINDOW_LENGTH-(from & WINDOW_MASK); |
133 | 133 | ||
134 | spin_lock(&sbc_gxx_spin); | 134 | spin_lock(&sbc_gxx_spin); |
135 | sbc_gxx_page(map, from); | 135 | sbc_gxx_page(map, from); |
136 | memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); | 136 | memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); |
@@ -150,12 +150,12 @@ static void sbc_gxx_write8(struct map_info *map, map_word d, unsigned long adr) | |||
150 | } | 150 | } |
151 | 151 | ||
152 | static void sbc_gxx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) | 152 | static void sbc_gxx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) |
153 | { | 153 | { |
154 | while(len) { | 154 | while(len) { |
155 | unsigned long thislen = len; | 155 | unsigned long thislen = len; |
156 | if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) | 156 | if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) |
157 | thislen = WINDOW_LENGTH-(to & WINDOW_MASK); | 157 | thislen = WINDOW_LENGTH-(to & WINDOW_MASK); |
158 | 158 | ||
159 | spin_lock(&sbc_gxx_spin); | 159 | spin_lock(&sbc_gxx_spin); |
160 | sbc_gxx_page(map, to); | 160 | sbc_gxx_page(map, to); |
161 | memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen); | 161 | memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen); |
@@ -201,7 +201,7 @@ static int __init init_sbc_gxx(void) | |||
201 | sbc_gxx_map.name ); | 201 | sbc_gxx_map.name ); |
202 | return -EIO; | 202 | return -EIO; |
203 | } | 203 | } |
204 | 204 | ||
205 | if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { | 205 | if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { |
206 | printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", | 206 | printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", |
207 | sbc_gxx_map.name, | 207 | sbc_gxx_map.name, |
@@ -209,8 +209,8 @@ static int __init init_sbc_gxx(void) | |||
209 | iounmap(iomapadr); | 209 | iounmap(iomapadr); |
210 | return -EAGAIN; | 210 | return -EAGAIN; |
211 | } | 211 | } |
212 | 212 | ||
213 | 213 | ||
214 | printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", | 214 | printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", |
215 | sbc_gxx_map.name, | 215 | sbc_gxx_map.name, |
216 | PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, | 216 | PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, |
@@ -222,7 +222,7 @@ static int __init init_sbc_gxx(void) | |||
222 | cleanup_sbc_gxx(); | 222 | cleanup_sbc_gxx(); |
223 | return -ENXIO; | 223 | return -ENXIO; |
224 | } | 224 | } |
225 | 225 | ||
226 | all_mtd->owner = THIS_MODULE; | 226 | all_mtd->owner = THIS_MODULE; |
227 | 227 | ||
228 | /* Create MTD devices for each partition. */ | 228 | /* Create MTD devices for each partition. */ |
diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index a06ed21e7ed1..6fb9f3c57aab 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c | |||
@@ -16,7 +16,7 @@ | |||
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
18 | * | 18 | * |
19 | * $Id: sc520cdp.c,v 1.21 2004/12/13 10:27:08 dedekind Exp $ | 19 | * $Id: sc520cdp.c,v 1.22 2005/11/07 11:14:28 gleixner Exp $ |
20 | * | 20 | * |
21 | * | 21 | * |
22 | * The SC520CDP is an evaluation board for the Elan SC520 processor available | 22 | * The SC520CDP is an evaluation board for the Elan SC520 processor available |
@@ -231,7 +231,7 @@ static void sc520cdp_setup_par(void) | |||
231 | static int __init init_sc520cdp(void) | 231 | static int __init init_sc520cdp(void) |
232 | { | 232 | { |
233 | int i, devices_found = 0; | 233 | int i, devices_found = 0; |
234 | 234 | ||
235 | #ifdef REPROGRAM_PAR | 235 | #ifdef REPROGRAM_PAR |
236 | /* reprogram PAR registers so flash appears at the desired addresses */ | 236 | /* reprogram PAR registers so flash appears at the desired addresses */ |
237 | sc520cdp_setup_par(); | 237 | sc520cdp_setup_par(); |
@@ -278,7 +278,7 @@ static int __init init_sc520cdp(void) | |||
278 | static void __exit cleanup_sc520cdp(void) | 278 | static void __exit cleanup_sc520cdp(void) |
279 | { | 279 | { |
280 | int i; | 280 | int i; |
281 | 281 | ||
282 | if (merged_mtd) { | 282 | if (merged_mtd) { |
283 | del_mtd_device(merged_mtd); | 283 | del_mtd_device(merged_mtd); |
284 | mtd_concat_destroy(merged_mtd); | 284 | mtd_concat_destroy(merged_mtd); |
diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index 0ece3786d6ea..2c91dff8bb60 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* linux/drivers/mtd/maps/scx200_docflash.c | 1 | /* linux/drivers/mtd/maps/scx200_docflash.c |
2 | 2 | ||
3 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> | 3 | Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> |
4 | 4 | ||
5 | $Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $ | 5 | $Id: scx200_docflash.c,v 1.12 2005/11/07 11:14:28 gleixner Exp $ |
6 | 6 | ||
7 | National Semiconductor SCx200 flash mapped with DOCCS | 7 | National Semiconductor SCx200 flash mapped with DOCCS |
8 | */ | 8 | */ |
@@ -49,23 +49,23 @@ static struct mtd_info *mymtd; | |||
49 | 49 | ||
50 | #ifdef CONFIG_MTD_PARTITIONS | 50 | #ifdef CONFIG_MTD_PARTITIONS |
51 | static struct mtd_partition partition_info[] = { | 51 | static struct mtd_partition partition_info[] = { |
52 | { | 52 | { |
53 | .name = "DOCCS Boot kernel", | 53 | .name = "DOCCS Boot kernel", |
54 | .offset = 0, | 54 | .offset = 0, |
55 | .size = 0xc0000 | 55 | .size = 0xc0000 |
56 | }, | 56 | }, |
57 | { | 57 | { |
58 | .name = "DOCCS Low BIOS", | 58 | .name = "DOCCS Low BIOS", |
59 | .offset = 0xc0000, | 59 | .offset = 0xc0000, |
60 | .size = 0x40000 | 60 | .size = 0x40000 |
61 | }, | 61 | }, |
62 | { | 62 | { |
63 | .name = "DOCCS File system", | 63 | .name = "DOCCS File system", |
64 | .offset = 0x100000, | 64 | .offset = 0x100000, |
65 | .size = ~0 /* calculate from flash size */ | 65 | .size = ~0 /* calculate from flash size */ |
66 | }, | 66 | }, |
67 | { | 67 | { |
68 | .name = "DOCCS High BIOS", | 68 | .name = "DOCCS High BIOS", |
69 | .offset = ~0, /* calculate from flash size */ | 69 | .offset = ~0, /* calculate from flash size */ |
70 | .size = 0x80000 | 70 | .size = 0x80000 |
71 | }, | 71 | }, |
@@ -88,7 +88,7 @@ static int __init init_scx200_docflash(void) | |||
88 | 88 | ||
89 | printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n"); | 89 | printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n"); |
90 | 90 | ||
91 | if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, | 91 | if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, |
92 | PCI_DEVICE_ID_NS_SCx200_BRIDGE, | 92 | PCI_DEVICE_ID_NS_SCx200_BRIDGE, |
93 | NULL)) == NULL) | 93 | NULL)) == NULL) |
94 | return -ENODEV; | 94 | return -ENODEV; |
@@ -134,28 +134,28 @@ static int __init init_scx200_docflash(void) | |||
134 | printk(KERN_ERR NAME ": invalid size for flash mapping\n"); | 134 | printk(KERN_ERR NAME ": invalid size for flash mapping\n"); |
135 | return -EINVAL; | 135 | return -EINVAL; |
136 | } | 136 | } |
137 | 137 | ||
138 | if (width != 8 && width != 16) { | 138 | if (width != 8 && width != 16) { |
139 | printk(KERN_ERR NAME ": invalid bus width for flash mapping\n"); | 139 | printk(KERN_ERR NAME ": invalid bus width for flash mapping\n"); |
140 | return -EINVAL; | 140 | return -EINVAL; |
141 | } | 141 | } |
142 | 142 | ||
143 | if (allocate_resource(&iomem_resource, &docmem, | 143 | if (allocate_resource(&iomem_resource, &docmem, |
144 | size, | 144 | size, |
145 | 0xc0000000, 0xffffffff, | 145 | 0xc0000000, 0xffffffff, |
146 | size, NULL, NULL)) { | 146 | size, NULL, NULL)) { |
147 | printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n"); | 147 | printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n"); |
148 | return -ENOMEM; | 148 | return -ENOMEM; |
149 | } | 149 | } |
150 | 150 | ||
151 | ctrl = 0x07000000 | ((size-1) >> 13); | 151 | ctrl = 0x07000000 | ((size-1) >> 13); |
152 | 152 | ||
153 | printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl); | 153 | printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl); |
154 | 154 | ||
155 | pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start); | 155 | pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start); |
156 | pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl); | 156 | pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl); |
157 | pmr = inl(scx200_cb_base + SCx200_PMR); | 157 | pmr = inl(scx200_cb_base + SCx200_PMR); |
158 | 158 | ||
159 | if (width == 8) { | 159 | if (width == 8) { |
160 | pmr &= ~(1<<6); | 160 | pmr &= ~(1<<6); |
161 | } else { | 161 | } else { |
@@ -163,8 +163,8 @@ static int __init init_scx200_docflash(void) | |||
163 | } | 163 | } |
164 | outl(pmr, scx200_cb_base + SCx200_PMR); | 164 | outl(pmr, scx200_cb_base + SCx200_PMR); |
165 | } | 165 | } |
166 | 166 | ||
167 | printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", | 167 | printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", |
168 | docmem.start, docmem.end, width); | 168 | docmem.start, docmem.end, width); |
169 | 169 | ||
170 | scx200_docflash_map.size = size; | 170 | scx200_docflash_map.size = size; |
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index b7f093fbf9b0..999f4bb3d845 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * sharpsl-flash.c | 2 | * sharpsl-flash.c |
3 | * | 3 | * |
4 | * Copyright (C) 2001 Lineo Japan, Inc. | 4 | * Copyright (C) 2001 Lineo Japan, Inc. |
5 | * Copyright (C) 2002 SHARP | 5 | * Copyright (C) 2002 SHARP |
6 | * | 6 | * |
7 | * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $ | 7 | * $Id: sharpsl-flash.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ |
8 | * | 8 | * |
9 | * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp | 9 | * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp |
10 | * Handle mapping of the flash on the RPX Lite and CLLF boards | 10 | * Handle mapping of the flash on the RPX Lite and CLLF boards |
@@ -57,7 +57,7 @@ int __init init_sharpsl(void) | |||
57 | int nb_parts = 0; | 57 | int nb_parts = 0; |
58 | char *part_type = "static"; | 58 | char *part_type = "static"; |
59 | 59 | ||
60 | printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", | 60 | printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", |
61 | WINDOW_SIZE, WINDOW_ADDR); | 61 | WINDOW_SIZE, WINDOW_ADDR); |
62 | sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); | 62 | sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); |
63 | if (!sharpsl_map.virt) { | 63 | if (!sharpsl_map.virt) { |
@@ -75,7 +75,7 @@ int __init init_sharpsl(void) | |||
75 | 75 | ||
76 | mymtd->owner = THIS_MODULE; | 76 | mymtd->owner = THIS_MODULE; |
77 | 77 | ||
78 | if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() | 78 | if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() |
79 | || machine_is_poodle()) { | 79 | || machine_is_poodle()) { |
80 | sharpsl_partitions[0].size=0x006d0000; | 80 | sharpsl_partitions[0].size=0x006d0000; |
81 | sharpsl_partitions[0].offset=0x00120000; | 81 | sharpsl_partitions[0].offset=0x00120000; |
@@ -87,10 +87,10 @@ int __init init_sharpsl(void) | |||
87 | sharpsl_partitions[0].offset=0x00140000; | 87 | sharpsl_partitions[0].offset=0x00140000; |
88 | } else { | 88 | } else { |
89 | map_destroy(mymtd); | 89 | map_destroy(mymtd); |
90 | iounmap(sharpsl_map.virt); | 90 | iounmap(sharpsl_map.virt); |
91 | return -ENODEV; | 91 | return -ENODEV; |
92 | } | 92 | } |
93 | 93 | ||
94 | parts = sharpsl_partitions; | 94 | parts = sharpsl_partitions; |
95 | nb_parts = NB_OF(sharpsl_partitions); | 95 | nb_parts = NB_OF(sharpsl_partitions); |
96 | 96 | ||
diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index 8ce5d897645c..c53c2c369c9d 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: solutionengine.c,v 1.14 2004/09/16 23:27:14 gleixner Exp $ | 2 | * $Id: solutionengine.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ |
3 | * | 3 | * |
4 | * Flash and EPROM on Hitachi Solution Engine and similar boards. | 4 | * Flash and EPROM on Hitachi Solution Engine and similar boards. |
5 | * | 5 | * |
@@ -67,7 +67,7 @@ static int __init init_soleng_maps(void) | |||
67 | soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000); | 67 | soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000); |
68 | simple_map_init(&soleng_eprom_map); | 68 | simple_map_init(&soleng_eprom_map); |
69 | simple_map_init(&soleng_flash_map); | 69 | simple_map_init(&soleng_flash_map); |
70 | 70 | ||
71 | printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); | 71 | printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); |
72 | flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); | 72 | flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); |
73 | if (!flash_mtd) { | 73 | if (!flash_mtd) { |
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 1355c28f90a4..0758cb1d0105 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: sun_uflash.c,v 1.11 2004/11/04 13:24:15 gleixner Exp $ | 1 | /* $Id: sun_uflash.c,v 1.13 2005/11/07 11:14:28 gleixner Exp $ |
2 | * | 2 | * |
3 | * sun_uflash - Driver implementation for user-programmable flash | 3 | * sun_uflash - Driver implementation for user-programmable flash |
4 | * present on many Sun Microsystems SME boardsets. | 4 | * present on many Sun Microsystems SME boardsets. |
@@ -63,7 +63,7 @@ int uflash_devinit(struct linux_ebus_device* edev) | |||
63 | iTmp = prom_getproperty( | 63 | iTmp = prom_getproperty( |
64 | edev->prom_node, "reg", (void *)regs, sizeof(regs)); | 64 | edev->prom_node, "reg", (void *)regs, sizeof(regs)); |
65 | if ((iTmp % sizeof(regs[0])) != 0) { | 65 | if ((iTmp % sizeof(regs[0])) != 0) { |
66 | printk("%s: Strange reg property size %d\n", | 66 | printk("%s: Strange reg property size %d\n", |
67 | UFLASH_DEVNAME, iTmp); | 67 | UFLASH_DEVNAME, iTmp); |
68 | return -ENODEV; | 68 | return -ENODEV; |
69 | } | 69 | } |
@@ -75,7 +75,7 @@ int uflash_devinit(struct linux_ebus_device* edev) | |||
75 | * can work on supporting it. | 75 | * can work on supporting it. |
76 | */ | 76 | */ |
77 | printk("%s: unsupported device at 0x%lx (%d regs): " \ | 77 | printk("%s: unsupported device at 0x%lx (%d regs): " \ |
78 | "email ebrower@usa.net\n", | 78 | "email ebrower@usa.net\n", |
79 | UFLASH_DEVNAME, edev->resource[0].start, nregs); | 79 | UFLASH_DEVNAME, edev->resource[0].start, nregs); |
80 | return -ENODEV; | 80 | return -ENODEV; |
81 | } | 81 | } |
@@ -84,7 +84,7 @@ int uflash_devinit(struct linux_ebus_device* edev) | |||
84 | printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); | 84 | printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); |
85 | return(-ENOMEM); | 85 | return(-ENOMEM); |
86 | } | 86 | } |
87 | 87 | ||
88 | /* copy defaults and tweak parameters */ | 88 | /* copy defaults and tweak parameters */ |
89 | memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); | 89 | memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); |
90 | pdev->map.size = regs[0].reg_size; | 90 | pdev->map.size = regs[0].reg_size; |
@@ -155,7 +155,7 @@ static void __exit uflash_cleanup(void) | |||
155 | 155 | ||
156 | list_for_each(udevlist, &device_list) { | 156 | list_for_each(udevlist, &device_list) { |
157 | udev = list_entry(udevlist, struct uflash_dev, list); | 157 | udev = list_entry(udevlist, struct uflash_dev, list); |
158 | DEBUG(2, "%s: removing device %s\n", | 158 | DEBUG(2, "%s: removing device %s\n", |
159 | UFLASH_DEVNAME, udev->name); | 159 | UFLASH_DEVNAME, udev->name); |
160 | 160 | ||
161 | if(0 != udev->mtd) { | 161 | if(0 != udev->mtd) { |
@@ -168,7 +168,7 @@ static void __exit uflash_cleanup(void) | |||
168 | } | 168 | } |
169 | kfree(udev->name); | 169 | kfree(udev->name); |
170 | kfree(udev); | 170 | kfree(udev); |
171 | } | 171 | } |
172 | } | 172 | } |
173 | 173 | ||
174 | module_init(uflash_init); | 174 | module_init(uflash_init); |
diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c new file mode 100644 index 000000000000..c7ae9a515c1a --- /dev/null +++ b/drivers/mtd/maps/tqm834x.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* | ||
2 | * drivers/mtd/maps/tqm834x.c | ||
3 | * | ||
4 | * MTD mapping driver for TQM834x boards | ||
5 | * | ||
6 | * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>. | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/ppcboot.h> | ||
22 | |||
23 | #include <linux/mtd/mtd.h> | ||
24 | #include <linux/mtd/map.h> | ||
25 | #include <linux/mtd/partitions.h> | ||
26 | |||
27 | #define FLASH_BANK_MAX 2 | ||
28 | |||
29 | extern unsigned char __res[]; | ||
30 | |||
31 | /* trivial struct to describe partition information */ | ||
32 | struct mtd_part_def | ||
33 | { | ||
34 | int nums; | ||
35 | unsigned char *type; | ||
36 | struct mtd_partition* mtd_part; | ||
37 | }; | ||
38 | |||
39 | static struct mtd_info* mtd_banks[FLASH_BANK_MAX]; | ||
40 | static struct map_info* map_banks[FLASH_BANK_MAX]; | ||
41 | static struct mtd_part_def part_banks[FLASH_BANK_MAX]; | ||
42 | |||
43 | static unsigned long num_banks; | ||
44 | static unsigned long start_scan_addr; | ||
45 | |||
46 | #ifdef CONFIG_MTD_PARTITIONS | ||
47 | /* | ||
48 | * The following defines the partition layout of TQM834x boards. | ||
49 | * | ||
50 | * See include/linux/mtd/partitions.h for definition of the | ||
51 | * mtd_partition structure. | ||
52 | * | ||
53 | * Assume minimal initial size of 4 MiB per bank, will be updated | ||
54 | * later in init_tqm834x_mtd() routine. | ||
55 | */ | ||
56 | |||
57 | /* Partition definition for the first flash bank which is always present. */ | ||
58 | static struct mtd_partition tqm834x_partitions_bank1[] = { | ||
59 | { | ||
60 | .name = "u-boot", /* u-boot firmware */ | ||
61 | .offset = 0x00000000, | ||
62 | .size = 0x00040000, /* 256 KiB */ | ||
63 | /*mask_flags: MTD_WRITEABLE, * force read-only */ | ||
64 | }, | ||
65 | { | ||
66 | .name = "env", /* u-boot environment */ | ||
67 | .offset = 0x00040000, | ||
68 | .size = 0x00020000, /* 128 KiB */ | ||
69 | /*mask_flags: MTD_WRITEABLE, * force read-only */ | ||
70 | }, | ||
71 | { | ||
72 | .name = "kernel", /* linux kernel image */ | ||
73 | .offset = 0x00060000, | ||
74 | .size = 0x00100000, /* 1 MiB */ | ||
75 | /*mask_flags: MTD_WRITEABLE, * force read-only */ | ||
76 | }, | ||
77 | { | ||
78 | .name = "initrd", /* ramdisk image */ | ||
79 | .offset = 0x00160000, | ||
80 | .size = 0x00200000, /* 2 MiB */ | ||
81 | }, | ||
82 | { | ||
83 | .name = "user", /* user data */ | ||
84 | .offset = 0x00360000, | ||
85 | .size = 0x000a0000, /* remaining space */ | ||
86 | /* NOTE: this parttion size is re-calcated in */ | ||
87 | /* init_tqm834x_mtd() to cover actual remaining space. */ | ||
88 | }, | ||
89 | }; | ||
90 | |||
91 | /* Partition definition for the second flash bank which may be present on some | ||
92 | * TQM834x boards. | ||
93 | */ | ||
94 | static struct mtd_partition tqm834x_partitions_bank2[] = { | ||
95 | { | ||
96 | .name = "jffs2", /* jffs2 filesystem */ | ||
97 | .offset = 0x00000000, | ||
98 | .size = 0x00400000, /* whole device */ | ||
99 | /* NOTE: this parttion size is re-calcated in */ | ||
100 | /* init_tqm834x_mtd() to cover actual device size. */ | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | #endif /* CONFIG_MTD_PARTITIONS */ | ||
105 | |||
106 | static int __init init_tqm834x_mtd(void) | ||
107 | { | ||
108 | int idx = 0, ret = 0; | ||
109 | unsigned long flash_addr, flash_size, mtd_size = 0; | ||
110 | |||
111 | /* pointer to TQM834x board info data */ | ||
112 | bd_t *bd = (bd_t *)__res; | ||
113 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
114 | int n; | ||
115 | char mtdid[4]; | ||
116 | const char *part_probes[] = { "cmdlinepart", NULL }; | ||
117 | #endif | ||
118 | |||
119 | flash_addr = bd->bi_flashstart; | ||
120 | flash_size = bd->bi_flashsize; | ||
121 | |||
122 | /* request maximum flash size address space */ | ||
123 | start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); | ||
124 | if (!start_scan_addr) { | ||
125 | printk("%s: Failed to ioremap address: 0x%lx\n", | ||
126 | __FUNCTION__, flash_addr); | ||
127 | return -EIO; | ||
128 | } | ||
129 | |||
130 | for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { | ||
131 | if (mtd_size >= flash_size) | ||
132 | break; | ||
133 | |||
134 | pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx); | ||
135 | |||
136 | map_banks[idx] = | ||
137 | (struct map_info *)kmalloc(sizeof(struct map_info), | ||
138 | GFP_KERNEL); | ||
139 | if (map_banks[idx] == NULL) { | ||
140 | ret = -ENOMEM; | ||
141 | goto error_mem; | ||
142 | } | ||
143 | memset((void *)map_banks[idx], 0, sizeof(struct map_info)); | ||
144 | map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); | ||
145 | if (map_banks[idx]->name == NULL) { | ||
146 | ret = -ENOMEM; | ||
147 | goto error_mem; | ||
148 | } | ||
149 | memset((void *)map_banks[idx]->name, 0, 16); | ||
150 | |||
151 | sprintf(map_banks[idx]->name, "TQM834x-%d", idx); | ||
152 | map_banks[idx]->size = flash_size; | ||
153 | map_banks[idx]->bankwidth = 4; | ||
154 | |||
155 | simple_map_init(map_banks[idx]); | ||
156 | |||
157 | map_banks[idx]->virt = (void __iomem *) | ||
158 | (start_scan_addr + ((idx > 0) ? | ||
159 | (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0)); | ||
160 | map_banks[idx]->phys = | ||
161 | flash_addr + ((idx > 0) ? | ||
162 | (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); | ||
163 | |||
164 | /* start to probe flash chips */ | ||
165 | mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); | ||
166 | if (mtd_banks[idx]) { | ||
167 | mtd_banks[idx]->owner = THIS_MODULE; | ||
168 | mtd_size += mtd_banks[idx]->size; | ||
169 | num_banks++; | ||
170 | pr_debug("%s: bank %ld, name: %s, size: %d bytes \n", | ||
171 | __FUNCTION__, num_banks, | ||
172 | mtd_banks[idx]->name, mtd_banks[idx]->size); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | /* no supported flash chips found */ | ||
177 | if (!num_banks) { | ||
178 | printk("TQM834x: No supported flash chips found!\n"); | ||
179 | ret = -ENXIO; | ||
180 | goto error_mem; | ||
181 | } | ||
182 | |||
183 | #ifdef CONFIG_MTD_PARTITIONS | ||
184 | /* | ||
185 | * Select static partition definitions | ||
186 | */ | ||
187 | n = ARRAY_SIZE(tqm834x_partitions_bank1); | ||
188 | part_banks[0].mtd_part = tqm834x_partitions_bank1; | ||
189 | part_banks[0].type = "static image bank1"; | ||
190 | part_banks[0].nums = n; | ||
191 | |||
192 | /* update last partition size to cover actual remaining space */ | ||
193 | tqm834x_partitions_bank1[n - 1].size = | ||
194 | mtd_banks[0]->size - | ||
195 | tqm834x_partitions_bank1[n - 1].offset; | ||
196 | |||
197 | /* check if we have second bank? */ | ||
198 | if (num_banks == 2) { | ||
199 | n = ARRAY_SIZE(tqm834x_partitions_bank2); | ||
200 | part_banks[1].mtd_part = tqm834x_partitions_bank2; | ||
201 | part_banks[1].type = "static image bank2"; | ||
202 | part_banks[1].nums = n; | ||
203 | |||
204 | /* update last partition size to cover actual remaining space */ | ||
205 | tqm834x_partitions_bank2[n - 1].size = | ||
206 | mtd_banks[1]->size - | ||
207 | tqm834x_partitions_bank2[n - 1].offset; | ||
208 | } | ||
209 | |||
210 | for(idx = 0; idx < num_banks ; idx++) { | ||
211 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
212 | sprintf(mtdid, "%d", idx); | ||
213 | n = parse_mtd_partitions(mtd_banks[idx], | ||
214 | part_probes, | ||
215 | &part_banks[idx].mtd_part, | ||
216 | 0); | ||
217 | pr_debug("%s: %d command line partitions on bank %s\n", | ||
218 | __FUNCTION__, n, mtdid); | ||
219 | if (n > 0) { | ||
220 | part_banks[idx].type = "command line"; | ||
221 | part_banks[idx].nums = n; | ||
222 | } | ||
223 | #endif /* CONFIG_MTD_CMDLINE_PARTS */ | ||
224 | if (part_banks[idx].nums == 0) { | ||
225 | printk(KERN_NOTICE | ||
226 | "TQM834x flash bank %d: no partition info " | ||
227 | "available, registering whole device\n", idx); | ||
228 | add_mtd_device(mtd_banks[idx]); | ||
229 | } else { | ||
230 | printk(KERN_NOTICE | ||
231 | "TQM834x flash bank %d: Using %s partition " | ||
232 | "definition\n", idx, part_banks[idx].type); | ||
233 | add_mtd_partitions(mtd_banks[idx], | ||
234 | part_banks[idx].mtd_part, | ||
235 | part_banks[idx].nums); | ||
236 | } | ||
237 | } | ||
238 | #else /* ! CONFIG_MTD_PARTITIONS */ | ||
239 | printk(KERN_NOTICE "TQM834x flash: registering %d flash banks " | ||
240 | "at once\n", num_banks); | ||
241 | |||
242 | for(idx = 0 ; idx < num_banks ; idx++) | ||
243 | add_mtd_device(mtd_banks[idx]); | ||
244 | |||
245 | #endif /* CONFIG_MTD_PARTITIONS */ | ||
246 | |||
247 | return 0; | ||
248 | error_mem: | ||
249 | for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { | ||
250 | if (map_banks[idx] != NULL) { | ||
251 | if (map_banks[idx]->name != NULL) { | ||
252 | kfree(map_banks[idx]->name); | ||
253 | map_banks[idx]->name = NULL; | ||
254 | } | ||
255 | kfree(map_banks[idx]); | ||
256 | map_banks[idx] = NULL; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | iounmap((void *)start_scan_addr); | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | static void __exit cleanup_tqm834x_mtd(void) | ||
266 | { | ||
267 | unsigned int idx = 0; | ||
268 | for(idx = 0 ; idx < num_banks ; idx++) { | ||
269 | /* destroy mtd_info previously allocated */ | ||
270 | if (mtd_banks[idx]) { | ||
271 | del_mtd_partitions(mtd_banks[idx]); | ||
272 | map_destroy(mtd_banks[idx]); | ||
273 | } | ||
274 | |||
275 | /* release map_info not used anymore */ | ||
276 | kfree(map_banks[idx]->name); | ||
277 | kfree(map_banks[idx]); | ||
278 | } | ||
279 | |||
280 | if (start_scan_addr) { | ||
281 | iounmap((void *)start_scan_addr); | ||
282 | start_scan_addr = 0; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | module_init(init_tqm834x_mtd); | ||
287 | module_exit(cleanup_tqm834x_mtd); | ||
288 | |||
289 | MODULE_LICENSE("GPL"); | ||
290 | MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>"); | ||
291 | MODULE_DESCRIPTION("MTD map driver for TQM834x boards"); | ||
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 0aca8179f27f..a43517053e7c 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c | |||
@@ -1,15 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * Handle mapping of the flash memory access routines | 2 | * Handle mapping of the flash memory access routines |
3 | * on TQM8xxL based devices. | 3 | * on TQM8xxL based devices. |
4 | * | 4 | * |
5 | * $Id: tqm8xxl.c,v 1.13 2004/10/20 22:21:53 dwmw2 Exp $ | 5 | * $Id: tqm8xxl.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ |
6 | * | 6 | * |
7 | * based on rpxlite.c | 7 | * based on rpxlite.c |
8 | * | 8 | * |
9 | * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw> | 9 | * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw> |
10 | * | 10 | * |
11 | * This code is GPLed | 11 | * This code is GPLed |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | /* | 15 | /* |
@@ -19,7 +19,7 @@ | |||
19 | * 2MiB 512Kx16 2MiB 0 | 19 | * 2MiB 512Kx16 2MiB 0 |
20 | * 4MiB 1Mx16 4MiB 0 | 20 | * 4MiB 1Mx16 4MiB 0 |
21 | * 8MiB 1Mx16 4MiB 4MiB | 21 | * 8MiB 1Mx16 4MiB 4MiB |
22 | * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at | 22 | * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at |
23 | * kernel configuration. | 23 | * kernel configuration. |
24 | */ | 24 | */ |
25 | #include <linux/config.h> | 25 | #include <linux/config.h> |
@@ -58,9 +58,9 @@ static void __iomem *start_scan_addr; | |||
58 | * Here are partition information for all known TQM8xxL series devices. | 58 | * Here are partition information for all known TQM8xxL series devices. |
59 | * See include/linux/mtd/partitions.h for definition of the mtd_partition | 59 | * See include/linux/mtd/partitions.h for definition of the mtd_partition |
60 | * structure. | 60 | * structure. |
61 | * | 61 | * |
62 | * The *_max_flash_size is the maximum possible mapped flash size which | 62 | * The *_max_flash_size is the maximum possible mapped flash size which |
63 | * is not necessarily the actual flash size. It must correspond to the | 63 | * is not necessarily the actual flash size. It must correspond to the |
64 | * value specified in the mapping definition defined by the | 64 | * value specified in the mapping definition defined by the |
65 | * "struct map_desc *_io_desc" for the corresponding machine. | 65 | * "struct map_desc *_io_desc" for the corresponding machine. |
66 | */ | 66 | */ |
@@ -132,9 +132,9 @@ int __init init_tqm_mtd(void) | |||
132 | for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { | 132 | for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { |
133 | if(mtd_size >= flash_size) | 133 | if(mtd_size >= flash_size) |
134 | break; | 134 | break; |
135 | 135 | ||
136 | printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); | 136 | printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); |
137 | 137 | ||
138 | map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); | 138 | map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); |
139 | if(map_banks[idx] == NULL) { | 139 | if(map_banks[idx] == NULL) { |
140 | ret = -ENOMEM; | 140 | ret = -ENOMEM; |
@@ -180,7 +180,7 @@ int __init init_tqm_mtd(void) | |||
180 | mtd_size += mtd_banks[idx]->size; | 180 | mtd_size += mtd_banks[idx]->size; |
181 | num_banks++; | 181 | num_banks++; |
182 | 182 | ||
183 | printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, | 183 | printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, |
184 | mtd_banks[idx]->name, mtd_banks[idx]->size); | 184 | mtd_banks[idx]->name, mtd_banks[idx]->size); |
185 | } | 185 | } |
186 | } | 186 | } |
@@ -211,7 +211,7 @@ int __init init_tqm_mtd(void) | |||
211 | } else { | 211 | } else { |
212 | printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n", | 212 | printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n", |
213 | idx, part_banks[idx].type); | 213 | idx, part_banks[idx].type); |
214 | add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part, | 214 | add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part, |
215 | part_banks[idx].nums); | 215 | part_banks[idx].nums); |
216 | } | 216 | } |
217 | } | 217 | } |
diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index 3ebd90f56503..4b372bcb17f1 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c | |||
@@ -19,26 +19,22 @@ | |||
19 | * | 19 | * |
20 | * Note: | 20 | * Note: |
21 | * - In order for detection to work, jumper 3 must be set. | 21 | * - In order for detection to work, jumper 3 must be set. |
22 | * - Drive A and B use a proprietary FTL from General Software which isn't | 22 | * - Drive A and B use the resident flash disk (RFD) flash translation layer. |
23 | * supported as of yet so standard drives can't be mounted; you can create | 23 | * - If you have created your own jffs file system and the bios overwrites |
24 | * your own (e.g. jffs) file system. | ||
25 | * - If you have created your own jffs file system and the bios overwrites | ||
26 | * it during boot, try disabling Drive A: and B: in the boot order. | 24 | * it during boot, try disabling Drive A: and B: in the boot order. |
27 | * | 25 | * |
28 | * $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $ | 26 | * $Id: ts5500_flash.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ |
29 | */ | 27 | */ |
30 | 28 | ||
31 | #include <linux/config.h> | 29 | #include <linux/config.h> |
30 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | 31 | #include <linux/module.h> |
33 | #include <linux/types.h> | ||
34 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
35 | #include <linux/init.h> | ||
36 | #include <linux/mtd/mtd.h> | ||
37 | #include <linux/mtd/map.h> | 33 | #include <linux/mtd/map.h> |
38 | 34 | #include <linux/mtd/mtd.h> | |
39 | #ifdef CONFIG_MTD_PARTITIONS | ||
40 | #include <linux/mtd/partitions.h> | 35 | #include <linux/mtd/partitions.h> |
41 | #endif | 36 | #include <linux/types.h> |
37 | |||
42 | 38 | ||
43 | #define WINDOW_ADDR 0x09400000 | 39 | #define WINDOW_ADDR 0x09400000 |
44 | #define WINDOW_SIZE 0x00200000 | 40 | #define WINDOW_SIZE 0x00200000 |
@@ -50,7 +46,6 @@ static struct map_info ts5500_map = { | |||
50 | .phys = WINDOW_ADDR | 46 | .phys = WINDOW_ADDR |
51 | }; | 47 | }; |
52 | 48 | ||
53 | #ifdef CONFIG_MTD_PARTITIONS | ||
54 | static struct mtd_partition ts5500_partitions[] = { | 49 | static struct mtd_partition ts5500_partitions[] = { |
55 | { | 50 | { |
56 | .name = "Drive A", | 51 | .name = "Drive A", |
@@ -71,8 +66,6 @@ static struct mtd_partition ts5500_partitions[] = { | |||
71 | 66 | ||
72 | #define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition)) | 67 | #define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition)) |
73 | 68 | ||
74 | #endif | ||
75 | |||
76 | static struct mtd_info *mymtd; | 69 | static struct mtd_info *mymtd; |
77 | 70 | ||
78 | static int __init init_ts5500_map(void) | 71 | static int __init init_ts5500_map(void) |
@@ -81,48 +74,39 @@ static int __init init_ts5500_map(void) | |||
81 | 74 | ||
82 | ts5500_map.virt = ioremap_nocache(ts5500_map.phys, ts5500_map.size); | 75 | ts5500_map.virt = ioremap_nocache(ts5500_map.phys, ts5500_map.size); |
83 | 76 | ||
84 | if(!ts5500_map.virt) { | 77 | if (!ts5500_map.virt) { |
85 | printk(KERN_ERR "Failed to ioremap_nocache\n"); | 78 | printk(KERN_ERR "Failed to ioremap_nocache\n"); |
86 | rc = -EIO; | 79 | rc = -EIO; |
87 | goto err_out_ioremap; | 80 | goto err2; |
88 | } | 81 | } |
89 | 82 | ||
90 | simple_map_init(&ts5500_map); | 83 | simple_map_init(&ts5500_map); |
91 | 84 | ||
92 | mymtd = do_map_probe("jedec_probe", &ts5500_map); | 85 | mymtd = do_map_probe("jedec_probe", &ts5500_map); |
93 | if(!mymtd) | 86 | if (!mymtd) |
94 | mymtd = do_map_probe("map_rom", &ts5500_map); | 87 | mymtd = do_map_probe("map_rom", &ts5500_map); |
95 | 88 | ||
96 | if(!mymtd) { | 89 | if (!mymtd) { |
97 | rc = -ENXIO; | 90 | rc = -ENXIO; |
98 | goto err_out_map; | 91 | goto err1; |
99 | } | 92 | } |
100 | 93 | ||
101 | mymtd->owner = THIS_MODULE; | 94 | mymtd->owner = THIS_MODULE; |
102 | #ifdef CONFIG_MTD_PARTITIONS | ||
103 | add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS); | 95 | add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS); |
104 | #else | ||
105 | add_mtd_device(mymtd); | ||
106 | #endif | ||
107 | 96 | ||
108 | return 0; | 97 | return 0; |
109 | 98 | ||
110 | err_out_map: | 99 | err1: |
111 | map_destroy(mymtd); | 100 | map_destroy(mymtd); |
112 | err_out_ioremap: | ||
113 | iounmap(ts5500_map.virt); | 101 | iounmap(ts5500_map.virt); |
114 | 102 | err2: | |
115 | return rc; | 103 | return rc; |
116 | } | 104 | } |
117 | 105 | ||
118 | static void __exit cleanup_ts5500_map(void) | 106 | static void __exit cleanup_ts5500_map(void) |
119 | { | 107 | { |
120 | if (mymtd) { | 108 | if (mymtd) { |
121 | #ifdef CONFIG_MTD_PARTITIONS | ||
122 | del_mtd_partitions(mymtd); | 109 | del_mtd_partitions(mymtd); |
123 | #else | ||
124 | del_mtd_device(mymtd); | ||
125 | #endif | ||
126 | map_destroy(mymtd); | 110 | map_destroy(mymtd); |
127 | } | 111 | } |
128 | 112 | ||
diff --git a/drivers/mtd/maps/tsunami_flash.c b/drivers/mtd/maps/tsunami_flash.c index 170d71239e5e..9e21e6c02f80 100644 --- a/drivers/mtd/maps/tsunami_flash.c +++ b/drivers/mtd/maps/tsunami_flash.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * tsunami_flash.c | 2 | * tsunami_flash.c |
3 | * | 3 | * |
4 | * flash chip on alpha ds10... | 4 | * flash chip on alpha ds10... |
5 | * $Id: tsunami_flash.c,v 1.9 2004/07/14 09:52:55 dwmw2 Exp $ | 5 | * $Id: tsunami_flash.c,v 1.10 2005/11/07 11:14:29 gleixner Exp $ |
6 | */ | 6 | */ |
7 | #include <asm/io.h> | 7 | #include <asm/io.h> |
8 | #include <asm/core_tsunami.h> | 8 | #include <asm/core_tsunami.h> |
@@ -41,7 +41,7 @@ static void tsunami_flash_copy_from( | |||
41 | } | 41 | } |
42 | 42 | ||
43 | static void tsunami_flash_copy_to( | 43 | static void tsunami_flash_copy_to( |
44 | struct map_info *map, unsigned long offset, | 44 | struct map_info *map, unsigned long offset, |
45 | const void *addr, ssize_t len) | 45 | const void *addr, ssize_t len) |
46 | { | 46 | { |
47 | const unsigned char *src; | 47 | const unsigned char *src; |
@@ -90,7 +90,7 @@ static int __init init_tsunami_flash(void) | |||
90 | char **type; | 90 | char **type; |
91 | 91 | ||
92 | tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); | 92 | tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); |
93 | 93 | ||
94 | tsunami_flash_mtd = 0; | 94 | tsunami_flash_mtd = 0; |
95 | type = rom_probe_types; | 95 | type = rom_probe_types; |
96 | for(; !tsunami_flash_mtd && *type; type++) { | 96 | for(; !tsunami_flash_mtd && *type; type++) { |
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index cc372136e852..79d92808b766 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) | 6 | * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) |
7 | * | 7 | * |
8 | * $Id: uclinux.c,v 1.10 2005/01/05 18:05:13 dwmw2 Exp $ | 8 | * $Id: uclinux.c,v 1.12 2005/11/07 11:14:29 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | /****************************************************************************/ | 11 | /****************************************************************************/ |
@@ -82,7 +82,7 @@ int __init uclinux_mtd_init(void) | |||
82 | iounmap(mapp->virt); | 82 | iounmap(mapp->virt); |
83 | return(-ENXIO); | 83 | return(-ENXIO); |
84 | } | 84 | } |
85 | 85 | ||
86 | mtd->owner = THIS_MODULE; | 86 | mtd->owner = THIS_MODULE; |
87 | mtd->point = uclinux_point; | 87 | mtd->point = uclinux_point; |
88 | mtd->priv = mapp; | 88 | mtd->priv = mapp; |
diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c index c8c74110ed1b..e0063941c0df 100644 --- a/drivers/mtd/maps/vmax301.c +++ b/drivers/mtd/maps/vmax301.c | |||
@@ -1,19 +1,19 @@ | |||
1 | // $Id: vmax301.c,v 1.30 2004/07/12 22:38:29 dwmw2 Exp $ | 1 | // $Id: vmax301.c,v 1.32 2005/11/07 11:14:29 gleixner Exp $ |
2 | /* ###################################################################### | 2 | /* ###################################################################### |
3 | 3 | ||
4 | Tempustech VMAX SBC301 MTD Driver. | 4 | Tempustech VMAX SBC301 MTD Driver. |
5 | 5 | ||
6 | The VMAx 301 is a SBC based on . It | 6 | The VMAx 301 is a SBC based on . It |
7 | comes with three builtin AMD 29F016B flash chips and a socket for SRAM or | 7 | comes with three builtin AMD 29F016B flash chips and a socket for SRAM or |
8 | more flash. Each unit has it's own 8k mapping into a settable region | 8 | more flash. Each unit has it's own 8k mapping into a settable region |
9 | (0xD8000). There are two 8k mappings for each MTD, the first is always set | 9 | (0xD8000). There are two 8k mappings for each MTD, the first is always set |
10 | to the lower 8k of the device the second is paged. Writing a 16 bit page | 10 | to the lower 8k of the device the second is paged. Writing a 16 bit page |
11 | value to anywhere in the first 8k will cause the second 8k to page around. | 11 | value to anywhere in the first 8k will cause the second 8k to page around. |
12 | 12 | ||
13 | To boot the device a bios extension must be installed into the first 8k | 13 | To boot the device a bios extension must be installed into the first 8k |
14 | of flash that is smart enough to copy itself down, page in the rest of | 14 | of flash that is smart enough to copy itself down, page in the rest of |
15 | itself and begin executing. | 15 | itself and begin executing. |
16 | 16 | ||
17 | ##################################################################### */ | 17 | ##################################################################### */ |
18 | 18 | ||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
@@ -35,7 +35,7 @@ | |||
35 | /* Actually we could use two spinlocks, but we'd have to have | 35 | /* Actually we could use two spinlocks, but we'd have to have |
36 | more private space in the struct map_info. We lose a little | 36 | more private space in the struct map_info. We lose a little |
37 | performance like this, but we'd probably lose more by having | 37 | performance like this, but we'd probably lose more by having |
38 | the extra indirection from having one of the map->map_priv | 38 | the extra indirection from having one of the map->map_priv |
39 | fields pointing to yet another private struct. | 39 | fields pointing to yet another private struct. |
40 | */ | 40 | */ |
41 | static DEFINE_SPINLOCK(vmax301_spin); | 41 | static DEFINE_SPINLOCK(vmax301_spin); |
@@ -98,7 +98,7 @@ static void vmax301_copy_to(struct map_info *map, unsigned long to, const void * | |||
98 | spin_lock(&vmax301_spin); | 98 | spin_lock(&vmax301_spin); |
99 | vmax301_page(map, to); | 99 | vmax301_page(map, to); |
100 | memcpy_toio(map->map_priv_2 + to, from, thislen); | 100 | memcpy_toio(map->map_priv_2 + to, from, thislen); |
101 | spin_unlock(&vmax301_spin); | 101 | spin_unlock(&vmax301_spin); |
102 | to += thislen; | 102 | to += thislen; |
103 | from += thislen; | 103 | from += thislen; |
104 | len -= thislen; | 104 | len -= thislen; |
@@ -137,7 +137,7 @@ static struct mtd_info *vmax_mtd[2] = {NULL, NULL}; | |||
137 | static void __exit cleanup_vmax301(void) | 137 | static void __exit cleanup_vmax301(void) |
138 | { | 138 | { |
139 | int i; | 139 | int i; |
140 | 140 | ||
141 | for (i=0; i<2; i++) { | 141 | for (i=0; i<2; i++) { |
142 | if (vmax_mtd[i]) { | 142 | if (vmax_mtd[i]) { |
143 | del_mtd_device(vmax_mtd[i]); | 143 | del_mtd_device(vmax_mtd[i]); |
@@ -161,13 +161,13 @@ int __init init_vmax301(void) | |||
161 | return -EIO; | 161 | return -EIO; |
162 | } | 162 | } |
163 | /* Put the address in the map's private data area. | 163 | /* Put the address in the map's private data area. |
164 | We store the actual MTD IO address rather than the | 164 | We store the actual MTD IO address rather than the |
165 | address of the first half, because it's used more | 165 | address of the first half, because it's used more |
166 | often. | 166 | often. |
167 | */ | 167 | */ |
168 | vmax_map[0].map_priv_2 = iomapadr + WINDOW_START; | 168 | vmax_map[0].map_priv_2 = iomapadr + WINDOW_START; |
169 | vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START); | 169 | vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START); |
170 | 170 | ||
171 | for (i=0; i<2; i++) { | 171 | for (i=0; i<2; i++) { |
172 | vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]); | 172 | vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]); |
173 | if (!vmax_mtd[i]) | 173 | if (!vmax_mtd[i]) |
diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c index d6137b1b5670..5c17bca3a37e 100644 --- a/drivers/mtd/maps/walnut.c +++ b/drivers/mtd/maps/walnut.c | |||
@@ -1,12 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: walnut.c,v 1.2 2004/12/10 12:07:42 holindho Exp $ | 2 | * $Id: walnut.c,v 1.3 2005/11/07 11:14:29 gleixner Exp $ |
3 | * | 3 | * |
4 | * Mapping for Walnut flash | 4 | * Mapping for Walnut flash |
5 | * (used ebony.c as a "framework") | 5 | * (used ebony.c as a "framework") |
6 | * | 6 | * |
7 | * Heikki Lindholm <holindho@infradead.org> | 7 | * Heikki Lindholm <holindho@infradead.org> |
8 | * | 8 | * |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
11 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
@@ -48,7 +48,7 @@ static struct mtd_partition walnut_partitions[] = { | |||
48 | .name = "OpenBIOS", | 48 | .name = "OpenBIOS", |
49 | .offset = 0x0, | 49 | .offset = 0x0, |
50 | .size = WALNUT_FLASH_SIZE, | 50 | .size = WALNUT_FLASH_SIZE, |
51 | /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */ | 51 | /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */ |
52 | } | 52 | } |
53 | }; | 53 | }; |
54 | 54 | ||
@@ -72,11 +72,11 @@ int __init init_walnut(void) | |||
72 | printk("The on-board flash is disabled (U79 sw 5)!"); | 72 | printk("The on-board flash is disabled (U79 sw 5)!"); |
73 | return -EIO; | 73 | return -EIO; |
74 | } | 74 | } |
75 | if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) | 75 | if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) |
76 | flash_base = WALNUT_FLASH_LOW; | 76 | flash_base = WALNUT_FLASH_LOW; |
77 | else | 77 | else |
78 | flash_base = WALNUT_FLASH_HIGH; | 78 | flash_base = WALNUT_FLASH_HIGH; |
79 | 79 | ||
80 | walnut_map.phys = flash_base; | 80 | walnut_map.phys = flash_base; |
81 | walnut_map.virt = | 81 | walnut_map.virt = |
82 | (void __iomem *)ioremap(flash_base, walnut_map.size); | 82 | (void __iomem *)ioremap(flash_base, walnut_map.size); |
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 82b887b05707..60c197ec455b 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: wr_sbc82xx_flash.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $ | 2 | * $Id: wr_sbc82xx_flash.c,v 1.8 2005/11/07 11:14:29 gleixner Exp $ |
3 | * | 3 | * |
4 | * Map for flash chips on Wind River PowerQUICC II SBC82xx board. | 4 | * Map for flash chips on Wind River PowerQUICC II SBC82xx board. |
5 | * | 5 | * |
@@ -163,10 +163,10 @@ static void __exit cleanup_sbc82xx_flash(void) | |||
163 | del_mtd_partitions(sbcmtd[i]); | 163 | del_mtd_partitions(sbcmtd[i]); |
164 | else | 164 | else |
165 | del_mtd_device(sbcmtd[i]); | 165 | del_mtd_device(sbcmtd[i]); |
166 | 166 | ||
167 | kfree(sbcmtd_parts[i]); | 167 | kfree(sbcmtd_parts[i]); |
168 | map_destroy(sbcmtd[i]); | 168 | map_destroy(sbcmtd[i]); |
169 | 169 | ||
170 | iounmap((void *)sbc82xx_flash_map[i].virt); | 170 | iounmap((void *)sbc82xx_flash_map[i].virt); |
171 | sbc82xx_flash_map[i].virt = 0; | 171 | sbc82xx_flash_map[i].virt = 0; |
172 | } | 172 | } |
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index f8d2185819e7..339cb1218eaa 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mtd_blkdevs.c,v 1.24 2004/11/16 18:28:59 dwmw2 Exp $ | 2 | * $Id: mtd_blkdevs.c,v 1.27 2005/11/07 11:14:20 gleixner Exp $ |
3 | * | 3 | * |
4 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> | 4 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> |
5 | * | 5 | * |
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <asm/semaphore.h> | 22 | #include <asm/semaphore.h> |
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <linux/devfs_fs_kernel.h> | ||
25 | 24 | ||
26 | static LIST_HEAD(blktrans_majors); | 25 | static LIST_HEAD(blktrans_majors); |
27 | 26 | ||
@@ -86,7 +85,7 @@ static int mtd_blktrans_thread(void *arg) | |||
86 | daemonize("%sd", tr->name); | 85 | daemonize("%sd", tr->name); |
87 | 86 | ||
88 | /* daemonize() doesn't do this for us since some kernel threads | 87 | /* daemonize() doesn't do this for us since some kernel threads |
89 | actually want to deal with signals. We can't just call | 88 | actually want to deal with signals. We can't just call |
90 | exit_sighand() since that'll cause an oops when we finally | 89 | exit_sighand() since that'll cause an oops when we finally |
91 | do exit. */ | 90 | do exit. */ |
92 | spin_lock_irq(¤t->sighand->siglock); | 91 | spin_lock_irq(¤t->sighand->siglock); |
@@ -95,7 +94,7 @@ static int mtd_blktrans_thread(void *arg) | |||
95 | spin_unlock_irq(¤t->sighand->siglock); | 94 | spin_unlock_irq(¤t->sighand->siglock); |
96 | 95 | ||
97 | spin_lock_irq(rq->queue_lock); | 96 | spin_lock_irq(rq->queue_lock); |
98 | 97 | ||
99 | while (!tr->blkcore_priv->exiting) { | 98 | while (!tr->blkcore_priv->exiting) { |
100 | struct request *req; | 99 | struct request *req; |
101 | struct mtd_blktrans_dev *dev; | 100 | struct mtd_blktrans_dev *dev; |
@@ -158,7 +157,7 @@ static int blktrans_open(struct inode *i, struct file *f) | |||
158 | if (!try_module_get(tr->owner)) | 157 | if (!try_module_get(tr->owner)) |
159 | goto out_tr; | 158 | goto out_tr; |
160 | 159 | ||
161 | /* FIXME: Locking. A hot pluggable device can go away | 160 | /* FIXME: Locking. A hot pluggable device can go away |
162 | (del_mtd_device can be called for it) without its module | 161 | (del_mtd_device can be called for it) without its module |
163 | being unloaded. */ | 162 | being unloaded. */ |
164 | dev->mtd->usecount++; | 163 | dev->mtd->usecount++; |
@@ -196,7 +195,7 @@ static int blktrans_release(struct inode *i, struct file *f) | |||
196 | } | 195 | } |
197 | 196 | ||
198 | 197 | ||
199 | static int blktrans_ioctl(struct inode *inode, struct file *file, | 198 | static int blktrans_ioctl(struct inode *inode, struct file *file, |
200 | unsigned int cmd, unsigned long arg) | 199 | unsigned int cmd, unsigned long arg) |
201 | { | 200 | { |
202 | struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; | 201 | struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; |
@@ -265,7 +264,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
265 | /* Required number was free */ | 264 | /* Required number was free */ |
266 | list_add_tail(&new->list, &d->list); | 265 | list_add_tail(&new->list, &d->list); |
267 | goto added; | 266 | goto added; |
268 | } | 267 | } |
269 | last_devnum = d->devnum; | 268 | last_devnum = d->devnum; |
270 | } | 269 | } |
271 | if (new->devnum == -1) | 270 | if (new->devnum == -1) |
@@ -289,11 +288,19 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
289 | gd->major = tr->major; | 288 | gd->major = tr->major; |
290 | gd->first_minor = (new->devnum) << tr->part_bits; | 289 | gd->first_minor = (new->devnum) << tr->part_bits; |
291 | gd->fops = &mtd_blktrans_ops; | 290 | gd->fops = &mtd_blktrans_ops; |
292 | 291 | ||
293 | snprintf(gd->disk_name, sizeof(gd->disk_name), | 292 | if (tr->part_bits) |
294 | "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); | 293 | if (new->devnum < 26) |
295 | snprintf(gd->devfs_name, sizeof(gd->devfs_name), | 294 | snprintf(gd->disk_name, sizeof(gd->disk_name), |
296 | "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); | 295 | "%s%c", tr->name, 'a' + new->devnum); |
296 | else | ||
297 | snprintf(gd->disk_name, sizeof(gd->disk_name), | ||
298 | "%s%c%c", tr->name, | ||
299 | 'a' - 1 + new->devnum / 26, | ||
300 | 'a' + new->devnum % 26); | ||
301 | else | ||
302 | snprintf(gd->disk_name, sizeof(gd->disk_name), | ||
303 | "%s%d", tr->name, new->devnum); | ||
297 | 304 | ||
298 | /* 2.5 has capacity in units of 512 bytes while still | 305 | /* 2.5 has capacity in units of 512 bytes while still |
299 | having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ | 306 | having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ |
@@ -307,7 +314,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
307 | set_disk_ro(gd, 1); | 314 | set_disk_ro(gd, 1); |
308 | 315 | ||
309 | add_disk(gd); | 316 | add_disk(gd); |
310 | 317 | ||
311 | return 0; | 318 | return 0; |
312 | } | 319 | } |
313 | 320 | ||
@@ -322,7 +329,7 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) | |||
322 | 329 | ||
323 | del_gendisk(old->blkcore_priv); | 330 | del_gendisk(old->blkcore_priv); |
324 | put_disk(old->blkcore_priv); | 331 | put_disk(old->blkcore_priv); |
325 | 332 | ||
326 | return 0; | 333 | return 0; |
327 | } | 334 | } |
328 | 335 | ||
@@ -361,12 +368,12 @@ static struct mtd_notifier blktrans_notifier = { | |||
361 | .add = blktrans_notify_add, | 368 | .add = blktrans_notify_add, |
362 | .remove = blktrans_notify_remove, | 369 | .remove = blktrans_notify_remove, |
363 | }; | 370 | }; |
364 | 371 | ||
365 | int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | 372 | int register_mtd_blktrans(struct mtd_blktrans_ops *tr) |
366 | { | 373 | { |
367 | int ret, i; | 374 | int ret, i; |
368 | 375 | ||
369 | /* Register the notifier if/when the first device type is | 376 | /* Register the notifier if/when the first device type is |
370 | registered, to prevent the link/init ordering from fucking | 377 | registered, to prevent the link/init ordering from fucking |
371 | us over. */ | 378 | us over. */ |
372 | if (!blktrans_notifier.list.next) | 379 | if (!blktrans_notifier.list.next) |
@@ -409,9 +416,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
409 | kfree(tr->blkcore_priv); | 416 | kfree(tr->blkcore_priv); |
410 | up(&mtd_table_mutex); | 417 | up(&mtd_table_mutex); |
411 | return ret; | 418 | return ret; |
412 | } | 419 | } |
413 | |||
414 | devfs_mk_dir(tr->name); | ||
415 | 420 | ||
416 | INIT_LIST_HEAD(&tr->devs); | 421 | INIT_LIST_HEAD(&tr->devs); |
417 | list_add(&tr->list, &blktrans_majors); | 422 | list_add(&tr->list, &blktrans_majors); |
@@ -445,7 +450,6 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
445 | tr->remove_dev(dev); | 450 | tr->remove_dev(dev); |
446 | } | 451 | } |
447 | 452 | ||
448 | devfs_remove(tr->name); | ||
449 | blk_cleanup_queue(tr->blkcore_priv->rq); | 453 | blk_cleanup_queue(tr->blkcore_priv->rq); |
450 | unregister_blkdev(tr->major, tr->name); | 454 | unregister_blkdev(tr->major, tr->name); |
451 | 455 | ||
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 400dd9c89883..e84756644fd1 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c | |||
@@ -1,21 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * Direct MTD block device access | 2 | * Direct MTD block device access |
3 | * | 3 | * |
4 | * $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $ | 4 | * $Id: mtdblock.c,v 1.68 2005/11/07 11:14:20 gleixner Exp $ |
5 | * | 5 | * |
6 | * (C) 2000-2003 Nicolas Pitre <nico@cam.org> | 6 | * (C) 2000-2003 Nicolas Pitre <nico@cam.org> |
7 | * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> | 7 | * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
11 | #include <linux/types.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
15 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/types.h> | ||
17 | #include <linux/vmalloc.h> | 18 | #include <linux/vmalloc.h> |
18 | #include <linux/sched.h> /* TASK_* */ | 19 | |
19 | #include <linux/mtd/mtd.h> | 20 | #include <linux/mtd/mtd.h> |
20 | #include <linux/mtd/blktrans.h> | 21 | #include <linux/mtd/blktrans.h> |
21 | 22 | ||
@@ -31,7 +32,7 @@ static struct mtdblk_dev { | |||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * Cache stuff... | 34 | * Cache stuff... |
34 | * | 35 | * |
35 | * Since typical flash erasable sectors are much larger than what Linux's | 36 | * Since typical flash erasable sectors are much larger than what Linux's |
36 | * buffer cache can handle, we must implement read-modify-write on flash | 37 | * buffer cache can handle, we must implement read-modify-write on flash |
37 | * sectors for each block write requests. To avoid over-erasing flash sectors | 38 | * sectors for each block write requests. To avoid over-erasing flash sectors |
@@ -45,7 +46,7 @@ static void erase_callback(struct erase_info *done) | |||
45 | wake_up(wait_q); | 46 | wake_up(wait_q); |
46 | } | 47 | } |
47 | 48 | ||
48 | static int erase_write (struct mtd_info *mtd, unsigned long pos, | 49 | static int erase_write (struct mtd_info *mtd, unsigned long pos, |
49 | int len, const char *buf) | 50 | int len, const char *buf) |
50 | { | 51 | { |
51 | struct erase_info erase; | 52 | struct erase_info erase; |
@@ -103,18 +104,18 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) | |||
103 | return 0; | 104 | return 0; |
104 | 105 | ||
105 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " | 106 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " |
106 | "at 0x%lx, size 0x%x\n", mtd->name, | 107 | "at 0x%lx, size 0x%x\n", mtd->name, |
107 | mtdblk->cache_offset, mtdblk->cache_size); | 108 | mtdblk->cache_offset, mtdblk->cache_size); |
108 | 109 | ||
109 | ret = erase_write (mtd, mtdblk->cache_offset, | 110 | ret = erase_write (mtd, mtdblk->cache_offset, |
110 | mtdblk->cache_size, mtdblk->cache_data); | 111 | mtdblk->cache_size, mtdblk->cache_data); |
111 | if (ret) | 112 | if (ret) |
112 | return ret; | 113 | return ret; |
113 | 114 | ||
114 | /* | 115 | /* |
115 | * Here we could argubly set the cache state to STATE_CLEAN. | 116 | * Here we could argubly set the cache state to STATE_CLEAN. |
116 | * However this could lead to inconsistency since we will not | 117 | * However this could lead to inconsistency since we will not |
117 | * be notified if this content is altered on the flash by other | 118 | * be notified if this content is altered on the flash by other |
118 | * means. Let's declare it empty and leave buffering tasks to | 119 | * means. Let's declare it empty and leave buffering tasks to |
119 | * the buffer cache instead. | 120 | * the buffer cache instead. |
120 | */ | 121 | */ |
@@ -123,7 +124,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) | |||
123 | } | 124 | } |
124 | 125 | ||
125 | 126 | ||
126 | static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | 127 | static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, |
127 | int len, const char *buf) | 128 | int len, const char *buf) |
128 | { | 129 | { |
129 | struct mtd_info *mtd = mtdblk->mtd; | 130 | struct mtd_info *mtd = mtdblk->mtd; |
@@ -133,7 +134,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
133 | 134 | ||
134 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", | 135 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", |
135 | mtd->name, pos, len); | 136 | mtd->name, pos, len); |
136 | 137 | ||
137 | if (!sect_size) | 138 | if (!sect_size) |
138 | return MTD_WRITE (mtd, pos, len, &retlen, buf); | 139 | return MTD_WRITE (mtd, pos, len, &retlen, buf); |
139 | 140 | ||
@@ -141,11 +142,11 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
141 | unsigned long sect_start = (pos/sect_size)*sect_size; | 142 | unsigned long sect_start = (pos/sect_size)*sect_size; |
142 | unsigned int offset = pos - sect_start; | 143 | unsigned int offset = pos - sect_start; |
143 | unsigned int size = sect_size - offset; | 144 | unsigned int size = sect_size - offset; |
144 | if( size > len ) | 145 | if( size > len ) |
145 | size = len; | 146 | size = len; |
146 | 147 | ||
147 | if (size == sect_size) { | 148 | if (size == sect_size) { |
148 | /* | 149 | /* |
149 | * We are covering a whole sector. Thus there is no | 150 | * We are covering a whole sector. Thus there is no |
150 | * need to bother with the cache while it may still be | 151 | * need to bother with the cache while it may still be |
151 | * useful for other partial writes. | 152 | * useful for other partial writes. |
@@ -159,7 +160,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
159 | if (mtdblk->cache_state == STATE_DIRTY && | 160 | if (mtdblk->cache_state == STATE_DIRTY && |
160 | mtdblk->cache_offset != sect_start) { | 161 | mtdblk->cache_offset != sect_start) { |
161 | ret = write_cached_data(mtdblk); | 162 | ret = write_cached_data(mtdblk); |
162 | if (ret) | 163 | if (ret) |
163 | return ret; | 164 | return ret; |
164 | } | 165 | } |
165 | 166 | ||
@@ -192,7 +193,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
192 | } | 193 | } |
193 | 194 | ||
194 | 195 | ||
195 | static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, | 196 | static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, |
196 | int len, char *buf) | 197 | int len, char *buf) |
197 | { | 198 | { |
198 | struct mtd_info *mtd = mtdblk->mtd; | 199 | struct mtd_info *mtd = mtdblk->mtd; |
@@ -200,9 +201,9 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
200 | size_t retlen; | 201 | size_t retlen; |
201 | int ret; | 202 | int ret; |
202 | 203 | ||
203 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", | 204 | DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", |
204 | mtd->name, pos, len); | 205 | mtd->name, pos, len); |
205 | 206 | ||
206 | if (!sect_size) | 207 | if (!sect_size) |
207 | return MTD_READ (mtd, pos, len, &retlen, buf); | 208 | return MTD_READ (mtd, pos, len, &retlen, buf); |
208 | 209 | ||
@@ -210,7 +211,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, | |||
210 | unsigned long sect_start = (pos/sect_size)*sect_size; | 211 | unsigned long sect_start = (pos/sect_size)*sect_size; |
211 | unsigned int offset = pos - sect_start; | 212 | unsigned int offset = pos - sect_start; |
212 | unsigned int size = sect_size - offset; | 213 | unsigned int size = sect_size - offset; |
213 | if (size > len) | 214 | if (size > len) |
214 | size = len; | 215 | size = len; |
215 | 216 | ||
216 | /* | 217 | /* |
@@ -268,12 +269,12 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) | |||
268 | int dev = mbd->devnum; | 269 | int dev = mbd->devnum; |
269 | 270 | ||
270 | DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); | 271 | DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); |
271 | 272 | ||
272 | if (mtdblks[dev]) { | 273 | if (mtdblks[dev]) { |
273 | mtdblks[dev]->count++; | 274 | mtdblks[dev]->count++; |
274 | return 0; | 275 | return 0; |
275 | } | 276 | } |
276 | 277 | ||
277 | /* OK, it's not open. Create cache info for it */ | 278 | /* OK, it's not open. Create cache info for it */ |
278 | mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); | 279 | mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); |
279 | if (!mtdblk) | 280 | if (!mtdblk) |
@@ -292,7 +293,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) | |||
292 | } | 293 | } |
293 | 294 | ||
294 | mtdblks[dev] = mtdblk; | 295 | mtdblks[dev] = mtdblk; |
295 | 296 | ||
296 | DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); | 297 | DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); |
297 | 298 | ||
298 | return 0; | 299 | return 0; |
@@ -320,7 +321,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) | |||
320 | DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); | 321 | DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); |
321 | 322 | ||
322 | return 0; | 323 | return 0; |
323 | } | 324 | } |
324 | 325 | ||
325 | static int mtdblock_flush(struct mtd_blktrans_dev *dev) | 326 | static int mtdblock_flush(struct mtd_blktrans_dev *dev) |
326 | { | 327 | { |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 16df1e4fb0e9..6f044584bdc6 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -1,22 +1,23 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mtdchar.c,v 1.73 2005/07/04 17:36:41 gleixner Exp $ | 2 | * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ |
3 | * | 3 | * |
4 | * Character-device access to raw MTD devices. | 4 | * Character-device access to raw MTD devices. |
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/config.h> | 8 | #include <linux/config.h> |
9 | #include <linux/device.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/init.h> | ||
9 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
10 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/slab.h> | ||
15 | #include <linux/sched.h> | ||
16 | |||
11 | #include <linux/mtd/mtd.h> | 17 | #include <linux/mtd/mtd.h> |
12 | #include <linux/mtd/compatmac.h> | 18 | #include <linux/mtd/compatmac.h> |
13 | #include <linux/slab.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/sched.h> /* TASK_* */ | ||
17 | #include <asm/uaccess.h> | ||
18 | 19 | ||
19 | #include <linux/device.h> | 20 | #include <asm/uaccess.h> |
20 | 21 | ||
21 | static struct class *mtd_class; | 22 | static struct class *mtd_class; |
22 | 23 | ||
@@ -27,7 +28,7 @@ static void mtd_notify_add(struct mtd_info* mtd) | |||
27 | 28 | ||
28 | class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), | 29 | class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), |
29 | NULL, "mtd%d", mtd->index); | 30 | NULL, "mtd%d", mtd->index); |
30 | 31 | ||
31 | class_device_create(mtd_class, NULL, | 32 | class_device_create(mtd_class, NULL, |
32 | MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), | 33 | MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), |
33 | NULL, "mtd%dro", mtd->index); | 34 | NULL, "mtd%dro", mtd->index); |
@@ -70,26 +71,23 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) | |||
70 | switch (orig) { | 71 | switch (orig) { |
71 | case 0: | 72 | case 0: |
72 | /* SEEK_SET */ | 73 | /* SEEK_SET */ |
73 | file->f_pos = offset; | ||
74 | break; | 74 | break; |
75 | case 1: | 75 | case 1: |
76 | /* SEEK_CUR */ | 76 | /* SEEK_CUR */ |
77 | file->f_pos += offset; | 77 | offset += file->f_pos; |
78 | break; | 78 | break; |
79 | case 2: | 79 | case 2: |
80 | /* SEEK_END */ | 80 | /* SEEK_END */ |
81 | file->f_pos =mtd->size + offset; | 81 | offset += mtd->size; |
82 | break; | 82 | break; |
83 | default: | 83 | default: |
84 | return -EINVAL; | 84 | return -EINVAL; |
85 | } | 85 | } |
86 | 86 | ||
87 | if (file->f_pos < 0) | 87 | if (offset >= 0 && offset < mtd->size) |
88 | file->f_pos = 0; | 88 | return file->f_pos = offset; |
89 | else if (file->f_pos >= mtd->size) | ||
90 | file->f_pos = mtd->size - 1; | ||
91 | 89 | ||
92 | return file->f_pos; | 90 | return -EINVAL; |
93 | } | 91 | } |
94 | 92 | ||
95 | 93 | ||
@@ -110,23 +108,23 @@ static int mtd_open(struct inode *inode, struct file *file) | |||
110 | return -EACCES; | 108 | return -EACCES; |
111 | 109 | ||
112 | mtd = get_mtd_device(NULL, devnum); | 110 | mtd = get_mtd_device(NULL, devnum); |
113 | 111 | ||
114 | if (!mtd) | 112 | if (!mtd) |
115 | return -ENODEV; | 113 | return -ENODEV; |
116 | 114 | ||
117 | if (MTD_ABSENT == mtd->type) { | 115 | if (MTD_ABSENT == mtd->type) { |
118 | put_mtd_device(mtd); | 116 | put_mtd_device(mtd); |
119 | return -ENODEV; | 117 | return -ENODEV; |
120 | } | 118 | } |
121 | 119 | ||
122 | file->private_data = mtd; | 120 | file->private_data = mtd; |
123 | 121 | ||
124 | /* You can't open it RW if it's not a writeable device */ | 122 | /* You can't open it RW if it's not a writeable device */ |
125 | if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { | 123 | if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { |
126 | put_mtd_device(mtd); | 124 | put_mtd_device(mtd); |
127 | return -EACCES; | 125 | return -EACCES; |
128 | } | 126 | } |
129 | 127 | ||
130 | return 0; | 128 | return 0; |
131 | } /* mtd_open */ | 129 | } /* mtd_open */ |
132 | 130 | ||
@@ -139,10 +137,10 @@ static int mtd_close(struct inode *inode, struct file *file) | |||
139 | DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); | 137 | DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); |
140 | 138 | ||
141 | mtd = TO_MTD(file); | 139 | mtd = TO_MTD(file); |
142 | 140 | ||
143 | if (mtd->sync) | 141 | if (mtd->sync) |
144 | mtd->sync(mtd); | 142 | mtd->sync(mtd); |
145 | 143 | ||
146 | put_mtd_device(mtd); | 144 | put_mtd_device(mtd); |
147 | 145 | ||
148 | return 0; | 146 | return 0; |
@@ -161,7 +159,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
161 | int ret=0; | 159 | int ret=0; |
162 | int len; | 160 | int len; |
163 | char *kbuf; | 161 | char *kbuf; |
164 | 162 | ||
165 | DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); | 163 | DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); |
166 | 164 | ||
167 | if (*ppos + count > mtd->size) | 165 | if (*ppos + count > mtd->size) |
@@ -169,11 +167,11 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
169 | 167 | ||
170 | if (!count) | 168 | if (!count) |
171 | return 0; | 169 | return 0; |
172 | 170 | ||
173 | /* FIXME: Use kiovec in 2.5 to lock down the user's buffers | 171 | /* FIXME: Use kiovec in 2.5 to lock down the user's buffers |
174 | and pass them directly to the MTD functions */ | 172 | and pass them directly to the MTD functions */ |
175 | while (count) { | 173 | while (count) { |
176 | if (count > MAX_KMALLOC_SIZE) | 174 | if (count > MAX_KMALLOC_SIZE) |
177 | len = MAX_KMALLOC_SIZE; | 175 | len = MAX_KMALLOC_SIZE; |
178 | else | 176 | else |
179 | len = count; | 177 | len = count; |
@@ -181,7 +179,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
181 | kbuf=kmalloc(len,GFP_KERNEL); | 179 | kbuf=kmalloc(len,GFP_KERNEL); |
182 | if (!kbuf) | 180 | if (!kbuf) |
183 | return -ENOMEM; | 181 | return -ENOMEM; |
184 | 182 | ||
185 | switch (MTD_MODE(file)) { | 183 | switch (MTD_MODE(file)) { |
186 | case MTD_MODE_OTP_FACT: | 184 | case MTD_MODE_OTP_FACT: |
187 | ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); | 185 | ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); |
@@ -194,7 +192,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
194 | } | 192 | } |
195 | /* Nand returns -EBADMSG on ecc errors, but it returns | 193 | /* Nand returns -EBADMSG on ecc errors, but it returns |
196 | * the data. For our userspace tools it is important | 194 | * the data. For our userspace tools it is important |
197 | * to dump areas with ecc errors ! | 195 | * to dump areas with ecc errors ! |
198 | * Userspace software which accesses NAND this way | 196 | * Userspace software which accesses NAND this way |
199 | * must be aware of the fact that it deals with NAND | 197 | * must be aware of the fact that it deals with NAND |
200 | */ | 198 | */ |
@@ -216,7 +214,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t | |||
216 | kfree(kbuf); | 214 | kfree(kbuf); |
217 | return ret; | 215 | return ret; |
218 | } | 216 | } |
219 | 217 | ||
220 | kfree(kbuf); | 218 | kfree(kbuf); |
221 | } | 219 | } |
222 | 220 | ||
@@ -233,10 +231,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count | |||
233 | int len; | 231 | int len; |
234 | 232 | ||
235 | DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); | 233 | DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); |
236 | 234 | ||
237 | if (*ppos == mtd->size) | 235 | if (*ppos == mtd->size) |
238 | return -ENOSPC; | 236 | return -ENOSPC; |
239 | 237 | ||
240 | if (*ppos + count > mtd->size) | 238 | if (*ppos + count > mtd->size) |
241 | count = mtd->size - *ppos; | 239 | count = mtd->size - *ppos; |
242 | 240 | ||
@@ -244,7 +242,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count | |||
244 | return 0; | 242 | return 0; |
245 | 243 | ||
246 | while (count) { | 244 | while (count) { |
247 | if (count > MAX_KMALLOC_SIZE) | 245 | if (count > MAX_KMALLOC_SIZE) |
248 | len = MAX_KMALLOC_SIZE; | 246 | len = MAX_KMALLOC_SIZE; |
249 | else | 247 | else |
250 | len = count; | 248 | len = count; |
@@ -259,7 +257,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count | |||
259 | kfree(kbuf); | 257 | kfree(kbuf); |
260 | return -EFAULT; | 258 | return -EFAULT; |
261 | } | 259 | } |
262 | 260 | ||
263 | switch (MTD_MODE(file)) { | 261 | switch (MTD_MODE(file)) { |
264 | case MTD_MODE_OTP_FACT: | 262 | case MTD_MODE_OTP_FACT: |
265 | ret = -EROFS; | 263 | ret = -EROFS; |
@@ -284,7 +282,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count | |||
284 | kfree(kbuf); | 282 | kfree(kbuf); |
285 | return ret; | 283 | return ret; |
286 | } | 284 | } |
287 | 285 | ||
288 | kfree(kbuf); | 286 | kfree(kbuf); |
289 | } | 287 | } |
290 | 288 | ||
@@ -308,7 +306,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
308 | void __user *argp = (void __user *)arg; | 306 | void __user *argp = (void __user *)arg; |
309 | int ret = 0; | 307 | int ret = 0; |
310 | u_long size; | 308 | u_long size; |
311 | 309 | ||
312 | DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); | 310 | DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); |
313 | 311 | ||
314 | size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; | 312 | size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; |
@@ -320,7 +318,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
320 | if (!access_ok(VERIFY_WRITE, argp, size)) | 318 | if (!access_ok(VERIFY_WRITE, argp, size)) |
321 | return -EFAULT; | 319 | return -EFAULT; |
322 | } | 320 | } |
323 | 321 | ||
324 | switch (cmd) { | 322 | switch (cmd) { |
325 | case MEMGETREGIONCOUNT: | 323 | case MEMGETREGIONCOUNT: |
326 | if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) | 324 | if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) |
@@ -372,11 +370,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
372 | erase->mtd = mtd; | 370 | erase->mtd = mtd; |
373 | erase->callback = mtdchar_erase_callback; | 371 | erase->callback = mtdchar_erase_callback; |
374 | erase->priv = (unsigned long)&waitq; | 372 | erase->priv = (unsigned long)&waitq; |
375 | 373 | ||
376 | /* | 374 | /* |
377 | FIXME: Allow INTERRUPTIBLE. Which means | 375 | FIXME: Allow INTERRUPTIBLE. Which means |
378 | not having the wait_queue head on the stack. | 376 | not having the wait_queue head on the stack. |
379 | 377 | ||
380 | If the wq_head is on the stack, and we | 378 | If the wq_head is on the stack, and we |
381 | leave because we got interrupted, then the | 379 | leave because we got interrupted, then the |
382 | wq_head is no longer there when the | 380 | wq_head is no longer there when the |
@@ -404,13 +402,13 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
404 | struct mtd_oob_buf buf; | 402 | struct mtd_oob_buf buf; |
405 | void *databuf; | 403 | void *databuf; |
406 | ssize_t retlen; | 404 | ssize_t retlen; |
407 | 405 | ||
408 | if(!(file->f_mode & 2)) | 406 | if(!(file->f_mode & 2)) |
409 | return -EPERM; | 407 | return -EPERM; |
410 | 408 | ||
411 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) | 409 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) |
412 | return -EFAULT; | 410 | return -EFAULT; |
413 | 411 | ||
414 | if (buf.length > 0x4096) | 412 | if (buf.length > 0x4096) |
415 | return -EINVAL; | 413 | return -EINVAL; |
416 | 414 | ||
@@ -426,7 +424,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
426 | databuf = kmalloc(buf.length, GFP_KERNEL); | 424 | databuf = kmalloc(buf.length, GFP_KERNEL); |
427 | if (!databuf) | 425 | if (!databuf) |
428 | return -ENOMEM; | 426 | return -ENOMEM; |
429 | 427 | ||
430 | if (copy_from_user(databuf, buf.ptr, buf.length)) { | 428 | if (copy_from_user(databuf, buf.ptr, buf.length)) { |
431 | kfree(databuf); | 429 | kfree(databuf); |
432 | return -EFAULT; | 430 | return -EFAULT; |
@@ -450,7 +448,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
450 | 448 | ||
451 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) | 449 | if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) |
452 | return -EFAULT; | 450 | return -EFAULT; |
453 | 451 | ||
454 | if (buf.length > 0x4096) | 452 | if (buf.length > 0x4096) |
455 | return -EINVAL; | 453 | return -EINVAL; |
456 | 454 | ||
@@ -466,14 +464,14 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
466 | databuf = kmalloc(buf.length, GFP_KERNEL); | 464 | databuf = kmalloc(buf.length, GFP_KERNEL); |
467 | if (!databuf) | 465 | if (!databuf) |
468 | return -ENOMEM; | 466 | return -ENOMEM; |
469 | 467 | ||
470 | ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); | 468 | ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); |
471 | 469 | ||
472 | if (put_user(retlen, (uint32_t __user *)argp)) | 470 | if (put_user(retlen, (uint32_t __user *)argp)) |
473 | ret = -EFAULT; | 471 | ret = -EFAULT; |
474 | else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) | 472 | else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) |
475 | ret = -EFAULT; | 473 | ret = -EFAULT; |
476 | 474 | ||
477 | kfree(databuf); | 475 | kfree(databuf); |
478 | break; | 476 | break; |
479 | } | 477 | } |
@@ -523,7 +521,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
523 | case MEMGETBADBLOCK: | 521 | case MEMGETBADBLOCK: |
524 | { | 522 | { |
525 | loff_t offs; | 523 | loff_t offs; |
526 | 524 | ||
527 | if (copy_from_user(&offs, argp, sizeof(loff_t))) | 525 | if (copy_from_user(&offs, argp, sizeof(loff_t))) |
528 | return -EFAULT; | 526 | return -EFAULT; |
529 | if (!mtd->block_isbad) | 527 | if (!mtd->block_isbad) |
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index f3e65af33a9c..b1bf8c411de7 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
@@ -7,14 +7,15 @@ | |||
7 | * | 7 | * |
8 | * This code is GPL | 8 | * This code is GPL |
9 | * | 9 | * |
10 | * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $ | 10 | * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $ |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> | ||
16 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
17 | #include <linux/sched.h> /* TASK_* */ | 16 | #include <linux/sched.h> |
17 | #include <linux/types.h> | ||
18 | |||
18 | #include <linux/mtd/mtd.h> | 19 | #include <linux/mtd/mtd.h> |
19 | #include <linux/mtd/concat.h> | 20 | #include <linux/mtd/concat.h> |
20 | 21 | ||
@@ -43,7 +44,7 @@ struct mtd_concat { | |||
43 | */ | 44 | */ |
44 | #define CONCAT(x) ((struct mtd_concat *)(x)) | 45 | #define CONCAT(x) ((struct mtd_concat *)(x)) |
45 | 46 | ||
46 | /* | 47 | /* |
47 | * MTD methods which look up the relevant subdevice, translate the | 48 | * MTD methods which look up the relevant subdevice, translate the |
48 | * effective address and pass through to the subdevice. | 49 | * effective address and pass through to the subdevice. |
49 | */ | 50 | */ |
@@ -877,7 +878,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c | |||
877 | return &concat->mtd; | 878 | return &concat->mtd; |
878 | } | 879 | } |
879 | 880 | ||
880 | /* | 881 | /* |
881 | * This function destroys an MTD object obtained from concat_mtd_devs() | 882 | * This function destroys an MTD object obtained from concat_mtd_devs() |
882 | */ | 883 | */ |
883 | 884 | ||
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index dc86df18e94b..dade02ab0687 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $ | 2 | * $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $ |
3 | * | 3 | * |
4 | * Core registration and callback routines for MTD | 4 | * Core registration and callback routines for MTD |
5 | * drivers and users. | 5 | * drivers and users. |
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/mtd/mtd.h> | 26 | #include <linux/mtd/mtd.h> |
27 | 27 | ||
28 | /* These are exported solely for the purpose of mtd_blkdevs.c. You | 28 | /* These are exported solely for the purpose of mtd_blkdevs.c. You |
29 | should not use them for _anything_ else */ | 29 | should not use them for _anything_ else */ |
30 | DECLARE_MUTEX(mtd_table_mutex); | 30 | DECLARE_MUTEX(mtd_table_mutex); |
31 | struct mtd_info *mtd_table[MAX_MTD_DEVICES]; | 31 | struct mtd_info *mtd_table[MAX_MTD_DEVICES]; |
@@ -66,7 +66,7 @@ int add_mtd_device(struct mtd_info *mtd) | |||
66 | struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); | 66 | struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); |
67 | not->add(mtd); | 67 | not->add(mtd); |
68 | } | 68 | } |
69 | 69 | ||
70 | up(&mtd_table_mutex); | 70 | up(&mtd_table_mutex); |
71 | /* We _know_ we aren't being removed, because | 71 | /* We _know_ we aren't being removed, because |
72 | our caller is still holding us here. So none | 72 | our caller is still holding us here. So none |
@@ -75,7 +75,7 @@ int add_mtd_device(struct mtd_info *mtd) | |||
75 | __module_get(THIS_MODULE); | 75 | __module_get(THIS_MODULE); |
76 | return 0; | 76 | return 0; |
77 | } | 77 | } |
78 | 78 | ||
79 | up(&mtd_table_mutex); | 79 | up(&mtd_table_mutex); |
80 | return 1; | 80 | return 1; |
81 | } | 81 | } |
@@ -93,13 +93,13 @@ int add_mtd_device(struct mtd_info *mtd) | |||
93 | int del_mtd_device (struct mtd_info *mtd) | 93 | int del_mtd_device (struct mtd_info *mtd) |
94 | { | 94 | { |
95 | int ret; | 95 | int ret; |
96 | 96 | ||
97 | down(&mtd_table_mutex); | 97 | down(&mtd_table_mutex); |
98 | 98 | ||
99 | if (mtd_table[mtd->index] != mtd) { | 99 | if (mtd_table[mtd->index] != mtd) { |
100 | ret = -ENODEV; | 100 | ret = -ENODEV; |
101 | } else if (mtd->usecount) { | 101 | } else if (mtd->usecount) { |
102 | printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", | 102 | printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", |
103 | mtd->index, mtd->name, mtd->usecount); | 103 | mtd->index, mtd->name, mtd->usecount); |
104 | ret = -EBUSY; | 104 | ret = -EBUSY; |
105 | } else { | 105 | } else { |
@@ -140,7 +140,7 @@ void register_mtd_user (struct mtd_notifier *new) | |||
140 | list_add(&new->list, &mtd_notifiers); | 140 | list_add(&new->list, &mtd_notifiers); |
141 | 141 | ||
142 | __module_get(THIS_MODULE); | 142 | __module_get(THIS_MODULE); |
143 | 143 | ||
144 | for (i=0; i< MAX_MTD_DEVICES; i++) | 144 | for (i=0; i< MAX_MTD_DEVICES; i++) |
145 | if (mtd_table[i]) | 145 | if (mtd_table[i]) |
146 | new->add(mtd_table[i]); | 146 | new->add(mtd_table[i]); |
@@ -169,7 +169,7 @@ int unregister_mtd_user (struct mtd_notifier *old) | |||
169 | for (i=0; i< MAX_MTD_DEVICES; i++) | 169 | for (i=0; i< MAX_MTD_DEVICES; i++) |
170 | if (mtd_table[i]) | 170 | if (mtd_table[i]) |
171 | old->remove(mtd_table[i]); | 171 | old->remove(mtd_table[i]); |
172 | 172 | ||
173 | list_del(&old->list); | 173 | list_del(&old->list); |
174 | up(&mtd_table_mutex); | 174 | up(&mtd_table_mutex); |
175 | return 0; | 175 | return 0; |
@@ -187,7 +187,7 @@ int unregister_mtd_user (struct mtd_notifier *old) | |||
187 | * both, return the num'th driver only if its address matches. Return NULL | 187 | * both, return the num'th driver only if its address matches. Return NULL |
188 | * if not. | 188 | * if not. |
189 | */ | 189 | */ |
190 | 190 | ||
191 | struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) | 191 | struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) |
192 | { | 192 | { |
193 | struct mtd_info *ret = NULL; | 193 | struct mtd_info *ret = NULL; |
@@ -297,39 +297,6 @@ EXPORT_SYMBOL(default_mtd_writev); | |||
297 | EXPORT_SYMBOL(default_mtd_readv); | 297 | EXPORT_SYMBOL(default_mtd_readv); |
298 | 298 | ||
299 | /*====================================================================*/ | 299 | /*====================================================================*/ |
300 | /* Power management code */ | ||
301 | |||
302 | #ifdef CONFIG_PM | ||
303 | |||
304 | #include <linux/pm.h> | ||
305 | |||
306 | static struct pm_dev *mtd_pm_dev = NULL; | ||
307 | |||
308 | static int mtd_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) | ||
309 | { | ||
310 | int ret = 0, i; | ||
311 | |||
312 | if (down_trylock(&mtd_table_mutex)) | ||
313 | return -EAGAIN; | ||
314 | if (rqst == PM_SUSPEND) { | ||
315 | for (i = 0; ret == 0 && i < MAX_MTD_DEVICES; i++) { | ||
316 | if (mtd_table[i] && mtd_table[i]->suspend) | ||
317 | ret = mtd_table[i]->suspend(mtd_table[i]); | ||
318 | } | ||
319 | } else i = MAX_MTD_DEVICES-1; | ||
320 | |||
321 | if (rqst == PM_RESUME || ret) { | ||
322 | for ( ; i >= 0; i--) { | ||
323 | if (mtd_table[i] && mtd_table[i]->resume) | ||
324 | mtd_table[i]->resume(mtd_table[i]); | ||
325 | } | ||
326 | } | ||
327 | up(&mtd_table_mutex); | ||
328 | return ret; | ||
329 | } | ||
330 | #endif | ||
331 | |||
332 | /*====================================================================*/ | ||
333 | /* Support for /proc/mtd */ | 300 | /* Support for /proc/mtd */ |
334 | 301 | ||
335 | #ifdef CONFIG_PROC_FS | 302 | #ifdef CONFIG_PROC_FS |
@@ -388,22 +355,11 @@ static int __init init_mtd(void) | |||
388 | if ((proc_mtd = create_proc_entry( "mtd", 0, NULL ))) | 355 | if ((proc_mtd = create_proc_entry( "mtd", 0, NULL ))) |
389 | proc_mtd->read_proc = mtd_read_proc; | 356 | proc_mtd->read_proc = mtd_read_proc; |
390 | #endif | 357 | #endif |
391 | |||
392 | #ifdef CONFIG_PM | ||
393 | mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback); | ||
394 | #endif | ||
395 | return 0; | 358 | return 0; |
396 | } | 359 | } |
397 | 360 | ||
398 | static void __exit cleanup_mtd(void) | 361 | static void __exit cleanup_mtd(void) |
399 | { | 362 | { |
400 | #ifdef CONFIG_PM | ||
401 | if (mtd_pm_dev) { | ||
402 | pm_unregister(mtd_pm_dev); | ||
403 | mtd_pm_dev = NULL; | ||
404 | } | ||
405 | #endif | ||
406 | |||
407 | #ifdef CONFIG_PROC_FS | 363 | #ifdef CONFIG_PROC_FS |
408 | if (proc_mtd) | 364 | if (proc_mtd) |
409 | remove_proc_entry( "mtd", NULL); | 365 | remove_proc_entry( "mtd", NULL); |
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index b92e6bfffaf2..99395911d26f 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -5,11 +5,11 @@ | |||
5 | * | 5 | * |
6 | * This code is GPL | 6 | * This code is GPL |
7 | * | 7 | * |
8 | * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $ | 8 | * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $ |
9 | * | 9 | * |
10 | * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> | 10 | * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> |
11 | * added support for read_oob, write_oob | 11 | * added support for read_oob, write_oob |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/types.h> | 15 | #include <linux/types.h> |
@@ -41,13 +41,13 @@ struct mtd_part { | |||
41 | */ | 41 | */ |
42 | #define PART(x) ((struct mtd_part *)(x)) | 42 | #define PART(x) ((struct mtd_part *)(x)) |
43 | 43 | ||
44 | 44 | ||
45 | /* | 45 | /* |
46 | * MTD methods which simply translate the effective address and pass through | 46 | * MTD methods which simply translate the effective address and pass through |
47 | * to the _real_ device. | 47 | * to the _real_ device. |
48 | */ | 48 | */ |
49 | 49 | ||
50 | static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | 50 | static int part_read (struct mtd_info *mtd, loff_t from, size_t len, |
51 | size_t *retlen, u_char *buf) | 51 | size_t *retlen, u_char *buf) |
52 | { | 52 | { |
53 | struct mtd_part *part = PART(mtd); | 53 | struct mtd_part *part = PART(mtd); |
@@ -55,15 +55,15 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | |||
55 | len = 0; | 55 | len = 0; |
56 | else if (from + len > mtd->size) | 56 | else if (from + len > mtd->size) |
57 | len = mtd->size - from; | 57 | len = mtd->size - from; |
58 | if (part->master->read_ecc == NULL) | 58 | if (part->master->read_ecc == NULL) |
59 | return part->master->read (part->master, from + part->offset, | 59 | return part->master->read (part->master, from + part->offset, |
60 | len, retlen, buf); | 60 | len, retlen, buf); |
61 | else | 61 | else |
62 | return part->master->read_ecc (part->master, from + part->offset, | 62 | return part->master->read_ecc (part->master, from + part->offset, |
63 | len, retlen, buf, NULL, &mtd->oobinfo); | 63 | len, retlen, buf, NULL, &mtd->oobinfo); |
64 | } | 64 | } |
65 | 65 | ||
66 | static int part_point (struct mtd_info *mtd, loff_t from, size_t len, | 66 | static int part_point (struct mtd_info *mtd, loff_t from, size_t len, |
67 | size_t *retlen, u_char **buf) | 67 | size_t *retlen, u_char **buf) |
68 | { | 68 | { |
69 | struct mtd_part *part = PART(mtd); | 69 | struct mtd_part *part = PART(mtd); |
@@ -71,7 +71,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len, | |||
71 | len = 0; | 71 | len = 0; |
72 | else if (from + len > mtd->size) | 72 | else if (from + len > mtd->size) |
73 | len = mtd->size - from; | 73 | len = mtd->size - from; |
74 | return part->master->point (part->master, from + part->offset, | 74 | return part->master->point (part->master, from + part->offset, |
75 | len, retlen, buf); | 75 | len, retlen, buf); |
76 | } | 76 | } |
77 | static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) | 77 | static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) |
@@ -82,7 +82,7 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_ | |||
82 | } | 82 | } |
83 | 83 | ||
84 | 84 | ||
85 | static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | 85 | static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, |
86 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) | 86 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) |
87 | { | 87 | { |
88 | struct mtd_part *part = PART(mtd); | 88 | struct mtd_part *part = PART(mtd); |
@@ -92,11 +92,11 @@ static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
92 | len = 0; | 92 | len = 0; |
93 | else if (from + len > mtd->size) | 93 | else if (from + len > mtd->size) |
94 | len = mtd->size - from; | 94 | len = mtd->size - from; |
95 | return part->master->read_ecc (part->master, from + part->offset, | 95 | return part->master->read_ecc (part->master, from + part->offset, |
96 | len, retlen, buf, eccbuf, oobsel); | 96 | len, retlen, buf, eccbuf, oobsel); |
97 | } | 97 | } |
98 | 98 | ||
99 | static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, | 99 | static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, |
100 | size_t *retlen, u_char *buf) | 100 | size_t *retlen, u_char *buf) |
101 | { | 101 | { |
102 | struct mtd_part *part = PART(mtd); | 102 | struct mtd_part *part = PART(mtd); |
@@ -104,15 +104,15 @@ static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, | |||
104 | len = 0; | 104 | len = 0; |
105 | else if (from + len > mtd->size) | 105 | else if (from + len > mtd->size) |
106 | len = mtd->size - from; | 106 | len = mtd->size - from; |
107 | return part->master->read_oob (part->master, from + part->offset, | 107 | return part->master->read_oob (part->master, from + part->offset, |
108 | len, retlen, buf); | 108 | len, retlen, buf); |
109 | } | 109 | } |
110 | 110 | ||
111 | static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 111 | static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, |
112 | size_t *retlen, u_char *buf) | 112 | size_t *retlen, u_char *buf) |
113 | { | 113 | { |
114 | struct mtd_part *part = PART(mtd); | 114 | struct mtd_part *part = PART(mtd); |
115 | return part->master->read_user_prot_reg (part->master, from, | 115 | return part->master->read_user_prot_reg (part->master, from, |
116 | len, retlen, buf); | 116 | len, retlen, buf); |
117 | } | 117 | } |
118 | 118 | ||
@@ -123,11 +123,11 @@ static int part_get_user_prot_info (struct mtd_info *mtd, | |||
123 | return part->master->get_user_prot_info (part->master, buf, len); | 123 | return part->master->get_user_prot_info (part->master, buf, len); |
124 | } | 124 | } |
125 | 125 | ||
126 | static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 126 | static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, |
127 | size_t *retlen, u_char *buf) | 127 | size_t *retlen, u_char *buf) |
128 | { | 128 | { |
129 | struct mtd_part *part = PART(mtd); | 129 | struct mtd_part *part = PART(mtd); |
130 | return part->master->read_fact_prot_reg (part->master, from, | 130 | return part->master->read_fact_prot_reg (part->master, from, |
131 | len, retlen, buf); | 131 | len, retlen, buf); |
132 | } | 132 | } |
133 | 133 | ||
@@ -148,13 +148,13 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
148 | len = 0; | 148 | len = 0; |
149 | else if (to + len > mtd->size) | 149 | else if (to + len > mtd->size) |
150 | len = mtd->size - to; | 150 | len = mtd->size - to; |
151 | if (part->master->write_ecc == NULL) | 151 | if (part->master->write_ecc == NULL) |
152 | return part->master->write (part->master, to + part->offset, | 152 | return part->master->write (part->master, to + part->offset, |
153 | len, retlen, buf); | 153 | len, retlen, buf); |
154 | else | 154 | else |
155 | return part->master->write_ecc (part->master, to + part->offset, | 155 | return part->master->write_ecc (part->master, to + part->offset, |
156 | len, retlen, buf, NULL, &mtd->oobinfo); | 156 | len, retlen, buf, NULL, &mtd->oobinfo); |
157 | 157 | ||
158 | } | 158 | } |
159 | 159 | ||
160 | static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | 160 | static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, |
@@ -170,7 +170,7 @@ static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
170 | len = 0; | 170 | len = 0; |
171 | else if (to + len > mtd->size) | 171 | else if (to + len > mtd->size) |
172 | len = mtd->size - to; | 172 | len = mtd->size - to; |
173 | return part->master->write_ecc (part->master, to + part->offset, | 173 | return part->master->write_ecc (part->master, to + part->offset, |
174 | len, retlen, buf, eccbuf, oobsel); | 174 | len, retlen, buf, eccbuf, oobsel); |
175 | } | 175 | } |
176 | 176 | ||
@@ -184,19 +184,19 @@ static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, | |||
184 | len = 0; | 184 | len = 0; |
185 | else if (to + len > mtd->size) | 185 | else if (to + len > mtd->size) |
186 | len = mtd->size - to; | 186 | len = mtd->size - to; |
187 | return part->master->write_oob (part->master, to + part->offset, | 187 | return part->master->write_oob (part->master, to + part->offset, |
188 | len, retlen, buf); | 188 | len, retlen, buf); |
189 | } | 189 | } |
190 | 190 | ||
191 | static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, | 191 | static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, |
192 | size_t *retlen, u_char *buf) | 192 | size_t *retlen, u_char *buf) |
193 | { | 193 | { |
194 | struct mtd_part *part = PART(mtd); | 194 | struct mtd_part *part = PART(mtd); |
195 | return part->master->write_user_prot_reg (part->master, from, | 195 | return part->master->write_user_prot_reg (part->master, from, |
196 | len, retlen, buf); | 196 | len, retlen, buf); |
197 | } | 197 | } |
198 | 198 | ||
199 | static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) | 199 | static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) |
200 | { | 200 | { |
201 | struct mtd_part *part = PART(mtd); | 201 | struct mtd_part *part = PART(mtd); |
202 | return part->master->lock_user_prot_reg (part->master, from, len); | 202 | return part->master->lock_user_prot_reg (part->master, from, len); |
@@ -208,7 +208,7 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, | |||
208 | struct mtd_part *part = PART(mtd); | 208 | struct mtd_part *part = PART(mtd); |
209 | if (!(mtd->flags & MTD_WRITEABLE)) | 209 | if (!(mtd->flags & MTD_WRITEABLE)) |
210 | return -EROFS; | 210 | return -EROFS; |
211 | if (part->master->writev_ecc == NULL) | 211 | if (part->master->writev_ecc == NULL) |
212 | return part->master->writev (part->master, vecs, count, | 212 | return part->master->writev (part->master, vecs, count, |
213 | to + part->offset, retlen); | 213 | to + part->offset, retlen); |
214 | else | 214 | else |
@@ -221,12 +221,12 @@ static int part_readv (struct mtd_info *mtd, struct kvec *vecs, | |||
221 | unsigned long count, loff_t from, size_t *retlen) | 221 | unsigned long count, loff_t from, size_t *retlen) |
222 | { | 222 | { |
223 | struct mtd_part *part = PART(mtd); | 223 | struct mtd_part *part = PART(mtd); |
224 | if (part->master->readv_ecc == NULL) | 224 | if (part->master->readv_ecc == NULL) |
225 | return part->master->readv (part->master, vecs, count, | 225 | return part->master->readv (part->master, vecs, count, |
226 | from + part->offset, retlen); | 226 | from + part->offset, retlen); |
227 | else | 227 | else |
228 | return part->master->readv_ecc (part->master, vecs, count, | 228 | return part->master->readv_ecc (part->master, vecs, count, |
229 | from + part->offset, retlen, | 229 | from + part->offset, retlen, |
230 | NULL, &mtd->oobinfo); | 230 | NULL, &mtd->oobinfo); |
231 | } | 231 | } |
232 | 232 | ||
@@ -252,7 +252,7 @@ static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs, | |||
252 | if (oobsel == NULL) | 252 | if (oobsel == NULL) |
253 | oobsel = &mtd->oobinfo; | 253 | oobsel = &mtd->oobinfo; |
254 | return part->master->readv_ecc (part->master, vecs, count, | 254 | return part->master->readv_ecc (part->master, vecs, count, |
255 | from + part->offset, retlen, | 255 | from + part->offset, retlen, |
256 | eccbuf, oobsel); | 256 | eccbuf, oobsel); |
257 | } | 257 | } |
258 | 258 | ||
@@ -286,7 +286,7 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback); | |||
286 | static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) | 286 | static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) |
287 | { | 287 | { |
288 | struct mtd_part *part = PART(mtd); | 288 | struct mtd_part *part = PART(mtd); |
289 | if ((len + ofs) > mtd->size) | 289 | if ((len + ofs) > mtd->size) |
290 | return -EINVAL; | 290 | return -EINVAL; |
291 | return part->master->lock(part->master, ofs + part->offset, len); | 291 | return part->master->lock(part->master, ofs + part->offset, len); |
292 | } | 292 | } |
@@ -294,7 +294,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) | |||
294 | static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) | 294 | static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) |
295 | { | 295 | { |
296 | struct mtd_part *part = PART(mtd); | 296 | struct mtd_part *part = PART(mtd); |
297 | if ((len + ofs) > mtd->size) | 297 | if ((len + ofs) > mtd->size) |
298 | return -EINVAL; | 298 | return -EINVAL; |
299 | return part->master->unlock(part->master, ofs + part->offset, len); | 299 | return part->master->unlock(part->master, ofs + part->offset, len); |
300 | } | 300 | } |
@@ -337,8 +337,8 @@ static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) | |||
337 | return part->master->block_markbad(part->master, ofs); | 337 | return part->master->block_markbad(part->master, ofs); |
338 | } | 338 | } |
339 | 339 | ||
340 | /* | 340 | /* |
341 | * This function unregisters and destroy all slave MTD objects which are | 341 | * This function unregisters and destroy all slave MTD objects which are |
342 | * attached to the given master MTD object. | 342 | * attached to the given master MTD object. |
343 | */ | 343 | */ |
344 | 344 | ||
@@ -371,7 +371,7 @@ int del_mtd_partitions(struct mtd_info *master) | |||
371 | * (Q: should we register the master MTD object as well?) | 371 | * (Q: should we register the master MTD object as well?) |
372 | */ | 372 | */ |
373 | 373 | ||
374 | int add_mtd_partitions(struct mtd_info *master, | 374 | int add_mtd_partitions(struct mtd_info *master, |
375 | const struct mtd_partition *parts, | 375 | const struct mtd_partition *parts, |
376 | int nbparts) | 376 | int nbparts) |
377 | { | 377 | { |
@@ -414,7 +414,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
414 | slave->mtd.point = part_point; | 414 | slave->mtd.point = part_point; |
415 | slave->mtd.unpoint = part_unpoint; | 415 | slave->mtd.unpoint = part_unpoint; |
416 | } | 416 | } |
417 | 417 | ||
418 | if (master->read_ecc) | 418 | if (master->read_ecc) |
419 | slave->mtd.read_ecc = part_read_ecc; | 419 | slave->mtd.read_ecc = part_read_ecc; |
420 | if (master->write_ecc) | 420 | if (master->write_ecc) |
@@ -465,9 +465,10 @@ int add_mtd_partitions(struct mtd_info *master, | |||
465 | if (slave->offset == MTDPART_OFS_APPEND) | 465 | if (slave->offset == MTDPART_OFS_APPEND) |
466 | slave->offset = cur_offset; | 466 | slave->offset = cur_offset; |
467 | if (slave->offset == MTDPART_OFS_NXTBLK) { | 467 | if (slave->offset == MTDPART_OFS_NXTBLK) { |
468 | u_int32_t emask = master->erasesize-1; | 468 | slave->offset = cur_offset; |
469 | slave->offset = (cur_offset + emask) & ~emask; | 469 | if ((cur_offset % master->erasesize) != 0) { |
470 | if (slave->offset != cur_offset) { | 470 | /* Round up to next erasesize */ |
471 | slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; | ||
471 | printk(KERN_NOTICE "Moving partition %d: " | 472 | printk(KERN_NOTICE "Moving partition %d: " |
472 | "0x%08x -> 0x%08x\n", i, | 473 | "0x%08x -> 0x%08x\n", i, |
473 | cur_offset, slave->offset); | 474 | cur_offset, slave->offset); |
@@ -476,8 +477,8 @@ int add_mtd_partitions(struct mtd_info *master, | |||
476 | if (slave->mtd.size == MTDPART_SIZ_FULL) | 477 | if (slave->mtd.size == MTDPART_SIZ_FULL) |
477 | slave->mtd.size = master->size - slave->offset; | 478 | slave->mtd.size = master->size - slave->offset; |
478 | cur_offset = slave->offset + slave->mtd.size; | 479 | cur_offset = slave->offset + slave->mtd.size; |
479 | 480 | ||
480 | printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, | 481 | printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, |
481 | slave->offset + slave->mtd.size, slave->mtd.name); | 482 | slave->offset + slave->mtd.size, slave->mtd.name); |
482 | 483 | ||
483 | /* let's do some sanity checks */ | 484 | /* let's do some sanity checks */ |
@@ -497,7 +498,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
497 | /* Deal with variable erase size stuff */ | 498 | /* Deal with variable erase size stuff */ |
498 | int i; | 499 | int i; |
499 | struct mtd_erase_region_info *regions = master->eraseregions; | 500 | struct mtd_erase_region_info *regions = master->eraseregions; |
500 | 501 | ||
501 | /* Find the first erase regions which is part of this partition. */ | 502 | /* Find the first erase regions which is part of this partition. */ |
502 | for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) | 503 | for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) |
503 | ; | 504 | ; |
@@ -512,7 +513,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
512 | slave->mtd.erasesize = master->erasesize; | 513 | slave->mtd.erasesize = master->erasesize; |
513 | } | 514 | } |
514 | 515 | ||
515 | if ((slave->mtd.flags & MTD_WRITEABLE) && | 516 | if ((slave->mtd.flags & MTD_WRITEABLE) && |
516 | (slave->offset % slave->mtd.erasesize)) { | 517 | (slave->offset % slave->mtd.erasesize)) { |
517 | /* Doesn't start on a boundary of major erase size */ | 518 | /* Doesn't start on a boundary of major erase size */ |
518 | /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ | 519 | /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ |
@@ -520,14 +521,14 @@ int add_mtd_partitions(struct mtd_info *master, | |||
520 | printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", | 521 | printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", |
521 | parts[i].name); | 522 | parts[i].name); |
522 | } | 523 | } |
523 | if ((slave->mtd.flags & MTD_WRITEABLE) && | 524 | if ((slave->mtd.flags & MTD_WRITEABLE) && |
524 | (slave->mtd.size % slave->mtd.erasesize)) { | 525 | (slave->mtd.size % slave->mtd.erasesize)) { |
525 | slave->mtd.flags &= ~MTD_WRITEABLE; | 526 | slave->mtd.flags &= ~MTD_WRITEABLE; |
526 | printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", | 527 | printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", |
527 | parts[i].name); | 528 | parts[i].name); |
528 | } | 529 | } |
529 | 530 | ||
530 | /* copy oobinfo from master */ | 531 | /* copy oobinfo from master */ |
531 | memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo)); | 532 | memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo)); |
532 | 533 | ||
533 | if(parts[i].mtdp) | 534 | if(parts[i].mtdp) |
@@ -588,12 +589,12 @@ int deregister_mtd_parser(struct mtd_part_parser *p) | |||
588 | return 0; | 589 | return 0; |
589 | } | 590 | } |
590 | 591 | ||
591 | int parse_mtd_partitions(struct mtd_info *master, const char **types, | 592 | int parse_mtd_partitions(struct mtd_info *master, const char **types, |
592 | struct mtd_partition **pparts, unsigned long origin) | 593 | struct mtd_partition **pparts, unsigned long origin) |
593 | { | 594 | { |
594 | struct mtd_part_parser *parser; | 595 | struct mtd_part_parser *parser; |
595 | int ret = 0; | 596 | int ret = 0; |
596 | 597 | ||
597 | for ( ; ret <= 0 && *types; types++) { | 598 | for ( ; ret <= 0 && *types; types++) { |
598 | parser = get_partition_parser(*types); | 599 | parser = get_partition_parser(*types); |
599 | #ifdef CONFIG_KMOD | 600 | #ifdef CONFIG_KMOD |
@@ -607,7 +608,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, | |||
607 | } | 608 | } |
608 | ret = (*parser->parse_fn)(master, pparts, origin); | 609 | ret = (*parser->parse_fn)(master, pparts, origin); |
609 | if (ret > 0) { | 610 | if (ret > 0) { |
610 | printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", | 611 | printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", |
611 | ret, parser->name, master->name); | 612 | ret, parser->name, master->name); |
612 | } | 613 | } |
613 | put_partition_parser(parser); | 614 | put_partition_parser(parser); |
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 36d34e5e5a5a..1fc4c134d939 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -1,5 +1,5 @@ | |||
1 | # drivers/mtd/nand/Kconfig | 1 | # drivers/mtd/nand/Kconfig |
2 | # $Id: Kconfig,v 1.31 2005/06/20 12:03:21 bjd Exp $ | 2 | # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ |
3 | 3 | ||
4 | menu "NAND Flash Device Drivers" | 4 | menu "NAND Flash Device Drivers" |
5 | depends on MTD!=n | 5 | depends on MTD!=n |
@@ -25,33 +25,33 @@ config MTD_NAND_VERIFY_WRITE | |||
25 | 25 | ||
26 | config MTD_NAND_AUTCPU12 | 26 | config MTD_NAND_AUTCPU12 |
27 | tristate "SmartMediaCard on autronix autcpu12 board" | 27 | tristate "SmartMediaCard on autronix autcpu12 board" |
28 | depends on ARM && MTD_NAND && ARCH_AUTCPU12 | 28 | depends on MTD_NAND && ARCH_AUTCPU12 |
29 | help | 29 | help |
30 | This enables the driver for the autronix autcpu12 board to | 30 | This enables the driver for the autronix autcpu12 board to |
31 | access the SmartMediaCard. | 31 | access the SmartMediaCard. |
32 | 32 | ||
33 | config MTD_NAND_EDB7312 | 33 | config MTD_NAND_EDB7312 |
34 | tristate "Support for Cirrus Logic EBD7312 evaluation board" | 34 | tristate "Support for Cirrus Logic EBD7312 evaluation board" |
35 | depends on ARM && MTD_NAND && ARCH_EDB7312 | 35 | depends on MTD_NAND && ARCH_EDB7312 |
36 | help | 36 | help |
37 | This enables the driver for the Cirrus Logic EBD7312 evaluation | 37 | This enables the driver for the Cirrus Logic EBD7312 evaluation |
38 | board to access the onboard NAND Flash. | 38 | board to access the onboard NAND Flash. |
39 | 39 | ||
40 | config MTD_NAND_H1900 | 40 | config MTD_NAND_H1900 |
41 | tristate "iPAQ H1900 flash" | 41 | tristate "iPAQ H1900 flash" |
42 | depends on ARM && MTD_NAND && ARCH_PXA && MTD_PARTITIONS | 42 | depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS |
43 | help | 43 | help |
44 | This enables the driver for the iPAQ h1900 flash. | 44 | This enables the driver for the iPAQ h1900 flash. |
45 | 45 | ||
46 | config MTD_NAND_SPIA | 46 | config MTD_NAND_SPIA |
47 | tristate "NAND Flash device on SPIA board" | 47 | tristate "NAND Flash device on SPIA board" |
48 | depends on ARM && ARCH_P720T && MTD_NAND | 48 | depends on ARCH_P720T && MTD_NAND |
49 | help | 49 | help |
50 | If you had to ask, you don't have one. Say 'N'. | 50 | If you had to ask, you don't have one. Say 'N'. |
51 | 51 | ||
52 | config MTD_NAND_TOTO | 52 | config MTD_NAND_TOTO |
53 | tristate "NAND Flash device on TOTO board" | 53 | tristate "NAND Flash device on TOTO board" |
54 | depends on ARM && ARCH_OMAP && MTD_NAND | 54 | depends on ARCH_OMAP && MTD_NAND |
55 | help | 55 | help |
56 | Support for NAND flash on Texas Instruments Toto platform. | 56 | Support for NAND flash on Texas Instruments Toto platform. |
57 | 57 | ||
@@ -59,8 +59,8 @@ config MTD_NAND_IDS | |||
59 | tristate | 59 | tristate |
60 | 60 | ||
61 | config MTD_NAND_AU1550 | 61 | config MTD_NAND_AU1550 |
62 | tristate "Au1550 NAND support" | 62 | tristate "Au1550/1200 NAND support" |
63 | depends on SOC_AU1550 && MTD_NAND | 63 | depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND |
64 | help | 64 | help |
65 | This enables the driver for the NAND flash controller on the | 65 | This enables the driver for the NAND flash controller on the |
66 | AMD/Alchemy 1550 SOC. | 66 | AMD/Alchemy 1550 SOC. |
@@ -71,7 +71,7 @@ config MTD_NAND_RTC_FROM4 | |||
71 | select REED_SOLOMON | 71 | select REED_SOLOMON |
72 | select REED_SOLOMON_DEC8 | 72 | select REED_SOLOMON_DEC8 |
73 | help | 73 | help |
74 | This enables the driver for the Renesas Technology AG-AND | 74 | This enables the driver for the Renesas Technology AG-AND |
75 | flash interface board (FROM_BOARD4) | 75 | flash interface board (FROM_BOARD4) |
76 | 76 | ||
77 | config MTD_NAND_PPCHAMELEONEVB | 77 | config MTD_NAND_PPCHAMELEONEVB |
@@ -88,7 +88,7 @@ config MTD_NAND_S3C2410 | |||
88 | SoCs | 88 | SoCs |
89 | 89 | ||
90 | No board specfic support is done by this driver, each board | 90 | No board specfic support is done by this driver, each board |
91 | must advertise a platform_device for the driver to attach. | 91 | must advertise a platform_device for the driver to attach. |
92 | 92 | ||
93 | config MTD_NAND_S3C2410_DEBUG | 93 | config MTD_NAND_S3C2410_DEBUG |
94 | bool "S3C2410 NAND driver debug" | 94 | bool "S3C2410 NAND driver debug" |
@@ -181,7 +181,7 @@ config MTD_NAND_DISKONCHIP_BBTWRITE | |||
181 | 181 | ||
182 | config MTD_NAND_SHARPSL | 182 | config MTD_NAND_SHARPSL |
183 | bool "Support for NAND Flash on Sharp SL Series (C7xx + others)" | 183 | bool "Support for NAND Flash on Sharp SL Series (C7xx + others)" |
184 | depends on MTD_NAND && ARCH_PXA | 184 | depends on MTD_NAND && ARCH_PXA |
185 | 185 | ||
186 | config MTD_NAND_NANDSIM | 186 | config MTD_NAND_NANDSIM |
187 | bool "Support for NAND Flash Simulator" | 187 | bool "Support for NAND Flash Simulator" |
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 4c7719ce3f48..3cafcdf28aed 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2004 Embedded Edge, LLC | 4 | * Copyright (C) 2004 Embedded Edge, LLC |
5 | * | 5 | * |
6 | * $Id: au1550nd.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $ | 6 | * $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 gleixner Exp $ |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -21,20 +21,14 @@ | |||
21 | 21 | ||
22 | /* fixme: this is ugly */ | 22 | /* fixme: this is ugly */ |
23 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0) | 23 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0) |
24 | #include <asm/mach-au1x00/au1000.h> | 24 | #include <asm/mach-au1x00/au1xxx.h> |
25 | #ifdef CONFIG_MIPS_PB1550 | ||
26 | #include <asm/mach-pb1x00/pb1550.h> | ||
27 | #endif | ||
28 | #ifdef CONFIG_MIPS_DB1550 | ||
29 | #include <asm/mach-db1x00/db1x00.h> | ||
30 | #endif | ||
31 | #else | 25 | #else |
32 | #include <asm/au1000.h> | 26 | #include <asm/au1000.h> |
33 | #ifdef CONFIG_MIPS_PB1550 | 27 | #ifdef CONFIG_MIPS_PB1550 |
34 | #include <asm/pb1550.h> | 28 | #include <asm/pb1550.h> |
35 | #endif | 29 | #endif |
36 | #ifdef CONFIG_MIPS_DB1550 | 30 | #ifdef CONFIG_MIPS_DB1550 |
37 | #include <asm/db1x00.h> | 31 | #include <asm/db1x00.h> |
38 | #endif | 32 | #endif |
39 | #endif | 33 | #endif |
40 | 34 | ||
@@ -45,39 +39,22 @@ static struct mtd_info *au1550_mtd = NULL; | |||
45 | static void __iomem *p_nand; | 39 | static void __iomem *p_nand; |
46 | static int nand_width = 1; /* default x8*/ | 40 | static int nand_width = 1; /* default x8*/ |
47 | 41 | ||
48 | #define NAND_CS 1 | ||
49 | |||
50 | /* | 42 | /* |
51 | * Define partitions for flash device | 43 | * Define partitions for flash device |
52 | */ | 44 | */ |
53 | const static struct mtd_partition partition_info[] = { | 45 | const static struct mtd_partition partition_info[] = { |
54 | #ifdef CONFIG_MIPS_PB1550 | 46 | { |
55 | #define NUM_PARTITIONS 2 | 47 | .name = "NAND FS 0", |
56 | { | ||
57 | .name = "Pb1550 NAND FS 0", | ||
58 | .offset = 0, | 48 | .offset = 0, |
59 | .size = 8*1024*1024 | 49 | .size = 8*1024*1024 |
60 | }, | 50 | }, |
61 | { | 51 | { |
62 | .name = "Pb1550 NAND FS 1", | 52 | .name = "NAND FS 1", |
63 | .offset = MTDPART_OFS_APPEND, | 53 | .offset = MTDPART_OFS_APPEND, |
64 | .size = MTDPART_SIZ_FULL | 54 | .size = MTDPART_SIZ_FULL |
65 | } | 55 | } |
66 | #endif | ||
67 | #ifdef CONFIG_MIPS_DB1550 | ||
68 | #define NUM_PARTITIONS 2 | ||
69 | { | ||
70 | .name = "Db1550 NAND FS 0", | ||
71 | .offset = 0, | ||
72 | .size = 8*1024*1024 | ||
73 | }, | ||
74 | { | ||
75 | .name = "Db1550 NAND FS 1", | ||
76 | .offset = MTDPART_OFS_APPEND, | ||
77 | .size = MTDPART_SIZ_FULL | ||
78 | } | ||
79 | #endif | ||
80 | }; | 56 | }; |
57 | #define NB_OF(x) (sizeof(x)/sizeof(x[0])) | ||
81 | 58 | ||
82 | 59 | ||
83 | /** | 60 | /** |
@@ -112,7 +89,7 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte) | |||
112 | * au_read_byte16 - read one byte endianess aware from the chip | 89 | * au_read_byte16 - read one byte endianess aware from the chip |
113 | * @mtd: MTD device structure | 90 | * @mtd: MTD device structure |
114 | * | 91 | * |
115 | * read function for 16bit buswith with | 92 | * read function for 16bit buswith with |
116 | * endianess conversion | 93 | * endianess conversion |
117 | */ | 94 | */ |
118 | static u_char au_read_byte16(struct mtd_info *mtd) | 95 | static u_char au_read_byte16(struct mtd_info *mtd) |
@@ -142,7 +119,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte) | |||
142 | * au_read_word - read one word from the chip | 119 | * au_read_word - read one word from the chip |
143 | * @mtd: MTD device structure | 120 | * @mtd: MTD device structure |
144 | * | 121 | * |
145 | * read function for 16bit buswith without | 122 | * read function for 16bit buswith without |
146 | * endianess conversion | 123 | * endianess conversion |
147 | */ | 124 | */ |
148 | static u16 au_read_word(struct mtd_info *mtd) | 125 | static u16 au_read_word(struct mtd_info *mtd) |
@@ -158,7 +135,7 @@ static u16 au_read_word(struct mtd_info *mtd) | |||
158 | * @mtd: MTD device structure | 135 | * @mtd: MTD device structure |
159 | * @word: data word to write | 136 | * @word: data word to write |
160 | * | 137 | * |
161 | * write function for 16bit buswith without | 138 | * write function for 16bit buswith without |
162 | * endianess conversion | 139 | * endianess conversion |
163 | */ | 140 | */ |
164 | static void au_write_word(struct mtd_info *mtd, u16 word) | 141 | static void au_write_word(struct mtd_info *mtd, u16 word) |
@@ -188,7 +165,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
188 | } | 165 | } |
189 | 166 | ||
190 | /** | 167 | /** |
191 | * au_read_buf - read chip data into buffer | 168 | * au_read_buf - read chip data into buffer |
192 | * @mtd: MTD device structure | 169 | * @mtd: MTD device structure |
193 | * @buf: buffer to store date | 170 | * @buf: buffer to store date |
194 | * @len: number of bytes to read | 171 | * @len: number of bytes to read |
@@ -202,12 +179,12 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
202 | 179 | ||
203 | for (i=0; i<len; i++) { | 180 | for (i=0; i<len; i++) { |
204 | buf[i] = readb(this->IO_ADDR_R); | 181 | buf[i] = readb(this->IO_ADDR_R); |
205 | au_sync(); | 182 | au_sync(); |
206 | } | 183 | } |
207 | } | 184 | } |
208 | 185 | ||
209 | /** | 186 | /** |
210 | * au_verify_buf - Verify chip data against buffer | 187 | * au_verify_buf - Verify chip data against buffer |
211 | * @mtd: MTD device structure | 188 | * @mtd: MTD device structure |
212 | * @buf: buffer containing the data to compare | 189 | * @buf: buffer containing the data to compare |
213 | * @len: number of bytes to compare | 190 | * @len: number of bytes to compare |
@@ -242,16 +219,16 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) | |||
242 | struct nand_chip *this = mtd->priv; | 219 | struct nand_chip *this = mtd->priv; |
243 | u16 *p = (u16 *) buf; | 220 | u16 *p = (u16 *) buf; |
244 | len >>= 1; | 221 | len >>= 1; |
245 | 222 | ||
246 | for (i=0; i<len; i++) { | 223 | for (i=0; i<len; i++) { |
247 | writew(p[i], this->IO_ADDR_W); | 224 | writew(p[i], this->IO_ADDR_W); |
248 | au_sync(); | 225 | au_sync(); |
249 | } | 226 | } |
250 | 227 | ||
251 | } | 228 | } |
252 | 229 | ||
253 | /** | 230 | /** |
254 | * au_read_buf16 - read chip data into buffer | 231 | * au_read_buf16 - read chip data into buffer |
255 | * @mtd: MTD device structure | 232 | * @mtd: MTD device structure |
256 | * @buf: buffer to store date | 233 | * @buf: buffer to store date |
257 | * @len: number of bytes to read | 234 | * @len: number of bytes to read |
@@ -272,7 +249,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) | |||
272 | } | 249 | } |
273 | 250 | ||
274 | /** | 251 | /** |
275 | * au_verify_buf16 - Verify chip data against buffer | 252 | * au_verify_buf16 - Verify chip data against buffer |
276 | * @mtd: MTD device structure | 253 | * @mtd: MTD device structure |
277 | * @buf: buffer containing the data to compare | 254 | * @buf: buffer containing the data to compare |
278 | * @len: number of bytes to compare | 255 | * @len: number of bytes to compare |
@@ -305,26 +282,26 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) | |||
305 | case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break; | 282 | case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break; |
306 | 283 | ||
307 | case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break; | 284 | case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break; |
308 | case NAND_CTL_CLRALE: | 285 | case NAND_CTL_CLRALE: |
309 | this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; | 286 | this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; |
310 | /* FIXME: Nobody knows why this is neccecary, | 287 | /* FIXME: Nobody knows why this is neccecary, |
311 | * but it works only that way */ | 288 | * but it works only that way */ |
312 | udelay(1); | 289 | udelay(1); |
313 | break; | 290 | break; |
314 | 291 | ||
315 | case NAND_CTL_SETNCE: | 292 | case NAND_CTL_SETNCE: |
316 | /* assert (force assert) chip enable */ | 293 | /* assert (force assert) chip enable */ |
317 | au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break; | 294 | au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break; |
318 | break; | 295 | break; |
319 | 296 | ||
320 | case NAND_CTL_CLRNCE: | 297 | case NAND_CTL_CLRNCE: |
321 | /* deassert chip enable */ | 298 | /* deassert chip enable */ |
322 | au_writel(0, MEM_STNDCTL); break; | 299 | au_writel(0, MEM_STNDCTL); break; |
323 | break; | 300 | break; |
324 | } | 301 | } |
325 | 302 | ||
326 | this->IO_ADDR_R = this->IO_ADDR_W; | 303 | this->IO_ADDR_R = this->IO_ADDR_W; |
327 | 304 | ||
328 | /* Drain the writebuffer */ | 305 | /* Drain the writebuffer */ |
329 | au_sync(); | 306 | au_sync(); |
330 | } | 307 | } |
@@ -339,14 +316,16 @@ int au1550_device_ready(struct mtd_info *mtd) | |||
339 | /* | 316 | /* |
340 | * Main initialization routine | 317 | * Main initialization routine |
341 | */ | 318 | */ |
342 | int __init au1550_init (void) | 319 | int __init au1xxx_nand_init (void) |
343 | { | 320 | { |
344 | struct nand_chip *this; | 321 | struct nand_chip *this; |
345 | u16 boot_swapboot = 0; /* default value */ | 322 | u16 boot_swapboot = 0; /* default value */ |
346 | int retval; | 323 | int retval; |
324 | u32 mem_staddr; | ||
325 | u32 nand_phys; | ||
347 | 326 | ||
348 | /* Allocate memory for MTD device structure and private data */ | 327 | /* Allocate memory for MTD device structure and private data */ |
349 | au1550_mtd = kmalloc (sizeof(struct mtd_info) + | 328 | au1550_mtd = kmalloc (sizeof(struct mtd_info) + |
350 | sizeof (struct nand_chip), GFP_KERNEL); | 329 | sizeof (struct nand_chip), GFP_KERNEL); |
351 | if (!au1550_mtd) { | 330 | if (!au1550_mtd) { |
352 | printk ("Unable to allocate NAND MTD dev structure.\n"); | 331 | printk ("Unable to allocate NAND MTD dev structure.\n"); |
@@ -364,14 +343,17 @@ int __init au1550_init (void) | |||
364 | au1550_mtd->priv = this; | 343 | au1550_mtd->priv = this; |
365 | 344 | ||
366 | 345 | ||
367 | /* MEM_STNDCTL: disable ints, disable nand boot */ | 346 | /* disable interrupts */ |
368 | au_writel(0, MEM_STNDCTL); | 347 | au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL); |
348 | |||
349 | /* disable NAND boot */ | ||
350 | au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL); | ||
369 | 351 | ||
370 | #ifdef CONFIG_MIPS_PB1550 | 352 | #ifdef CONFIG_MIPS_PB1550 |
371 | /* set gpio206 high */ | 353 | /* set gpio206 high */ |
372 | au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR); | 354 | au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR); |
373 | 355 | ||
374 | boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | | 356 | boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | |
375 | ((bcsr->status >> 6) & 0x1); | 357 | ((bcsr->status >> 6) & 0x1); |
376 | switch (boot_swapboot) { | 358 | switch (boot_swapboot) { |
377 | case 0: | 359 | case 0: |
@@ -397,25 +379,66 @@ int __init au1550_init (void) | |||
397 | } | 379 | } |
398 | #endif | 380 | #endif |
399 | 381 | ||
400 | /* Configure RCE1 - should be done by YAMON */ | 382 | /* Configure chip-select; normally done by boot code, e.g. YAMON */ |
401 | au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */ | 383 | #ifdef NAND_STCFG |
402 | au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */ | 384 | if (NAND_CS == 0) { |
403 | au_sync(); | 385 | au_writel(NAND_STCFG, MEM_STCFG0); |
386 | au_writel(NAND_STTIME, MEM_STTIME0); | ||
387 | au_writel(NAND_STADDR, MEM_STADDR0); | ||
388 | } | ||
389 | if (NAND_CS == 1) { | ||
390 | au_writel(NAND_STCFG, MEM_STCFG1); | ||
391 | au_writel(NAND_STTIME, MEM_STTIME1); | ||
392 | au_writel(NAND_STADDR, MEM_STADDR1); | ||
393 | } | ||
394 | if (NAND_CS == 2) { | ||
395 | au_writel(NAND_STCFG, MEM_STCFG2); | ||
396 | au_writel(NAND_STTIME, MEM_STTIME2); | ||
397 | au_writel(NAND_STADDR, MEM_STADDR2); | ||
398 | } | ||
399 | if (NAND_CS == 3) { | ||
400 | au_writel(NAND_STCFG, MEM_STCFG3); | ||
401 | au_writel(NAND_STTIME, MEM_STTIME3); | ||
402 | au_writel(NAND_STADDR, MEM_STADDR3); | ||
403 | } | ||
404 | #endif | ||
404 | 405 | ||
405 | /* setup and enable chip select, MEM_STADDR1 */ | 406 | /* Locate NAND chip-select in order to determine NAND phys address */ |
406 | /* we really need to decode offsets only up till 0x20 */ | 407 | mem_staddr = 0x00000000; |
407 | au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | | 408 | if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0)) |
408 | (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), | 409 | mem_staddr = au_readl(MEM_STADDR0); |
409 | MEM_STADDR1); | 410 | else if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1)) |
410 | au_sync(); | 411 | mem_staddr = au_readl(MEM_STADDR1); |
412 | else if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2)) | ||
413 | mem_staddr = au_readl(MEM_STADDR2); | ||
414 | else if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3)) | ||
415 | mem_staddr = au_readl(MEM_STADDR3); | ||
416 | |||
417 | if (mem_staddr == 0x00000000) { | ||
418 | printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECT\n"); | ||
419 | kfree(au1550_mtd); | ||
420 | return 1; | ||
421 | } | ||
422 | nand_phys = (mem_staddr << 4) & 0xFFFC0000; | ||
423 | |||
424 | p_nand = (void __iomem *)ioremap(nand_phys, 0x1000); | ||
425 | |||
426 | /* make controller and MTD agree */ | ||
427 | if (NAND_CS == 0) | ||
428 | nand_width = au_readl(MEM_STCFG0) & (1<<22); | ||
429 | if (NAND_CS == 1) | ||
430 | nand_width = au_readl(MEM_STCFG1) & (1<<22); | ||
431 | if (NAND_CS == 2) | ||
432 | nand_width = au_readl(MEM_STCFG2) & (1<<22); | ||
433 | if (NAND_CS == 3) | ||
434 | nand_width = au_readl(MEM_STCFG3) & (1<<22); | ||
411 | 435 | ||
412 | p_nand = ioremap(NAND_PHYS_ADDR, 0x1000); | ||
413 | 436 | ||
414 | /* Set address of hardware control function */ | 437 | /* Set address of hardware control function */ |
415 | this->hwcontrol = au1550_hwcontrol; | 438 | this->hwcontrol = au1550_hwcontrol; |
416 | this->dev_ready = au1550_device_ready; | 439 | this->dev_ready = au1550_device_ready; |
417 | /* 30 us command delay time */ | 440 | /* 30 us command delay time */ |
418 | this->chip_delay = 30; | 441 | this->chip_delay = 30; |
419 | this->eccmode = NAND_ECC_SOFT; | 442 | this->eccmode = NAND_ECC_SOFT; |
420 | 443 | ||
421 | this->options = NAND_NO_AUTOINCR; | 444 | this->options = NAND_NO_AUTOINCR; |
@@ -438,19 +461,19 @@ int __init au1550_init (void) | |||
438 | } | 461 | } |
439 | 462 | ||
440 | /* Register the partitions */ | 463 | /* Register the partitions */ |
441 | add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS); | 464 | add_mtd_partitions(au1550_mtd, partition_info, NB_OF(partition_info)); |
442 | 465 | ||
443 | return 0; | 466 | return 0; |
444 | 467 | ||
445 | outio: | 468 | outio: |
446 | iounmap ((void *)p_nand); | 469 | iounmap ((void *)p_nand); |
447 | 470 | ||
448 | outmem: | 471 | outmem: |
449 | kfree (au1550_mtd); | 472 | kfree (au1550_mtd); |
450 | return retval; | 473 | return retval; |
451 | } | 474 | } |
452 | 475 | ||
453 | module_init(au1550_init); | 476 | module_init(au1xxx_nand_init); |
454 | 477 | ||
455 | /* | 478 | /* |
456 | * Clean up routine | 479 | * Clean up routine |
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 4afa8ced05ad..056dfc17a075 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c | |||
@@ -5,8 +5,8 @@ | |||
5 | * | 5 | * |
6 | * Derived from drivers/mtd/spia.c | 6 | * Derived from drivers/mtd/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: autcpu12.c,v 1.22 2004/11/04 12:53:10 gleixner Exp $ | 9 | * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -14,7 +14,7 @@ | |||
14 | * | 14 | * |
15 | * Overview: | 15 | * Overview: |
16 | * This is a device driver for the NAND flash device found on the | 16 | * This is a device driver for the NAND flash device found on the |
17 | * autronix autcpu12 board, which is a SmartMediaCard. It supports | 17 | * autronix autcpu12 board, which is a SmartMediaCard. It supports |
18 | * 16MiB, 32MiB and 64MiB cards. | 18 | * 16MiB, 32MiB and 64MiB cards. |
19 | * | 19 | * |
20 | * | 20 | * |
@@ -93,7 +93,7 @@ static struct mtd_partition partition_info128k[] = { | |||
93 | #define NUM_PARTITIONS32K 2 | 93 | #define NUM_PARTITIONS32K 2 |
94 | #define NUM_PARTITIONS64K 2 | 94 | #define NUM_PARTITIONS64K 2 |
95 | #define NUM_PARTITIONS128K 2 | 95 | #define NUM_PARTITIONS128K 2 |
96 | /* | 96 | /* |
97 | * hardware specific access to control-lines | 97 | * hardware specific access to control-lines |
98 | */ | 98 | */ |
99 | static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) | 99 | static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) |
@@ -163,7 +163,7 @@ int __init autcpu12_init (void) | |||
163 | this->hwcontrol = autcpu12_hwcontrol; | 163 | this->hwcontrol = autcpu12_hwcontrol; |
164 | this->dev_ready = autcpu12_device_ready; | 164 | this->dev_ready = autcpu12_device_ready; |
165 | /* 20 us command delay time */ | 165 | /* 20 us command delay time */ |
166 | this->chip_delay = 20; | 166 | this->chip_delay = 20; |
167 | this->eccmode = NAND_ECC_SOFT; | 167 | this->eccmode = NAND_ECC_SOFT; |
168 | 168 | ||
169 | /* Enable the following for a flash based bad block table */ | 169 | /* Enable the following for a flash based bad block table */ |
@@ -171,21 +171,21 @@ int __init autcpu12_init (void) | |||
171 | this->options = NAND_USE_FLASH_BBT; | 171 | this->options = NAND_USE_FLASH_BBT; |
172 | */ | 172 | */ |
173 | this->options = NAND_USE_FLASH_BBT; | 173 | this->options = NAND_USE_FLASH_BBT; |
174 | 174 | ||
175 | /* Scan to find existance of the device */ | 175 | /* Scan to find existance of the device */ |
176 | if (nand_scan (autcpu12_mtd, 1)) { | 176 | if (nand_scan (autcpu12_mtd, 1)) { |
177 | err = -ENXIO; | 177 | err = -ENXIO; |
178 | goto out_ior; | 178 | goto out_ior; |
179 | } | 179 | } |
180 | 180 | ||
181 | /* Register the partitions */ | 181 | /* Register the partitions */ |
182 | switch(autcpu12_mtd->size){ | 182 | switch(autcpu12_mtd->size){ |
183 | case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; | 183 | case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; |
184 | case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; | 184 | case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; |
185 | case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; | 185 | case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; |
186 | case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; | 186 | case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; |
187 | default: { | 187 | default: { |
188 | printk ("Unsupported SmartMedia device\n"); | 188 | printk ("Unsupported SmartMedia device\n"); |
189 | err = -ENXIO; | 189 | err = -ENXIO; |
190 | goto out_ior; | 190 | goto out_ior; |
191 | } | 191 | } |
@@ -213,7 +213,7 @@ static void __exit autcpu12_cleanup (void) | |||
213 | 213 | ||
214 | /* unmap physical adress */ | 214 | /* unmap physical adress */ |
215 | iounmap((void *)autcpu12_fio_base); | 215 | iounmap((void *)autcpu12_fio_base); |
216 | 216 | ||
217 | /* Free the MTD device structure */ | 217 | /* Free the MTD device structure */ |
218 | kfree (autcpu12_mtd); | 218 | kfree (autcpu12_mtd); |
219 | } | 219 | } |
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index fdb5d4ad3d52..21d4e8f4b7af 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/mtd/nand/diskonchip.c | 2 | * drivers/mtd/nand/diskonchip.c |
3 | * | 3 | * |
4 | * (C) 2003 Red Hat, Inc. | 4 | * (C) 2003 Red Hat, Inc. |
@@ -8,15 +8,15 @@ | |||
8 | * Author: David Woodhouse <dwmw2@infradead.org> | 8 | * Author: David Woodhouse <dwmw2@infradead.org> |
9 | * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org> | 9 | * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org> |
10 | * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee> | 10 | * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee> |
11 | * | 11 | * |
12 | * Error correction code lifted from the old docecc code | 12 | * Error correction code lifted from the old docecc code |
13 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 13 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
14 | * Copyright (C) 2000 Netgem S.A. | 14 | * Copyright (C) 2000 Netgem S.A. |
15 | * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> | 15 | * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> |
16 | * | 16 | * |
17 | * Interface to generic NAND code for M-Systems DiskOnChip devices | 17 | * Interface to generic NAND code for M-Systems DiskOnChip devices |
18 | * | 18 | * |
19 | * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $ | 19 | * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $ |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
@@ -42,16 +42,16 @@ | |||
42 | static unsigned long __initdata doc_locations[] = { | 42 | static unsigned long __initdata doc_locations[] = { |
43 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) | 43 | #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) |
44 | #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH | 44 | #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH |
45 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, | 45 | 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, |
46 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, | 46 | 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, |
47 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, | 47 | 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, |
48 | 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, | 48 | 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, |
49 | 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, | 49 | 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, |
50 | #else /* CONFIG_MTD_DOCPROBE_HIGH */ | 50 | #else /* CONFIG_MTD_DOCPROBE_HIGH */ |
51 | 0xc8000, 0xca000, 0xcc000, 0xce000, | 51 | 0xc8000, 0xca000, 0xcc000, 0xce000, |
52 | 0xd0000, 0xd2000, 0xd4000, 0xd6000, | 52 | 0xd0000, 0xd2000, 0xd4000, 0xd6000, |
53 | 0xd8000, 0xda000, 0xdc000, 0xde000, | 53 | 0xd8000, 0xda000, 0xdc000, 0xde000, |
54 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, | 54 | 0xe0000, 0xe2000, 0xe4000, 0xe6000, |
55 | 0xe8000, 0xea000, 0xec000, 0xee000, | 55 | 0xe8000, 0xea000, 0xec000, 0xee000, |
56 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ | 56 | #endif /* CONFIG_MTD_DOCPROBE_HIGH */ |
57 | #elif defined(__PPC__) | 57 | #elif defined(__PPC__) |
@@ -138,7 +138,7 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe | |||
138 | /* the Reed Solomon control structure */ | 138 | /* the Reed Solomon control structure */ |
139 | static struct rs_control *rs_decoder; | 139 | static struct rs_control *rs_decoder; |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * The HW decoder in the DoC ASIC's provides us a error syndrome, | 142 | * The HW decoder in the DoC ASIC's provides us a error syndrome, |
143 | * which we must convert to a standard syndrom usable by the generic | 143 | * which we must convert to a standard syndrom usable by the generic |
144 | * Reed-Solomon library code. | 144 | * Reed-Solomon library code. |
@@ -163,8 +163,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) | |||
163 | /* Initialize the syndrom buffer */ | 163 | /* Initialize the syndrom buffer */ |
164 | for (i = 0; i < NROOTS; i++) | 164 | for (i = 0; i < NROOTS; i++) |
165 | s[i] = ds[0]; | 165 | s[i] = ds[0]; |
166 | /* | 166 | /* |
167 | * Evaluate | 167 | * Evaluate |
168 | * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] | 168 | * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] |
169 | * where x = alpha^(FCR + i) | 169 | * where x = alpha^(FCR + i) |
170 | */ | 170 | */ |
@@ -188,7 +188,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) | |||
188 | if (nerr < 0) | 188 | if (nerr < 0) |
189 | return nerr; | 189 | return nerr; |
190 | 190 | ||
191 | /* | 191 | /* |
192 | * Correct the errors. The bitpositions are a bit of magic, | 192 | * Correct the errors. The bitpositions are a bit of magic, |
193 | * but they are given by the design of the de/encoder circuit | 193 | * but they are given by the design of the de/encoder circuit |
194 | * in the DoC ASIC's. | 194 | * in the DoC ASIC's. |
@@ -205,7 +205,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) | |||
205 | can be modified since pos is even */ | 205 | can be modified since pos is even */ |
206 | index = (pos >> 3) ^ 1; | 206 | index = (pos >> 3) ^ 1; |
207 | bitpos = pos & 7; | 207 | bitpos = pos & 7; |
208 | if ((index >= 0 && index < SECTOR_SIZE) || | 208 | if ((index >= 0 && index < SECTOR_SIZE) || |
209 | index == (SECTOR_SIZE + 1)) { | 209 | index == (SECTOR_SIZE + 1)) { |
210 | val = (uint8_t) (errval[i] >> (2 + bitpos)); | 210 | val = (uint8_t) (errval[i] >> (2 + bitpos)); |
211 | parity ^= val; | 211 | parity ^= val; |
@@ -216,7 +216,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) | |||
216 | bitpos = (bitpos + 10) & 7; | 216 | bitpos = (bitpos + 10) & 7; |
217 | if (bitpos == 0) | 217 | if (bitpos == 0) |
218 | bitpos = 8; | 218 | bitpos = 8; |
219 | if ((index >= 0 && index < SECTOR_SIZE) || | 219 | if ((index >= 0 && index < SECTOR_SIZE) || |
220 | index == (SECTOR_SIZE + 1)) { | 220 | index == (SECTOR_SIZE + 1)) { |
221 | val = (uint8_t)(errval[i] << (8 - bitpos)); | 221 | val = (uint8_t)(errval[i] << (8 - bitpos)); |
222 | parity ^= val; | 222 | parity ^= val; |
@@ -233,7 +233,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) | |||
233 | { | 233 | { |
234 | volatile char dummy; | 234 | volatile char dummy; |
235 | int i; | 235 | int i; |
236 | 236 | ||
237 | for (i = 0; i < cycles; i++) { | 237 | for (i = 0; i < cycles; i++) { |
238 | if (DoC_is_Millennium(doc)) | 238 | if (DoC_is_Millennium(doc)) |
239 | dummy = ReadDOC(doc->virtadr, NOP); | 239 | dummy = ReadDOC(doc->virtadr, NOP); |
@@ -242,7 +242,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) | |||
242 | else | 242 | else |
243 | dummy = ReadDOC(doc->virtadr, DOCStatus); | 243 | dummy = ReadDOC(doc->virtadr, DOCStatus); |
244 | } | 244 | } |
245 | 245 | ||
246 | } | 246 | } |
247 | 247 | ||
248 | #define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) | 248 | #define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) |
@@ -327,7 +327,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd) | |||
327 | return ret; | 327 | return ret; |
328 | } | 328 | } |
329 | 329 | ||
330 | static void doc2000_writebuf(struct mtd_info *mtd, | 330 | static void doc2000_writebuf(struct mtd_info *mtd, |
331 | const u_char *buf, int len) | 331 | const u_char *buf, int len) |
332 | { | 332 | { |
333 | struct nand_chip *this = mtd->priv; | 333 | struct nand_chip *this = mtd->priv; |
@@ -343,7 +343,7 @@ static void doc2000_writebuf(struct mtd_info *mtd, | |||
343 | if (debug) printk("\n"); | 343 | if (debug) printk("\n"); |
344 | } | 344 | } |
345 | 345 | ||
346 | static void doc2000_readbuf(struct mtd_info *mtd, | 346 | static void doc2000_readbuf(struct mtd_info *mtd, |
347 | u_char *buf, int len) | 347 | u_char *buf, int len) |
348 | { | 348 | { |
349 | struct nand_chip *this = mtd->priv; | 349 | struct nand_chip *this = mtd->priv; |
@@ -358,7 +358,7 @@ static void doc2000_readbuf(struct mtd_info *mtd, | |||
358 | } | 358 | } |
359 | } | 359 | } |
360 | 360 | ||
361 | static void doc2000_readbuf_dword(struct mtd_info *mtd, | 361 | static void doc2000_readbuf_dword(struct mtd_info *mtd, |
362 | u_char *buf, int len) | 362 | u_char *buf, int len) |
363 | { | 363 | { |
364 | struct nand_chip *this = mtd->priv; | 364 | struct nand_chip *this = mtd->priv; |
@@ -379,7 +379,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, | |||
379 | } | 379 | } |
380 | } | 380 | } |
381 | 381 | ||
382 | static int doc2000_verifybuf(struct mtd_info *mtd, | 382 | static int doc2000_verifybuf(struct mtd_info *mtd, |
383 | const u_char *buf, int len) | 383 | const u_char *buf, int len) |
384 | { | 384 | { |
385 | struct nand_chip *this = mtd->priv; | 385 | struct nand_chip *this = mtd->priv; |
@@ -406,12 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) | |||
406 | doc200x_hwcontrol(mtd, NAND_CTL_SETALE); | 406 | doc200x_hwcontrol(mtd, NAND_CTL_SETALE); |
407 | this->write_byte(mtd, 0); | 407 | this->write_byte(mtd, 0); |
408 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); | 408 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); |
409 | 409 | ||
410 | /* We cant' use dev_ready here, but at least we wait for the | 410 | /* We cant' use dev_ready here, but at least we wait for the |
411 | * command to complete | 411 | * command to complete |
412 | */ | 412 | */ |
413 | udelay(50); | 413 | udelay(50); |
414 | 414 | ||
415 | ret = this->read_byte(mtd) << 8; | 415 | ret = this->read_byte(mtd) << 8; |
416 | ret |= this->read_byte(mtd); | 416 | ret |= this->read_byte(mtd); |
417 | 417 | ||
@@ -438,7 +438,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) | |||
438 | this->read_buf = &doc2000_readbuf_dword; | 438 | this->read_buf = &doc2000_readbuf_dword; |
439 | } | 439 | } |
440 | } | 440 | } |
441 | 441 | ||
442 | return ret; | 442 | return ret; |
443 | } | 443 | } |
444 | 444 | ||
@@ -469,7 +469,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
469 | struct doc_priv *doc = this->priv; | 469 | struct doc_priv *doc = this->priv; |
470 | 470 | ||
471 | int status; | 471 | int status; |
472 | 472 | ||
473 | DoC_WaitReady(doc); | 473 | DoC_WaitReady(doc); |
474 | this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | 474 | this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); |
475 | DoC_WaitReady(doc); | 475 | DoC_WaitReady(doc); |
@@ -503,7 +503,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd) | |||
503 | return ReadDOC(docptr, LastDataRead); | 503 | return ReadDOC(docptr, LastDataRead); |
504 | } | 504 | } |
505 | 505 | ||
506 | static void doc2001_writebuf(struct mtd_info *mtd, | 506 | static void doc2001_writebuf(struct mtd_info *mtd, |
507 | const u_char *buf, int len) | 507 | const u_char *buf, int len) |
508 | { | 508 | { |
509 | struct nand_chip *this = mtd->priv; | 509 | struct nand_chip *this = mtd->priv; |
@@ -517,7 +517,7 @@ static void doc2001_writebuf(struct mtd_info *mtd, | |||
517 | WriteDOC(0x00, docptr, WritePipeTerm); | 517 | WriteDOC(0x00, docptr, WritePipeTerm); |
518 | } | 518 | } |
519 | 519 | ||
520 | static void doc2001_readbuf(struct mtd_info *mtd, | 520 | static void doc2001_readbuf(struct mtd_info *mtd, |
521 | u_char *buf, int len) | 521 | u_char *buf, int len) |
522 | { | 522 | { |
523 | struct nand_chip *this = mtd->priv; | 523 | struct nand_chip *this = mtd->priv; |
@@ -535,7 +535,7 @@ static void doc2001_readbuf(struct mtd_info *mtd, | |||
535 | buf[i] = ReadDOC(docptr, LastDataRead); | 535 | buf[i] = ReadDOC(docptr, LastDataRead); |
536 | } | 536 | } |
537 | 537 | ||
538 | static int doc2001_verifybuf(struct mtd_info *mtd, | 538 | static int doc2001_verifybuf(struct mtd_info *mtd, |
539 | const u_char *buf, int len) | 539 | const u_char *buf, int len) |
540 | { | 540 | { |
541 | struct nand_chip *this = mtd->priv; | 541 | struct nand_chip *this = mtd->priv; |
@@ -570,7 +570,7 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd) | |||
570 | return ret; | 570 | return ret; |
571 | } | 571 | } |
572 | 572 | ||
573 | static void doc2001plus_writebuf(struct mtd_info *mtd, | 573 | static void doc2001plus_writebuf(struct mtd_info *mtd, |
574 | const u_char *buf, int len) | 574 | const u_char *buf, int len) |
575 | { | 575 | { |
576 | struct nand_chip *this = mtd->priv; | 576 | struct nand_chip *this = mtd->priv; |
@@ -587,7 +587,7 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, | |||
587 | if (debug) printk("\n"); | 587 | if (debug) printk("\n"); |
588 | } | 588 | } |
589 | 589 | ||
590 | static void doc2001plus_readbuf(struct mtd_info *mtd, | 590 | static void doc2001plus_readbuf(struct mtd_info *mtd, |
591 | u_char *buf, int len) | 591 | u_char *buf, int len) |
592 | { | 592 | { |
593 | struct nand_chip *this = mtd->priv; | 593 | struct nand_chip *this = mtd->priv; |
@@ -617,7 +617,7 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, | |||
617 | if (debug) printk("\n"); | 617 | if (debug) printk("\n"); |
618 | } | 618 | } |
619 | 619 | ||
620 | static int doc2001plus_verifybuf(struct mtd_info *mtd, | 620 | static int doc2001plus_verifybuf(struct mtd_info *mtd, |
621 | const u_char *buf, int len) | 621 | const u_char *buf, int len) |
622 | { | 622 | { |
623 | struct nand_chip *this = mtd->priv; | 623 | struct nand_chip *this = mtd->priv; |
@@ -797,7 +797,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col | |||
797 | WriteDOC(0, docptr, Mplus_FlashControl); | 797 | WriteDOC(0, docptr, Mplus_FlashControl); |
798 | } | 798 | } |
799 | 799 | ||
800 | /* | 800 | /* |
801 | * program and erase have their own busy handlers | 801 | * program and erase have their own busy handlers |
802 | * status and sequential in needs no delay | 802 | * status and sequential in needs no delay |
803 | */ | 803 | */ |
@@ -822,7 +822,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col | |||
822 | 822 | ||
823 | /* This applies to read commands */ | 823 | /* This applies to read commands */ |
824 | default: | 824 | default: |
825 | /* | 825 | /* |
826 | * If we don't have access to the busy pin, we apply the given | 826 | * If we don't have access to the busy pin, we apply the given |
827 | * command delay | 827 | * command delay |
828 | */ | 828 | */ |
@@ -945,7 +945,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | |||
945 | for (i = 0; i < 6; i++) { | 945 | for (i = 0; i < 6; i++) { |
946 | if (DoC_is_MillenniumPlus(doc)) | 946 | if (DoC_is_MillenniumPlus(doc)) |
947 | ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); | 947 | ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); |
948 | else | 948 | else |
949 | ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); | 949 | ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); |
950 | if (ecc_code[i] != empty_write_ecc[i]) | 950 | if (ecc_code[i] != empty_write_ecc[i]) |
951 | emptymatch = 0; | 951 | emptymatch = 0; |
@@ -982,7 +982,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
982 | void __iomem *docptr = doc->virtadr; | 982 | void __iomem *docptr = doc->virtadr; |
983 | volatile u_char dummy; | 983 | volatile u_char dummy; |
984 | int emptymatch = 1; | 984 | int emptymatch = 1; |
985 | 985 | ||
986 | /* flush the pipeline */ | 986 | /* flush the pipeline */ |
987 | if (DoC_is_2000(doc)) { | 987 | if (DoC_is_2000(doc)) { |
988 | dummy = ReadDOC(docptr, 2k_ECCStatus); | 988 | dummy = ReadDOC(docptr, 2k_ECCStatus); |
@@ -997,7 +997,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
997 | dummy = ReadDOC(docptr, ECCConf); | 997 | dummy = ReadDOC(docptr, ECCConf); |
998 | dummy = ReadDOC(docptr, ECCConf); | 998 | dummy = ReadDOC(docptr, ECCConf); |
999 | } | 999 | } |
1000 | 1000 | ||
1001 | /* Error occured ? */ | 1001 | /* Error occured ? */ |
1002 | if (dummy & 0x80) { | 1002 | if (dummy & 0x80) { |
1003 | for (i = 0; i < 6; i++) { | 1003 | for (i = 0; i < 6; i++) { |
@@ -1035,7 +1035,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
1035 | if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); | 1035 | if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); |
1036 | if (ret > 0) | 1036 | if (ret > 0) |
1037 | printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); | 1037 | printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); |
1038 | } | 1038 | } |
1039 | if (DoC_is_MillenniumPlus(doc)) | 1039 | if (DoC_is_MillenniumPlus(doc)) |
1040 | WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); | 1040 | WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); |
1041 | else | 1041 | else |
@@ -1046,7 +1046,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ | |||
1046 | } | 1046 | } |
1047 | return ret; | 1047 | return ret; |
1048 | } | 1048 | } |
1049 | 1049 | ||
1050 | //u_char mydatabuf[528]; | 1050 | //u_char mydatabuf[528]; |
1051 | 1051 | ||
1052 | /* The strange out-of-order .oobfree list below is a (possibly unneeded) | 1052 | /* The strange out-of-order .oobfree list below is a (possibly unneeded) |
@@ -1065,7 +1065,7 @@ static struct nand_oobinfo doc200x_oobinfo = { | |||
1065 | .eccpos = {0, 1, 2, 3, 4, 5}, | 1065 | .eccpos = {0, 1, 2, 3, 4, 5}, |
1066 | .oobfree = { {8, 8}, {6, 2} } | 1066 | .oobfree = { {8, 8}, {6, 2} } |
1067 | }; | 1067 | }; |
1068 | 1068 | ||
1069 | /* Find the (I)NFTL Media Header, and optionally also the mirror media header. | 1069 | /* Find the (I)NFTL Media Header, and optionally also the mirror media header. |
1070 | On sucessful return, buf will contain a copy of the media header for | 1070 | On sucessful return, buf will contain a copy of the media header for |
1071 | further processing. id is the string to scan for, and will presumably be | 1071 | further processing. id is the string to scan for, and will presumably be |
@@ -1251,7 +1251,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, | |||
1251 | mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); | 1251 | mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); |
1252 | mh->FormatFlags = le32_to_cpu(mh->FormatFlags); | 1252 | mh->FormatFlags = le32_to_cpu(mh->FormatFlags); |
1253 | mh->PercentUsed = le32_to_cpu(mh->PercentUsed); | 1253 | mh->PercentUsed = le32_to_cpu(mh->PercentUsed); |
1254 | 1254 | ||
1255 | printk(KERN_INFO " bootRecordID = %s\n" | 1255 | printk(KERN_INFO " bootRecordID = %s\n" |
1256 | " NoOfBootImageBlocks = %d\n" | 1256 | " NoOfBootImageBlocks = %d\n" |
1257 | " NoOfBinaryPartitions = %d\n" | 1257 | " NoOfBinaryPartitions = %d\n" |
@@ -1468,7 +1468,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd) | |||
1468 | ReadDOC(doc->virtadr, ChipID); | 1468 | ReadDOC(doc->virtadr, ChipID); |
1469 | if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) { | 1469 | if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) { |
1470 | /* It's not a Millennium; it's one of the newer | 1470 | /* It's not a Millennium; it's one of the newer |
1471 | DiskOnChip 2000 units with a similar ASIC. | 1471 | DiskOnChip 2000 units with a similar ASIC. |
1472 | Treat it like a Millennium, except that it | 1472 | Treat it like a Millennium, except that it |
1473 | can have multiple chips. */ | 1473 | can have multiple chips. */ |
1474 | doc2000_count_chips(mtd); | 1474 | doc2000_count_chips(mtd); |
@@ -1530,20 +1530,20 @@ static inline int __init doc_probe(unsigned long physadr) | |||
1530 | * to the DOCControl register. So we store the current contents | 1530 | * to the DOCControl register. So we store the current contents |
1531 | * of the DOCControl register's location, in case we later decide | 1531 | * of the DOCControl register's location, in case we later decide |
1532 | * that it's not a DiskOnChip, and want to put it back how we | 1532 | * that it's not a DiskOnChip, and want to put it back how we |
1533 | * found it. | 1533 | * found it. |
1534 | */ | 1534 | */ |
1535 | save_control = ReadDOC(virtadr, DOCControl); | 1535 | save_control = ReadDOC(virtadr, DOCControl); |
1536 | 1536 | ||
1537 | /* Reset the DiskOnChip ASIC */ | 1537 | /* Reset the DiskOnChip ASIC */ |
1538 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, | 1538 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, |
1539 | virtadr, DOCControl); | 1539 | virtadr, DOCControl); |
1540 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, | 1540 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, |
1541 | virtadr, DOCControl); | 1541 | virtadr, DOCControl); |
1542 | 1542 | ||
1543 | /* Enable the DiskOnChip ASIC */ | 1543 | /* Enable the DiskOnChip ASIC */ |
1544 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, | 1544 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, |
1545 | virtadr, DOCControl); | 1545 | virtadr, DOCControl); |
1546 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, | 1546 | WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, |
1547 | virtadr, DOCControl); | 1547 | virtadr, DOCControl); |
1548 | 1548 | ||
1549 | ChipID = ReadDOC(virtadr, ChipID); | 1549 | ChipID = ReadDOC(virtadr, ChipID); |
@@ -1738,7 +1738,7 @@ static int __init init_nanddoc(void) | |||
1738 | int i, ret = 0; | 1738 | int i, ret = 0; |
1739 | 1739 | ||
1740 | /* We could create the decoder on demand, if memory is a concern. | 1740 | /* We could create the decoder on demand, if memory is a concern. |
1741 | * This way we have it handy, if an error happens | 1741 | * This way we have it handy, if an error happens |
1742 | * | 1742 | * |
1743 | * Symbolsize is 10 (bits) | 1743 | * Symbolsize is 10 (bits) |
1744 | * Primitve polynomial is x^10+x^3+1 | 1744 | * Primitve polynomial is x^10+x^3+1 |
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 5549681ccdce..9b1fd2f387fa 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Derived from drivers/mtd/nand/autcpu12.c | 6 | * Derived from drivers/mtd/nand/autcpu12.c |
7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 7 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
8 | * | 8 | * |
9 | * $Id: edb7312.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $ | 9 | * $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -71,27 +71,27 @@ static struct mtd_partition partition_info[] = { | |||
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | 73 | ||
74 | /* | 74 | /* |
75 | * hardware specific access to control-lines | 75 | * hardware specific access to control-lines |
76 | */ | 76 | */ |
77 | static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) | 77 | static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) |
78 | { | 78 | { |
79 | switch(cmd) { | 79 | switch(cmd) { |
80 | 80 | ||
81 | case NAND_CTL_SETCLE: | 81 | case NAND_CTL_SETCLE: |
82 | clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); | 82 | clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); |
83 | break; | 83 | break; |
84 | case NAND_CTL_CLRCLE: | 84 | case NAND_CTL_CLRCLE: |
85 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); | 85 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); |
86 | break; | 86 | break; |
87 | 87 | ||
88 | case NAND_CTL_SETALE: | 88 | case NAND_CTL_SETALE: |
89 | clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr); | 89 | clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr); |
90 | break; | 90 | break; |
91 | case NAND_CTL_CLRALE: | 91 | case NAND_CTL_CLRALE: |
92 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr); | 92 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr); |
93 | break; | 93 | break; |
94 | 94 | ||
95 | case NAND_CTL_SETNCE: | 95 | case NAND_CTL_SETNCE: |
96 | clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr); | 96 | clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr); |
97 | break; | 97 | break; |
@@ -122,16 +122,16 @@ static int __init ep7312_init (void) | |||
122 | int mtd_parts_nb = 0; | 122 | int mtd_parts_nb = 0; |
123 | struct mtd_partition *mtd_parts = 0; | 123 | struct mtd_partition *mtd_parts = 0; |
124 | void __iomem * ep7312_fio_base; | 124 | void __iomem * ep7312_fio_base; |
125 | 125 | ||
126 | /* Allocate memory for MTD device structure and private data */ | 126 | /* Allocate memory for MTD device structure and private data */ |
127 | ep7312_mtd = kmalloc(sizeof(struct mtd_info) + | 127 | ep7312_mtd = kmalloc(sizeof(struct mtd_info) + |
128 | sizeof(struct nand_chip), | 128 | sizeof(struct nand_chip), |
129 | GFP_KERNEL); | 129 | GFP_KERNEL); |
130 | if (!ep7312_mtd) { | 130 | if (!ep7312_mtd) { |
131 | printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); | 131 | printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); |
132 | return -ENOMEM; | 132 | return -ENOMEM; |
133 | } | 133 | } |
134 | 134 | ||
135 | /* map physical adress */ | 135 | /* map physical adress */ |
136 | ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); | 136 | ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); |
137 | if(!ep7312_fio_base) { | 137 | if(!ep7312_fio_base) { |
@@ -139,23 +139,23 @@ static int __init ep7312_init (void) | |||
139 | kfree(ep7312_mtd); | 139 | kfree(ep7312_mtd); |
140 | return -EIO; | 140 | return -EIO; |
141 | } | 141 | } |
142 | 142 | ||
143 | /* Get pointer to private data */ | 143 | /* Get pointer to private data */ |
144 | this = (struct nand_chip *) (&ep7312_mtd[1]); | 144 | this = (struct nand_chip *) (&ep7312_mtd[1]); |
145 | 145 | ||
146 | /* Initialize structures */ | 146 | /* Initialize structures */ |
147 | memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info)); | 147 | memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info)); |
148 | memset((char *) this, 0, sizeof(struct nand_chip)); | 148 | memset((char *) this, 0, sizeof(struct nand_chip)); |
149 | 149 | ||
150 | /* Link the private data with the MTD structure */ | 150 | /* Link the private data with the MTD structure */ |
151 | ep7312_mtd->priv = this; | 151 | ep7312_mtd->priv = this; |
152 | 152 | ||
153 | /* | 153 | /* |
154 | * Set GPIO Port B control register so that the pins are configured | 154 | * Set GPIO Port B control register so that the pins are configured |
155 | * to be outputs for controlling the NAND flash. | 155 | * to be outputs for controlling the NAND flash. |
156 | */ | 156 | */ |
157 | clps_writeb(0xf0, ep7312_pxddr); | 157 | clps_writeb(0xf0, ep7312_pxddr); |
158 | 158 | ||
159 | /* insert callbacks */ | 159 | /* insert callbacks */ |
160 | this->IO_ADDR_R = ep7312_fio_base; | 160 | this->IO_ADDR_R = ep7312_fio_base; |
161 | this->IO_ADDR_W = ep7312_fio_base; | 161 | this->IO_ADDR_W = ep7312_fio_base; |
@@ -163,14 +163,14 @@ static int __init ep7312_init (void) | |||
163 | this->dev_ready = ep7312_device_ready; | 163 | this->dev_ready = ep7312_device_ready; |
164 | /* 15 us command delay time */ | 164 | /* 15 us command delay time */ |
165 | this->chip_delay = 15; | 165 | this->chip_delay = 15; |
166 | 166 | ||
167 | /* Scan to find existence of the device */ | 167 | /* Scan to find existence of the device */ |
168 | if (nand_scan (ep7312_mtd, 1)) { | 168 | if (nand_scan (ep7312_mtd, 1)) { |
169 | iounmap((void *)ep7312_fio_base); | 169 | iounmap((void *)ep7312_fio_base); |
170 | kfree (ep7312_mtd); | 170 | kfree (ep7312_mtd); |
171 | return -ENXIO; | 171 | return -ENXIO; |
172 | } | 172 | } |
173 | 173 | ||
174 | #ifdef CONFIG_MTD_PARTITIONS | 174 | #ifdef CONFIG_MTD_PARTITIONS |
175 | ep7312_mtd->name = "edb7312-nand"; | 175 | ep7312_mtd->name = "edb7312-nand"; |
176 | mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, | 176 | mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, |
@@ -185,11 +185,11 @@ static int __init ep7312_init (void) | |||
185 | mtd_parts_nb = NUM_PARTITIONS; | 185 | mtd_parts_nb = NUM_PARTITIONS; |
186 | part_type = "static"; | 186 | part_type = "static"; |
187 | } | 187 | } |
188 | 188 | ||
189 | /* Register the partitions */ | 189 | /* Register the partitions */ |
190 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); | 190 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); |
191 | add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb); | 191 | add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb); |
192 | 192 | ||
193 | /* Return happy */ | 193 | /* Return happy */ |
194 | return 0; | 194 | return 0; |
195 | } | 195 | } |
@@ -201,13 +201,13 @@ module_init(ep7312_init); | |||
201 | static void __exit ep7312_cleanup (void) | 201 | static void __exit ep7312_cleanup (void) |
202 | { | 202 | { |
203 | struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1]; | 203 | struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1]; |
204 | 204 | ||
205 | /* Release resources, unregister device */ | 205 | /* Release resources, unregister device */ |
206 | nand_release (ap7312_mtd); | 206 | nand_release (ap7312_mtd); |
207 | 207 | ||
208 | /* Free internal data buffer */ | 208 | /* Free internal data buffer */ |
209 | kfree (this->data_buf); | 209 | kfree (this->data_buf); |
210 | 210 | ||
211 | /* Free the MTD device structure */ | 211 | /* Free the MTD device structure */ |
212 | kfree (ep7312_mtd); | 212 | kfree (ep7312_mtd); |
213 | } | 213 | } |
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 3825a7a0900c..041e4b3358fb 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) | 7 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) |
8 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | 8 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) |
9 | * | 9 | * |
10 | * $Id: h1910.c,v 1.5 2004/11/04 12:53:10 gleixner Exp $ | 10 | * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $ |
11 | * | 11 | * |
12 | * 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 |
13 | * 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 |
@@ -54,24 +54,24 @@ static struct mtd_partition partition_info[] = { | |||
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | 56 | ||
57 | /* | 57 | /* |
58 | * hardware specific access to control-lines | 58 | * hardware specific access to control-lines |
59 | */ | 59 | */ |
60 | static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) | 60 | static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) |
61 | { | 61 | { |
62 | struct nand_chip* this = (struct nand_chip *) (mtd->priv); | 62 | struct nand_chip* this = (struct nand_chip *) (mtd->priv); |
63 | 63 | ||
64 | switch(cmd) { | 64 | switch(cmd) { |
65 | 65 | ||
66 | case NAND_CTL_SETCLE: | 66 | case NAND_CTL_SETCLE: |
67 | this->IO_ADDR_R |= (1 << 2); | 67 | this->IO_ADDR_R |= (1 << 2); |
68 | this->IO_ADDR_W |= (1 << 2); | 68 | this->IO_ADDR_W |= (1 << 2); |
69 | break; | 69 | break; |
70 | case NAND_CTL_CLRCLE: | 70 | case NAND_CTL_CLRCLE: |
71 | this->IO_ADDR_R &= ~(1 << 2); | 71 | this->IO_ADDR_R &= ~(1 << 2); |
72 | this->IO_ADDR_W &= ~(1 << 2); | 72 | this->IO_ADDR_W &= ~(1 << 2); |
73 | break; | 73 | break; |
74 | 74 | ||
75 | case NAND_CTL_SETALE: | 75 | case NAND_CTL_SETALE: |
76 | this->IO_ADDR_R |= (1 << 3); | 76 | this->IO_ADDR_R |= (1 << 3); |
77 | this->IO_ADDR_W |= (1 << 3); | 77 | this->IO_ADDR_W |= (1 << 3); |
@@ -80,7 +80,7 @@ static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) | |||
80 | this->IO_ADDR_R &= ~(1 << 3); | 80 | this->IO_ADDR_R &= ~(1 << 3); |
81 | this->IO_ADDR_W &= ~(1 << 3); | 81 | this->IO_ADDR_W &= ~(1 << 3); |
82 | break; | 82 | break; |
83 | 83 | ||
84 | case NAND_CTL_SETNCE: | 84 | case NAND_CTL_SETNCE: |
85 | break; | 85 | break; |
86 | case NAND_CTL_CLRNCE: | 86 | case NAND_CTL_CLRNCE: |
@@ -108,18 +108,18 @@ static int __init h1910_init (void) | |||
108 | int mtd_parts_nb = 0; | 108 | int mtd_parts_nb = 0; |
109 | struct mtd_partition *mtd_parts = 0; | 109 | struct mtd_partition *mtd_parts = 0; |
110 | void __iomem *nandaddr; | 110 | void __iomem *nandaddr; |
111 | 111 | ||
112 | if (!machine_is_h1900()) | 112 | if (!machine_is_h1900()) |
113 | return -ENODEV; | 113 | return -ENODEV; |
114 | 114 | ||
115 | nandaddr = __ioremap(0x08000000, 0x1000, 0, 1); | 115 | nandaddr = __ioremap(0x08000000, 0x1000, 0, 1); |
116 | if (!nandaddr) { | 116 | if (!nandaddr) { |
117 | printk("Failed to ioremap nand flash.\n"); | 117 | printk("Failed to ioremap nand flash.\n"); |
118 | return -ENOMEM; | 118 | return -ENOMEM; |
119 | } | 119 | } |
120 | 120 | ||
121 | /* Allocate memory for MTD device structure and private data */ | 121 | /* Allocate memory for MTD device structure and private data */ |
122 | h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + | 122 | h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + |
123 | sizeof(struct nand_chip), | 123 | sizeof(struct nand_chip), |
124 | GFP_KERNEL); | 124 | GFP_KERNEL); |
125 | if (!h1910_nand_mtd) { | 125 | if (!h1910_nand_mtd) { |
@@ -127,22 +127,22 @@ static int __init h1910_init (void) | |||
127 | iounmap ((void *) nandaddr); | 127 | iounmap ((void *) nandaddr); |
128 | return -ENOMEM; | 128 | return -ENOMEM; |
129 | } | 129 | } |
130 | 130 | ||
131 | /* Get pointer to private data */ | 131 | /* Get pointer to private data */ |
132 | this = (struct nand_chip *) (&h1910_nand_mtd[1]); | 132 | this = (struct nand_chip *) (&h1910_nand_mtd[1]); |
133 | 133 | ||
134 | /* Initialize structures */ | 134 | /* Initialize structures */ |
135 | memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info)); | 135 | memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info)); |
136 | memset((char *) this, 0, sizeof(struct nand_chip)); | 136 | memset((char *) this, 0, sizeof(struct nand_chip)); |
137 | 137 | ||
138 | /* Link the private data with the MTD structure */ | 138 | /* Link the private data with the MTD structure */ |
139 | h1910_nand_mtd->priv = this; | 139 | h1910_nand_mtd->priv = this; |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * Enable VPEN | 142 | * Enable VPEN |
143 | */ | 143 | */ |
144 | GPSR(37) = GPIO_bit(37); | 144 | GPSR(37) = GPIO_bit(37); |
145 | 145 | ||
146 | /* insert callbacks */ | 146 | /* insert callbacks */ |
147 | this->IO_ADDR_R = nandaddr; | 147 | this->IO_ADDR_R = nandaddr; |
148 | this->IO_ADDR_W = nandaddr; | 148 | this->IO_ADDR_W = nandaddr; |
@@ -152,7 +152,7 @@ static int __init h1910_init (void) | |||
152 | this->chip_delay = 50; | 152 | this->chip_delay = 50; |
153 | this->eccmode = NAND_ECC_SOFT; | 153 | this->eccmode = NAND_ECC_SOFT; |
154 | this->options = NAND_NO_AUTOINCR; | 154 | this->options = NAND_NO_AUTOINCR; |
155 | 155 | ||
156 | /* Scan to find existence of the device */ | 156 | /* Scan to find existence of the device */ |
157 | if (nand_scan (h1910_nand_mtd, 1)) { | 157 | if (nand_scan (h1910_nand_mtd, 1)) { |
158 | printk(KERN_NOTICE "No NAND device - returning -ENXIO\n"); | 158 | printk(KERN_NOTICE "No NAND device - returning -ENXIO\n"); |
@@ -160,9 +160,9 @@ static int __init h1910_init (void) | |||
160 | iounmap ((void *) nandaddr); | 160 | iounmap ((void *) nandaddr); |
161 | return -ENXIO; | 161 | return -ENXIO; |
162 | } | 162 | } |
163 | 163 | ||
164 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 164 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
165 | mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, | 165 | mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, |
166 | "h1910-nand"); | 166 | "h1910-nand"); |
167 | if (mtd_parts_nb > 0) | 167 | if (mtd_parts_nb > 0) |
168 | part_type = "command line"; | 168 | part_type = "command line"; |
@@ -175,11 +175,11 @@ static int __init h1910_init (void) | |||
175 | mtd_parts_nb = NUM_PARTITIONS; | 175 | mtd_parts_nb = NUM_PARTITIONS; |
176 | part_type = "static"; | 176 | part_type = "static"; |
177 | } | 177 | } |
178 | 178 | ||
179 | /* Register the partitions */ | 179 | /* Register the partitions */ |
180 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); | 180 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); |
181 | add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb); | 181 | add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb); |
182 | 182 | ||
183 | /* Return happy */ | 183 | /* Return happy */ |
184 | return 0; | 184 | return 0; |
185 | } | 185 | } |
@@ -191,7 +191,7 @@ module_init(h1910_init); | |||
191 | static void __exit h1910_cleanup (void) | 191 | static void __exit h1910_cleanup (void) |
192 | { | 192 | { |
193 | struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1]; | 193 | struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1]; |
194 | 194 | ||
195 | /* Release resources, unregister device */ | 195 | /* Release resources, unregister device */ |
196 | nand_release (h1910_nand_mtd); | 196 | nand_release (h1910_nand_mtd); |
197 | 197 | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8e78d7b96a56..5d222460b42a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -5,14 +5,14 @@ | |||
5 | * This is the generic MTD driver for NAND flash devices. It should be | 5 | * This is the generic MTD driver for NAND flash devices. It should be |
6 | * capable of working with almost all NAND chips currently available. | 6 | * capable of working with almost all NAND chips currently available. |
7 | * Basic support for AG-AND chips is provided. | 7 | * Basic support for AG-AND chips is provided. |
8 | * | 8 | * |
9 | * Additional technical information is available on | 9 | * Additional technical information is available on |
10 | * http://www.linux-mtd.infradead.org/tech/nand.html | 10 | * http://www.linux-mtd.infradead.org/tech/nand.html |
11 | * | 11 | * |
12 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 12 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
13 | * 2002 Thomas Gleixner (tglx@linutronix.de) | 13 | * 2002 Thomas Gleixner (tglx@linutronix.de) |
14 | * | 14 | * |
15 | * 02-08-2004 tglx: support for strange chips, which cannot auto increment | 15 | * 02-08-2004 tglx: support for strange chips, which cannot auto increment |
16 | * pages on read / read_oob | 16 | * pages on read / read_oob |
17 | * | 17 | * |
18 | * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes | 18 | * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes |
@@ -21,7 +21,7 @@ | |||
21 | * Make reads over block boundaries work too | 21 | * Make reads over block boundaries work too |
22 | * | 22 | * |
23 | * 04-14-2004 tglx: first working version for 2k page size chips | 23 | * 04-14-2004 tglx: first working version for 2k page size chips |
24 | * | 24 | * |
25 | * 05-19-2004 tglx: Basic support for Renesas AG-AND chips | 25 | * 05-19-2004 tglx: Basic support for Renesas AG-AND chips |
26 | * | 26 | * |
27 | * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared | 27 | * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared |
@@ -30,25 +30,27 @@ | |||
30 | * | 30 | * |
31 | * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. | 31 | * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. |
32 | * Basically, any block not rewritten may lose data when surrounding blocks | 32 | * Basically, any block not rewritten may lose data when surrounding blocks |
33 | * are rewritten many times. JFFS2 ensures this doesn't happen for blocks | 33 | * are rewritten many times. JFFS2 ensures this doesn't happen for blocks |
34 | * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they | 34 | * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they |
35 | * do not lose data, force them to be rewritten when some of the surrounding | 35 | * do not lose data, force them to be rewritten when some of the surrounding |
36 | * blocks are erased. Rather than tracking a specific nearby block (which | 36 | * blocks are erased. Rather than tracking a specific nearby block (which |
37 | * could itself go bad), use a page address 'mask' to select several blocks | 37 | * could itself go bad), use a page address 'mask' to select several blocks |
38 | * in the same area, and rewrite the BBT when any of them are erased. | 38 | * in the same area, and rewrite the BBT when any of them are erased. |
39 | * | 39 | * |
40 | * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas | 40 | * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas |
41 | * AG-AND chips. If there was a sudden loss of power during an erase operation, | 41 | * AG-AND chips. If there was a sudden loss of power during an erase operation, |
42 | * a "device recovery" operation must be performed when power is restored | 42 | * a "device recovery" operation must be performed when power is restored |
43 | * to ensure correct operation. | 43 | * to ensure correct operation. |
44 | * | 44 | * |
45 | * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to | 45 | * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to |
46 | * perform extra error status checks on erase and write failures. This required | 46 | * perform extra error status checks on erase and write failures. This required |
47 | * adding a wrapper function for nand_read_ecc. | 47 | * adding a wrapper function for nand_read_ecc. |
48 | * | 48 | * |
49 | * 08-20-2005 vwool: suspend/resume added | ||
50 | * | ||
49 | * Credits: | 51 | * Credits: |
50 | * David Woodhouse for adding multichip support | 52 | * David Woodhouse for adding multichip support |
51 | * | 53 | * |
52 | * Aleph One Ltd. and Toby Churchill Ltd. for supporting the | 54 | * Aleph One Ltd. and Toby Churchill Ltd. for supporting the |
53 | * rework for 2K page size chips | 55 | * rework for 2K page size chips |
54 | * | 56 | * |
@@ -59,7 +61,7 @@ | |||
59 | * The AG-AND chips have nice features for speed improvement, | 61 | * The AG-AND chips have nice features for speed improvement, |
60 | * which are not supported yet. Read / program 4 pages in one go. | 62 | * which are not supported yet. Read / program 4 pages in one go. |
61 | * | 63 | * |
62 | * $Id: nand_base.c,v 1.147 2005/07/15 07:18:06 gleixner Exp $ | 64 | * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool Exp $ |
63 | * | 65 | * |
64 | * This program is free software; you can redistribute it and/or modify | 66 | * This program is free software; you can redistribute it and/or modify |
65 | * it under the terms of the GNU General Public License version 2 as | 67 | * it under the terms of the GNU General Public License version 2 as |
@@ -103,8 +105,8 @@ static struct nand_oobinfo nand_oob_64 = { | |||
103 | .useecc = MTD_NANDECC_AUTOPLACE, | 105 | .useecc = MTD_NANDECC_AUTOPLACE, |
104 | .eccbytes = 24, | 106 | .eccbytes = 24, |
105 | .eccpos = { | 107 | .eccpos = { |
106 | 40, 41, 42, 43, 44, 45, 46, 47, | 108 | 40, 41, 42, 43, 44, 45, 46, 47, |
107 | 48, 49, 50, 51, 52, 53, 54, 55, | 109 | 48, 49, 50, 51, 52, 53, 54, 55, |
108 | 56, 57, 58, 59, 60, 61, 62, 63}, | 110 | 56, 57, 58, 59, 60, 61, 62, 63}, |
109 | .oobfree = { {2, 38} } | 111 | .oobfree = { {2, 38} } |
110 | }; | 112 | }; |
@@ -147,19 +149,19 @@ static void nand_sync (struct mtd_info *mtd); | |||
147 | static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, | 149 | static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, |
148 | struct nand_oobinfo *oobsel, int mode); | 150 | struct nand_oobinfo *oobsel, int mode); |
149 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE | 151 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
150 | static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, | 152 | static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, |
151 | u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); | 153 | u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); |
152 | #else | 154 | #else |
153 | #define nand_verify_pages(...) (0) | 155 | #define nand_verify_pages(...) (0) |
154 | #endif | 156 | #endif |
155 | 157 | ||
156 | static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); | 158 | static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); |
157 | 159 | ||
158 | /** | 160 | /** |
159 | * nand_release_device - [GENERIC] release chip | 161 | * nand_release_device - [GENERIC] release chip |
160 | * @mtd: MTD device structure | 162 | * @mtd: MTD device structure |
161 | * | 163 | * |
162 | * Deselect, release chip lock and wake up anyone waiting on the device | 164 | * Deselect, release chip lock and wake up anyone waiting on the device |
163 | */ | 165 | */ |
164 | static void nand_release_device (struct mtd_info *mtd) | 166 | static void nand_release_device (struct mtd_info *mtd) |
165 | { | 167 | { |
@@ -213,7 +215,7 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
213 | * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip | 215 | * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip |
214 | * @mtd: MTD device structure | 216 | * @mtd: MTD device structure |
215 | * | 217 | * |
216 | * Default read function for 16bit buswith with | 218 | * Default read function for 16bit buswith with |
217 | * endianess conversion | 219 | * endianess conversion |
218 | */ | 220 | */ |
219 | static u_char nand_read_byte16(struct mtd_info *mtd) | 221 | static u_char nand_read_byte16(struct mtd_info *mtd) |
@@ -240,7 +242,7 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte) | |||
240 | * nand_read_word - [DEFAULT] read one word from the chip | 242 | * nand_read_word - [DEFAULT] read one word from the chip |
241 | * @mtd: MTD device structure | 243 | * @mtd: MTD device structure |
242 | * | 244 | * |
243 | * Default read function for 16bit buswith without | 245 | * Default read function for 16bit buswith without |
244 | * endianess conversion | 246 | * endianess conversion |
245 | */ | 247 | */ |
246 | static u16 nand_read_word(struct mtd_info *mtd) | 248 | static u16 nand_read_word(struct mtd_info *mtd) |
@@ -254,7 +256,7 @@ static u16 nand_read_word(struct mtd_info *mtd) | |||
254 | * @mtd: MTD device structure | 256 | * @mtd: MTD device structure |
255 | * @word: data word to write | 257 | * @word: data word to write |
256 | * | 258 | * |
257 | * Default write function for 16bit buswith without | 259 | * Default write function for 16bit buswith without |
258 | * endianess conversion | 260 | * endianess conversion |
259 | */ | 261 | */ |
260 | static void nand_write_word(struct mtd_info *mtd, u16 word) | 262 | static void nand_write_word(struct mtd_info *mtd, u16 word) |
@@ -275,7 +277,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) | |||
275 | struct nand_chip *this = mtd->priv; | 277 | struct nand_chip *this = mtd->priv; |
276 | switch(chip) { | 278 | switch(chip) { |
277 | case -1: | 279 | case -1: |
278 | this->hwcontrol(mtd, NAND_CTL_CLRNCE); | 280 | this->hwcontrol(mtd, NAND_CTL_CLRNCE); |
279 | break; | 281 | break; |
280 | case 0: | 282 | case 0: |
281 | this->hwcontrol(mtd, NAND_CTL_SETNCE); | 283 | this->hwcontrol(mtd, NAND_CTL_SETNCE); |
@@ -304,7 +306,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
304 | } | 306 | } |
305 | 307 | ||
306 | /** | 308 | /** |
307 | * nand_read_buf - [DEFAULT] read chip data into buffer | 309 | * nand_read_buf - [DEFAULT] read chip data into buffer |
308 | * @mtd: MTD device structure | 310 | * @mtd: MTD device structure |
309 | * @buf: buffer to store date | 311 | * @buf: buffer to store date |
310 | * @len: number of bytes to read | 312 | * @len: number of bytes to read |
@@ -321,7 +323,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
321 | } | 323 | } |
322 | 324 | ||
323 | /** | 325 | /** |
324 | * nand_verify_buf - [DEFAULT] Verify chip data against buffer | 326 | * nand_verify_buf - [DEFAULT] Verify chip data against buffer |
325 | * @mtd: MTD device structure | 327 | * @mtd: MTD device structure |
326 | * @buf: buffer containing the data to compare | 328 | * @buf: buffer containing the data to compare |
327 | * @len: number of bytes to compare | 329 | * @len: number of bytes to compare |
@@ -354,14 +356,14 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) | |||
354 | struct nand_chip *this = mtd->priv; | 356 | struct nand_chip *this = mtd->priv; |
355 | u16 *p = (u16 *) buf; | 357 | u16 *p = (u16 *) buf; |
356 | len >>= 1; | 358 | len >>= 1; |
357 | 359 | ||
358 | for (i=0; i<len; i++) | 360 | for (i=0; i<len; i++) |
359 | writew(p[i], this->IO_ADDR_W); | 361 | writew(p[i], this->IO_ADDR_W); |
360 | 362 | ||
361 | } | 363 | } |
362 | 364 | ||
363 | /** | 365 | /** |
364 | * nand_read_buf16 - [DEFAULT] read chip data into buffer | 366 | * nand_read_buf16 - [DEFAULT] read chip data into buffer |
365 | * @mtd: MTD device structure | 367 | * @mtd: MTD device structure |
366 | * @buf: buffer to store date | 368 | * @buf: buffer to store date |
367 | * @len: number of bytes to read | 369 | * @len: number of bytes to read |
@@ -380,7 +382,7 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) | |||
380 | } | 382 | } |
381 | 383 | ||
382 | /** | 384 | /** |
383 | * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer | 385 | * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer |
384 | * @mtd: MTD device structure | 386 | * @mtd: MTD device structure |
385 | * @buf: buffer containing the data to compare | 387 | * @buf: buffer containing the data to compare |
386 | * @len: number of bytes to compare | 388 | * @len: number of bytes to compare |
@@ -407,7 +409,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) | |||
407 | * @ofs: offset from device start | 409 | * @ofs: offset from device start |
408 | * @getchip: 0, if the chip is already selected | 410 | * @getchip: 0, if the chip is already selected |
409 | * | 411 | * |
410 | * Check, if the block is bad. | 412 | * Check, if the block is bad. |
411 | */ | 413 | */ |
412 | static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | 414 | static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) |
413 | { | 415 | { |
@@ -424,14 +426,14 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
424 | 426 | ||
425 | /* Select the NAND device */ | 427 | /* Select the NAND device */ |
426 | this->select_chip(mtd, chipnr); | 428 | this->select_chip(mtd, chipnr); |
427 | } else | 429 | } else |
428 | page = (int) ofs; | 430 | page = (int) ofs; |
429 | 431 | ||
430 | if (this->options & NAND_BUSWIDTH_16) { | 432 | if (this->options & NAND_BUSWIDTH_16) { |
431 | this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); | 433 | this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); |
432 | bad = cpu_to_le16(this->read_word(mtd)); | 434 | bad = cpu_to_le16(this->read_word(mtd)); |
433 | if (this->badblockpos & 0x1) | 435 | if (this->badblockpos & 0x1) |
434 | bad >>= 1; | 436 | bad >>= 8; |
435 | if ((bad & 0xFF) != 0xff) | 437 | if ((bad & 0xFF) != 0xff) |
436 | res = 1; | 438 | res = 1; |
437 | } else { | 439 | } else { |
@@ -439,12 +441,12 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
439 | if (this->read_byte(mtd) != 0xff) | 441 | if (this->read_byte(mtd) != 0xff) |
440 | res = 1; | 442 | res = 1; |
441 | } | 443 | } |
442 | 444 | ||
443 | if (getchip) { | 445 | if (getchip) { |
444 | /* Deselect and wake up anyone waiting on the device */ | 446 | /* Deselect and wake up anyone waiting on the device */ |
445 | nand_release_device(mtd); | 447 | nand_release_device(mtd); |
446 | } | 448 | } |
447 | 449 | ||
448 | return res; | 450 | return res; |
449 | } | 451 | } |
450 | 452 | ||
@@ -462,7 +464,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
462 | u_char buf[2] = {0, 0}; | 464 | u_char buf[2] = {0, 0}; |
463 | size_t retlen; | 465 | size_t retlen; |
464 | int block; | 466 | int block; |
465 | 467 | ||
466 | /* Get block number */ | 468 | /* Get block number */ |
467 | block = ((int) ofs) >> this->bbt_erase_shift; | 469 | block = ((int) ofs) >> this->bbt_erase_shift; |
468 | if (this->bbt) | 470 | if (this->bbt) |
@@ -471,25 +473,25 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
471 | /* Do we have a flash based bad block table ? */ | 473 | /* Do we have a flash based bad block table ? */ |
472 | if (this->options & NAND_USE_FLASH_BBT) | 474 | if (this->options & NAND_USE_FLASH_BBT) |
473 | return nand_update_bbt (mtd, ofs); | 475 | return nand_update_bbt (mtd, ofs); |
474 | 476 | ||
475 | /* We write two bytes, so we dont have to mess with 16 bit access */ | 477 | /* We write two bytes, so we dont have to mess with 16 bit access */ |
476 | ofs += mtd->oobsize + (this->badblockpos & ~0x01); | 478 | ofs += mtd->oobsize + (this->badblockpos & ~0x01); |
477 | return nand_write_oob (mtd, ofs , 2, &retlen, buf); | 479 | return nand_write_oob (mtd, ofs , 2, &retlen, buf); |
478 | } | 480 | } |
479 | 481 | ||
480 | /** | 482 | /** |
481 | * nand_check_wp - [GENERIC] check if the chip is write protected | 483 | * nand_check_wp - [GENERIC] check if the chip is write protected |
482 | * @mtd: MTD device structure | 484 | * @mtd: MTD device structure |
483 | * Check, if the device is write protected | 485 | * Check, if the device is write protected |
484 | * | 486 | * |
485 | * The function expects, that the device is already selected | 487 | * The function expects, that the device is already selected |
486 | */ | 488 | */ |
487 | static int nand_check_wp (struct mtd_info *mtd) | 489 | static int nand_check_wp (struct mtd_info *mtd) |
488 | { | 490 | { |
489 | struct nand_chip *this = mtd->priv; | 491 | struct nand_chip *this = mtd->priv; |
490 | /* Check the WP bit */ | 492 | /* Check the WP bit */ |
491 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); | 493 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); |
492 | return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; | 494 | return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; |
493 | } | 495 | } |
494 | 496 | ||
495 | /** | 497 | /** |
@@ -505,15 +507,15 @@ static int nand_check_wp (struct mtd_info *mtd) | |||
505 | static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) | 507 | static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) |
506 | { | 508 | { |
507 | struct nand_chip *this = mtd->priv; | 509 | struct nand_chip *this = mtd->priv; |
508 | 510 | ||
509 | if (!this->bbt) | 511 | if (!this->bbt) |
510 | return this->block_bad(mtd, ofs, getchip); | 512 | return this->block_bad(mtd, ofs, getchip); |
511 | 513 | ||
512 | /* Return info from the table */ | 514 | /* Return info from the table */ |
513 | return nand_isbad_bbt (mtd, ofs, allowbbt); | 515 | return nand_isbad_bbt (mtd, ofs, allowbbt); |
514 | } | 516 | } |
515 | 517 | ||
516 | /* | 518 | /* |
517 | * Wait for the ready pin, after a command | 519 | * Wait for the ready pin, after a command |
518 | * The timeout is catched later. | 520 | * The timeout is catched later. |
519 | */ | 521 | */ |
@@ -527,7 +529,7 @@ static void nand_wait_ready(struct mtd_info *mtd) | |||
527 | if (this->dev_ready(mtd)) | 529 | if (this->dev_ready(mtd)) |
528 | return; | 530 | return; |
529 | touch_softlockup_watchdog(); | 531 | touch_softlockup_watchdog(); |
530 | } while (time_before(jiffies, timeo)); | 532 | } while (time_before(jiffies, timeo)); |
531 | } | 533 | } |
532 | 534 | ||
533 | /** | 535 | /** |
@@ -590,13 +592,13 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in | |||
590 | /* Latch in address */ | 592 | /* Latch in address */ |
591 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | 593 | this->hwcontrol(mtd, NAND_CTL_CLRALE); |
592 | } | 594 | } |
593 | 595 | ||
594 | /* | 596 | /* |
595 | * program and erase have their own busy handlers | 597 | * program and erase have their own busy handlers |
596 | * status and sequential in needs no delay | 598 | * status and sequential in needs no delay |
597 | */ | 599 | */ |
598 | switch (command) { | 600 | switch (command) { |
599 | 601 | ||
600 | case NAND_CMD_PAGEPROG: | 602 | case NAND_CMD_PAGEPROG: |
601 | case NAND_CMD_ERASE1: | 603 | case NAND_CMD_ERASE1: |
602 | case NAND_CMD_ERASE2: | 604 | case NAND_CMD_ERASE2: |
@@ -605,7 +607,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in | |||
605 | return; | 607 | return; |
606 | 608 | ||
607 | case NAND_CMD_RESET: | 609 | case NAND_CMD_RESET: |
608 | if (this->dev_ready) | 610 | if (this->dev_ready) |
609 | break; | 611 | break; |
610 | udelay(this->chip_delay); | 612 | udelay(this->chip_delay); |
611 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 613 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
@@ -614,16 +616,16 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in | |||
614 | while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); | 616 | while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); |
615 | return; | 617 | return; |
616 | 618 | ||
617 | /* This applies to read commands */ | 619 | /* This applies to read commands */ |
618 | default: | 620 | default: |
619 | /* | 621 | /* |
620 | * If we don't have access to the busy pin, we apply the given | 622 | * If we don't have access to the busy pin, we apply the given |
621 | * command delay | 623 | * command delay |
622 | */ | 624 | */ |
623 | if (!this->dev_ready) { | 625 | if (!this->dev_ready) { |
624 | udelay (this->chip_delay); | 626 | udelay (this->chip_delay); |
625 | return; | 627 | return; |
626 | } | 628 | } |
627 | } | 629 | } |
628 | /* Apply this short delay always to ensure that we do wait tWB in | 630 | /* Apply this short delay always to ensure that we do wait tWB in |
629 | * any case on any machine. */ | 631 | * any case on any machine. */ |
@@ -653,8 +655,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
653 | column += mtd->oobblock; | 655 | column += mtd->oobblock; |
654 | command = NAND_CMD_READ0; | 656 | command = NAND_CMD_READ0; |
655 | } | 657 | } |
656 | 658 | ||
657 | 659 | ||
658 | /* Begin command latch cycle */ | 660 | /* Begin command latch cycle */ |
659 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 661 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
660 | /* Write out the command to the device. */ | 662 | /* Write out the command to the device. */ |
@@ -672,7 +674,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
672 | column >>= 1; | 674 | column >>= 1; |
673 | this->write_byte(mtd, column & 0xff); | 675 | this->write_byte(mtd, column & 0xff); |
674 | this->write_byte(mtd, column >> 8); | 676 | this->write_byte(mtd, column >> 8); |
675 | } | 677 | } |
676 | if (page_addr != -1) { | 678 | if (page_addr != -1) { |
677 | this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); | 679 | this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); |
678 | this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); | 680 | this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); |
@@ -683,13 +685,13 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
683 | /* Latch in address */ | 685 | /* Latch in address */ |
684 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | 686 | this->hwcontrol(mtd, NAND_CTL_CLRALE); |
685 | } | 687 | } |
686 | 688 | ||
687 | /* | 689 | /* |
688 | * program and erase have their own busy handlers | 690 | * program and erase have their own busy handlers |
689 | * status, sequential in, and deplete1 need no delay | 691 | * status, sequential in, and deplete1 need no delay |
690 | */ | 692 | */ |
691 | switch (command) { | 693 | switch (command) { |
692 | 694 | ||
693 | case NAND_CMD_CACHEDPROG: | 695 | case NAND_CMD_CACHEDPROG: |
694 | case NAND_CMD_PAGEPROG: | 696 | case NAND_CMD_PAGEPROG: |
695 | case NAND_CMD_ERASE1: | 697 | case NAND_CMD_ERASE1: |
@@ -699,7 +701,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
699 | case NAND_CMD_DEPLETE1: | 701 | case NAND_CMD_DEPLETE1: |
700 | return; | 702 | return; |
701 | 703 | ||
702 | /* | 704 | /* |
703 | * read error status commands require only a short delay | 705 | * read error status commands require only a short delay |
704 | */ | 706 | */ |
705 | case NAND_CMD_STATUS_ERROR: | 707 | case NAND_CMD_STATUS_ERROR: |
@@ -711,7 +713,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
711 | return; | 713 | return; |
712 | 714 | ||
713 | case NAND_CMD_RESET: | 715 | case NAND_CMD_RESET: |
714 | if (this->dev_ready) | 716 | if (this->dev_ready) |
715 | break; | 717 | break; |
716 | udelay(this->chip_delay); | 718 | udelay(this->chip_delay); |
717 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 719 | this->hwcontrol(mtd, NAND_CTL_SETCLE); |
@@ -728,17 +730,17 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
728 | /* End command latch cycle */ | 730 | /* End command latch cycle */ |
729 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 731 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); |
730 | /* Fall through into ready check */ | 732 | /* Fall through into ready check */ |
731 | 733 | ||
732 | /* This applies to read commands */ | 734 | /* This applies to read commands */ |
733 | default: | 735 | default: |
734 | /* | 736 | /* |
735 | * If we don't have access to the busy pin, we apply the given | 737 | * If we don't have access to the busy pin, we apply the given |
736 | * command delay | 738 | * command delay |
737 | */ | 739 | */ |
738 | if (!this->dev_ready) { | 740 | if (!this->dev_ready) { |
739 | udelay (this->chip_delay); | 741 | udelay (this->chip_delay); |
740 | return; | 742 | return; |
741 | } | 743 | } |
742 | } | 744 | } |
743 | 745 | ||
744 | /* Apply this short delay always to ensure that we do wait tWB in | 746 | /* Apply this short delay always to ensure that we do wait tWB in |
@@ -752,11 +754,11 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, | |||
752 | * nand_get_device - [GENERIC] Get chip for selected access | 754 | * nand_get_device - [GENERIC] Get chip for selected access |
753 | * @this: the nand chip descriptor | 755 | * @this: the nand chip descriptor |
754 | * @mtd: MTD device structure | 756 | * @mtd: MTD device structure |
755 | * @new_state: the state which is requested | 757 | * @new_state: the state which is requested |
756 | * | 758 | * |
757 | * Get the device and lock it for exclusive access | 759 | * Get the device and lock it for exclusive access |
758 | */ | 760 | */ |
759 | static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) | 761 | static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) |
760 | { | 762 | { |
761 | struct nand_chip *active; | 763 | struct nand_chip *active; |
762 | spinlock_t *lock; | 764 | spinlock_t *lock; |
@@ -779,7 +781,11 @@ retry: | |||
779 | if (active == this && this->state == FL_READY) { | 781 | if (active == this && this->state == FL_READY) { |
780 | this->state = new_state; | 782 | this->state = new_state; |
781 | spin_unlock(lock); | 783 | spin_unlock(lock); |
782 | return; | 784 | return 0; |
785 | } | ||
786 | if (new_state == FL_PM_SUSPENDED) { | ||
787 | spin_unlock(lock); | ||
788 | return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; | ||
783 | } | 789 | } |
784 | set_current_state(TASK_UNINTERRUPTIBLE); | 790 | set_current_state(TASK_UNINTERRUPTIBLE); |
785 | add_wait_queue(wq, &wait); | 791 | add_wait_queue(wq, &wait); |
@@ -796,7 +802,7 @@ retry: | |||
796 | * @state: state to select the max. timeout value | 802 | * @state: state to select the max. timeout value |
797 | * | 803 | * |
798 | * Wait for command done. This applies to erase and program only | 804 | * Wait for command done. This applies to erase and program only |
799 | * Erase can take up to 400ms and program up to 20ms according to | 805 | * Erase can take up to 400ms and program up to 20ms according to |
800 | * general NAND and SmartMedia specs | 806 | * general NAND and SmartMedia specs |
801 | * | 807 | * |
802 | */ | 808 | */ |
@@ -805,7 +811,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
805 | 811 | ||
806 | unsigned long timeo = jiffies; | 812 | unsigned long timeo = jiffies; |
807 | int status; | 813 | int status; |
808 | 814 | ||
809 | if (state == FL_ERASING) | 815 | if (state == FL_ERASING) |
810 | timeo += (HZ * 400) / 1000; | 816 | timeo += (HZ * 400) / 1000; |
811 | else | 817 | else |
@@ -817,17 +823,17 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
817 | 823 | ||
818 | if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) | 824 | if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) |
819 | this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); | 825 | this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); |
820 | else | 826 | else |
821 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); | 827 | this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); |
822 | 828 | ||
823 | while (time_before(jiffies, timeo)) { | 829 | while (time_before(jiffies, timeo)) { |
824 | /* Check, if we were interrupted */ | 830 | /* Check, if we were interrupted */ |
825 | if (this->state != state) | 831 | if (this->state != state) |
826 | return 0; | 832 | return 0; |
827 | 833 | ||
828 | if (this->dev_ready) { | 834 | if (this->dev_ready) { |
829 | if (this->dev_ready(mtd)) | 835 | if (this->dev_ready(mtd)) |
830 | break; | 836 | break; |
831 | } else { | 837 | } else { |
832 | if (this->read_byte(mtd) & NAND_STATUS_READY) | 838 | if (this->read_byte(mtd) & NAND_STATUS_READY) |
833 | break; | 839 | break; |
@@ -853,7 +859,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | |||
853 | * | 859 | * |
854 | * Cached programming is not supported yet. | 860 | * Cached programming is not supported yet. |
855 | */ | 861 | */ |
856 | static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, | 862 | static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, |
857 | u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) | 863 | u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) |
858 | { | 864 | { |
859 | int i, status; | 865 | int i, status; |
@@ -862,10 +868,10 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
862 | int *oob_config = oobsel->eccpos; | 868 | int *oob_config = oobsel->eccpos; |
863 | int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; | 869 | int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; |
864 | int eccbytes = 0; | 870 | int eccbytes = 0; |
865 | 871 | ||
866 | /* FIXME: Enable cached programming */ | 872 | /* FIXME: Enable cached programming */ |
867 | cached = 0; | 873 | cached = 0; |
868 | 874 | ||
869 | /* Send command to begin auto page programming */ | 875 | /* Send command to begin auto page programming */ |
870 | this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); | 876 | this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); |
871 | 877 | ||
@@ -876,7 +882,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
876 | printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); | 882 | printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); |
877 | this->write_buf(mtd, this->data_poi, mtd->oobblock); | 883 | this->write_buf(mtd, this->data_poi, mtd->oobblock); |
878 | break; | 884 | break; |
879 | 885 | ||
880 | /* Software ecc 3/256, write all */ | 886 | /* Software ecc 3/256, write all */ |
881 | case NAND_ECC_SOFT: | 887 | case NAND_ECC_SOFT: |
882 | for (; eccsteps; eccsteps--) { | 888 | for (; eccsteps; eccsteps--) { |
@@ -905,11 +911,11 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
905 | } | 911 | } |
906 | break; | 912 | break; |
907 | } | 913 | } |
908 | 914 | ||
909 | /* Write out OOB data */ | 915 | /* Write out OOB data */ |
910 | if (this->options & NAND_HWECC_SYNDROME) | 916 | if (this->options & NAND_HWECC_SYNDROME) |
911 | this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); | 917 | this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); |
912 | else | 918 | else |
913 | this->write_buf(mtd, oob_buf, mtd->oobsize); | 919 | this->write_buf(mtd, oob_buf, mtd->oobsize); |
914 | 920 | ||
915 | /* Send command to actually program the data */ | 921 | /* Send command to actually program the data */ |
@@ -934,7 +940,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
934 | /* wait until cache is ready*/ | 940 | /* wait until cache is ready*/ |
935 | // status = this->waitfunc (mtd, this, FL_CACHEDRPG); | 941 | // status = this->waitfunc (mtd, this, FL_CACHEDRPG); |
936 | } | 942 | } |
937 | return 0; | 943 | return 0; |
938 | } | 944 | } |
939 | 945 | ||
940 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE | 946 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
@@ -950,19 +956,19 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa | |||
950 | * @oobmode: 1 = full buffer verify, 0 = ecc only | 956 | * @oobmode: 1 = full buffer verify, 0 = ecc only |
951 | * | 957 | * |
952 | * The NAND device assumes that it is always writing to a cleanly erased page. | 958 | * The NAND device assumes that it is always writing to a cleanly erased page. |
953 | * Hence, it performs its internal write verification only on bits that | 959 | * Hence, it performs its internal write verification only on bits that |
954 | * transitioned from 1 to 0. The device does NOT verify the whole page on a | 960 | * transitioned from 1 to 0. The device does NOT verify the whole page on a |
955 | * byte by byte basis. It is possible that the page was not completely erased | 961 | * byte by byte basis. It is possible that the page was not completely erased |
956 | * or the page is becoming unusable due to wear. The read with ECC would catch | 962 | * or the page is becoming unusable due to wear. The read with ECC would catch |
957 | * the error later when the ECC page check fails, but we would rather catch | 963 | * the error later when the ECC page check fails, but we would rather catch |
958 | * it early in the page write stage. Better to write no data than invalid data. | 964 | * it early in the page write stage. Better to write no data than invalid data. |
959 | */ | 965 | */ |
960 | static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, | 966 | static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, |
961 | u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) | 967 | u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) |
962 | { | 968 | { |
963 | int i, j, datidx = 0, oobofs = 0, res = -EIO; | 969 | int i, j, datidx = 0, oobofs = 0, res = -EIO; |
964 | int eccsteps = this->eccsteps; | 970 | int eccsteps = this->eccsteps; |
965 | int hweccbytes; | 971 | int hweccbytes; |
966 | u_char oobdata[64]; | 972 | u_char oobdata[64]; |
967 | 973 | ||
968 | hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; | 974 | hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; |
@@ -1002,7 +1008,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int | |||
1002 | 1008 | ||
1003 | if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { | 1009 | if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { |
1004 | int ecccnt = oobsel->eccbytes; | 1010 | int ecccnt = oobsel->eccbytes; |
1005 | 1011 | ||
1006 | for (i = 0; i < ecccnt; i++) { | 1012 | for (i = 0; i < ecccnt; i++) { |
1007 | int idx = oobsel->eccpos[i]; | 1013 | int idx = oobsel->eccpos[i]; |
1008 | if (oobdata[idx] != oob_buf[oobofs + idx] ) { | 1014 | if (oobdata[idx] != oob_buf[oobofs + idx] ) { |
@@ -1012,20 +1018,20 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int | |||
1012 | goto out; | 1018 | goto out; |
1013 | } | 1019 | } |
1014 | } | 1020 | } |
1015 | } | 1021 | } |
1016 | } | 1022 | } |
1017 | oobofs += mtd->oobsize - hweccbytes * eccsteps; | 1023 | oobofs += mtd->oobsize - hweccbytes * eccsteps; |
1018 | page++; | 1024 | page++; |
1019 | numpages--; | 1025 | numpages--; |
1020 | 1026 | ||
1021 | /* Apply delay or wait for ready/busy pin | 1027 | /* Apply delay or wait for ready/busy pin |
1022 | * Do this before the AUTOINCR check, so no problems | 1028 | * Do this before the AUTOINCR check, so no problems |
1023 | * arise if a chip which does auto increment | 1029 | * arise if a chip which does auto increment |
1024 | * is marked as NOAUTOINCR by the board driver. | 1030 | * is marked as NOAUTOINCR by the board driver. |
1025 | * Do this also before returning, so the chip is | 1031 | * Do this also before returning, so the chip is |
1026 | * ready for the next command. | 1032 | * ready for the next command. |
1027 | */ | 1033 | */ |
1028 | if (!this->dev_ready) | 1034 | if (!this->dev_ready) |
1029 | udelay (this->chip_delay); | 1035 | udelay (this->chip_delay); |
1030 | else | 1036 | else |
1031 | nand_wait_ready(mtd); | 1037 | nand_wait_ready(mtd); |
@@ -1033,17 +1039,17 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int | |||
1033 | /* All done, return happy */ | 1039 | /* All done, return happy */ |
1034 | if (!numpages) | 1040 | if (!numpages) |
1035 | return 0; | 1041 | return 0; |
1036 | 1042 | ||
1037 | 1043 | ||
1038 | /* Check, if the chip supports auto page increment */ | 1044 | /* Check, if the chip supports auto page increment */ |
1039 | if (!NAND_CANAUTOINCR(this)) | 1045 | if (!NAND_CANAUTOINCR(this)) |
1040 | this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); | 1046 | this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); |
1041 | } | 1047 | } |
1042 | /* | 1048 | /* |
1043 | * Terminate the read command. We come here in case of an error | 1049 | * Terminate the read command. We come here in case of an error |
1044 | * So we must issue a reset command. | 1050 | * So we must issue a reset command. |
1045 | */ | 1051 | */ |
1046 | out: | 1052 | out: |
1047 | this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); | 1053 | this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); |
1048 | return res; | 1054 | return res; |
1049 | } | 1055 | } |
@@ -1105,7 +1111,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1105 | * NAND read with ECC | 1111 | * NAND read with ECC |
1106 | */ | 1112 | */ |
1107 | int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | 1113 | int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, |
1108 | size_t * retlen, u_char * buf, u_char * oob_buf, | 1114 | size_t * retlen, u_char * buf, u_char * oob_buf, |
1109 | struct nand_oobinfo *oobsel, int flags) | 1115 | struct nand_oobinfo *oobsel, int flags) |
1110 | { | 1116 | { |
1111 | 1117 | ||
@@ -1139,7 +1145,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1139 | /* Autoplace of oob data ? Use the default placement scheme */ | 1145 | /* Autoplace of oob data ? Use the default placement scheme */ |
1140 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) | 1146 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) |
1141 | oobsel = this->autooob; | 1147 | oobsel = this->autooob; |
1142 | 1148 | ||
1143 | eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; | 1149 | eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; |
1144 | oob_config = oobsel->eccpos; | 1150 | oob_config = oobsel->eccpos; |
1145 | 1151 | ||
@@ -1157,28 +1163,28 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1157 | end = mtd->oobblock; | 1163 | end = mtd->oobblock; |
1158 | ecc = this->eccsize; | 1164 | ecc = this->eccsize; |
1159 | eccbytes = this->eccbytes; | 1165 | eccbytes = this->eccbytes; |
1160 | 1166 | ||
1161 | if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) | 1167 | if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) |
1162 | compareecc = 0; | 1168 | compareecc = 0; |
1163 | 1169 | ||
1164 | oobreadlen = mtd->oobsize; | 1170 | oobreadlen = mtd->oobsize; |
1165 | if (this->options & NAND_HWECC_SYNDROME) | 1171 | if (this->options & NAND_HWECC_SYNDROME) |
1166 | oobreadlen -= oobsel->eccbytes; | 1172 | oobreadlen -= oobsel->eccbytes; |
1167 | 1173 | ||
1168 | /* Loop until all data read */ | 1174 | /* Loop until all data read */ |
1169 | while (read < len) { | 1175 | while (read < len) { |
1170 | 1176 | ||
1171 | int aligned = (!col && (len - read) >= end); | 1177 | int aligned = (!col && (len - read) >= end); |
1172 | /* | 1178 | /* |
1173 | * If the read is not page aligned, we have to read into data buffer | 1179 | * If the read is not page aligned, we have to read into data buffer |
1174 | * due to ecc, else we read into return buffer direct | 1180 | * due to ecc, else we read into return buffer direct |
1175 | */ | 1181 | */ |
1176 | if (aligned) | 1182 | if (aligned) |
1177 | data_poi = &buf[read]; | 1183 | data_poi = &buf[read]; |
1178 | else | 1184 | else |
1179 | data_poi = this->data_buf; | 1185 | data_poi = this->data_buf; |
1180 | 1186 | ||
1181 | /* Check, if we have this page in the buffer | 1187 | /* Check, if we have this page in the buffer |
1182 | * | 1188 | * |
1183 | * FIXME: Make it work when we must provide oob data too, | 1189 | * FIXME: Make it work when we must provide oob data too, |
1184 | * check the usage of data_buf oob field | 1190 | * check the usage of data_buf oob field |
@@ -1194,7 +1200,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1194 | if (sndcmd) { | 1200 | if (sndcmd) { |
1195 | this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); | 1201 | this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); |
1196 | sndcmd = 0; | 1202 | sndcmd = 0; |
1197 | } | 1203 | } |
1198 | 1204 | ||
1199 | /* get oob area, if we have no oob buffer from fs-driver */ | 1205 | /* get oob area, if we have no oob buffer from fs-driver */ |
1200 | if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || | 1206 | if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || |
@@ -1202,7 +1208,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1202 | oob_data = &this->data_buf[end]; | 1208 | oob_data = &this->data_buf[end]; |
1203 | 1209 | ||
1204 | eccsteps = this->eccsteps; | 1210 | eccsteps = this->eccsteps; |
1205 | 1211 | ||
1206 | switch (eccmode) { | 1212 | switch (eccmode) { |
1207 | case NAND_ECC_NONE: { /* No ECC, Read in a page */ | 1213 | case NAND_ECC_NONE: { /* No ECC, Read in a page */ |
1208 | static unsigned long lastwhinge = 0; | 1214 | static unsigned long lastwhinge = 0; |
@@ -1213,12 +1219,12 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1213 | this->read_buf(mtd, data_poi, end); | 1219 | this->read_buf(mtd, data_poi, end); |
1214 | break; | 1220 | break; |
1215 | } | 1221 | } |
1216 | 1222 | ||
1217 | case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ | 1223 | case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ |
1218 | this->read_buf(mtd, data_poi, end); | 1224 | this->read_buf(mtd, data_poi, end); |
1219 | for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) | 1225 | for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) |
1220 | this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); | 1226 | this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); |
1221 | break; | 1227 | break; |
1222 | 1228 | ||
1223 | default: | 1229 | default: |
1224 | for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { | 1230 | for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { |
@@ -1237,15 +1243,15 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1237 | * does the error correction on the fly */ | 1243 | * does the error correction on the fly */ |
1238 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); | 1244 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); |
1239 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { | 1245 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { |
1240 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " | 1246 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " |
1241 | "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); | 1247 | "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); |
1242 | ecc_failed++; | 1248 | ecc_failed++; |
1243 | } | 1249 | } |
1244 | } else { | 1250 | } else { |
1245 | this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); | 1251 | this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); |
1246 | } | 1252 | } |
1247 | } | 1253 | } |
1248 | break; | 1254 | break; |
1249 | } | 1255 | } |
1250 | 1256 | ||
1251 | /* read oobdata */ | 1257 | /* read oobdata */ |
@@ -1253,8 +1259,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1253 | 1259 | ||
1254 | /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ | 1260 | /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ |
1255 | if (!compareecc) | 1261 | if (!compareecc) |
1256 | goto readoob; | 1262 | goto readoob; |
1257 | 1263 | ||
1258 | /* Pick the ECC bytes out of the oob data */ | 1264 | /* Pick the ECC bytes out of the oob data */ |
1259 | for (j = 0; j < oobsel->eccbytes; j++) | 1265 | for (j = 0; j < oobsel->eccbytes; j++) |
1260 | ecc_code[j] = oob_data[oob_config[j]]; | 1266 | ecc_code[j] = oob_data[oob_config[j]]; |
@@ -1262,24 +1268,24 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1262 | /* correct data, if neccecary */ | 1268 | /* correct data, if neccecary */ |
1263 | for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { | 1269 | for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { |
1264 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); | 1270 | ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); |
1265 | 1271 | ||
1266 | /* Get next chunk of ecc bytes */ | 1272 | /* Get next chunk of ecc bytes */ |
1267 | j += eccbytes; | 1273 | j += eccbytes; |
1268 | 1274 | ||
1269 | /* Check, if we have a fs supplied oob-buffer, | 1275 | /* Check, if we have a fs supplied oob-buffer, |
1270 | * This is the legacy mode. Used by YAFFS1 | 1276 | * This is the legacy mode. Used by YAFFS1 |
1271 | * Should go away some day | 1277 | * Should go away some day |
1272 | */ | 1278 | */ |
1273 | if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { | 1279 | if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { |
1274 | int *p = (int *)(&oob_data[mtd->oobsize]); | 1280 | int *p = (int *)(&oob_data[mtd->oobsize]); |
1275 | p[i] = ecc_status; | 1281 | p[i] = ecc_status; |
1276 | } | 1282 | } |
1277 | 1283 | ||
1278 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { | 1284 | if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { |
1279 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); | 1285 | DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); |
1280 | ecc_failed++; | 1286 | ecc_failed++; |
1281 | } | 1287 | } |
1282 | } | 1288 | } |
1283 | 1289 | ||
1284 | readoob: | 1290 | readoob: |
1285 | /* check, if we have a fs supplied oob-buffer */ | 1291 | /* check, if we have a fs supplied oob-buffer */ |
@@ -1305,25 +1311,25 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1305 | } | 1311 | } |
1306 | readdata: | 1312 | readdata: |
1307 | /* Partial page read, transfer data into fs buffer */ | 1313 | /* Partial page read, transfer data into fs buffer */ |
1308 | if (!aligned) { | 1314 | if (!aligned) { |
1309 | for (j = col; j < end && read < len; j++) | 1315 | for (j = col; j < end && read < len; j++) |
1310 | buf[read++] = data_poi[j]; | 1316 | buf[read++] = data_poi[j]; |
1311 | this->pagebuf = realpage; | 1317 | this->pagebuf = realpage; |
1312 | } else | 1318 | } else |
1313 | read += mtd->oobblock; | 1319 | read += mtd->oobblock; |
1314 | 1320 | ||
1315 | /* Apply delay or wait for ready/busy pin | 1321 | /* Apply delay or wait for ready/busy pin |
1316 | * Do this before the AUTOINCR check, so no problems | 1322 | * Do this before the AUTOINCR check, so no problems |
1317 | * arise if a chip which does auto increment | 1323 | * arise if a chip which does auto increment |
1318 | * is marked as NOAUTOINCR by the board driver. | 1324 | * is marked as NOAUTOINCR by the board driver. |
1319 | */ | 1325 | */ |
1320 | if (!this->dev_ready) | 1326 | if (!this->dev_ready) |
1321 | udelay (this->chip_delay); | 1327 | udelay (this->chip_delay); |
1322 | else | 1328 | else |
1323 | nand_wait_ready(mtd); | 1329 | nand_wait_ready(mtd); |
1324 | 1330 | ||
1325 | if (read == len) | 1331 | if (read == len) |
1326 | break; | 1332 | break; |
1327 | 1333 | ||
1328 | /* For subsequent reads align to page boundary. */ | 1334 | /* For subsequent reads align to page boundary. */ |
1329 | col = 0; | 1335 | col = 0; |
@@ -1337,11 +1343,11 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | |||
1337 | this->select_chip(mtd, -1); | 1343 | this->select_chip(mtd, -1); |
1338 | this->select_chip(mtd, chipnr); | 1344 | this->select_chip(mtd, chipnr); |
1339 | } | 1345 | } |
1340 | /* Check, if the chip supports auto page increment | 1346 | /* Check, if the chip supports auto page increment |
1341 | * or if we have hit a block boundary. | 1347 | * or if we have hit a block boundary. |
1342 | */ | 1348 | */ |
1343 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) | 1349 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) |
1344 | sndcmd = 1; | 1350 | sndcmd = 1; |
1345 | } | 1351 | } |
1346 | 1352 | ||
1347 | /* Deselect and wake up anyone waiting on the device */ | 1353 | /* Deselect and wake up anyone waiting on the device */ |
@@ -1378,7 +1384,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
1378 | /* Shift to get page */ | 1384 | /* Shift to get page */ |
1379 | page = (int)(from >> this->page_shift); | 1385 | page = (int)(from >> this->page_shift); |
1380 | chipnr = (int)(from >> this->chip_shift); | 1386 | chipnr = (int)(from >> this->chip_shift); |
1381 | 1387 | ||
1382 | /* Mask to get column */ | 1388 | /* Mask to get column */ |
1383 | col = from & (mtd->oobsize - 1); | 1389 | col = from & (mtd->oobsize - 1); |
1384 | 1390 | ||
@@ -1400,7 +1406,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
1400 | 1406 | ||
1401 | /* Send the read command */ | 1407 | /* Send the read command */ |
1402 | this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); | 1408 | this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); |
1403 | /* | 1409 | /* |
1404 | * Read the data, if we read more than one page | 1410 | * Read the data, if we read more than one page |
1405 | * oob data, let the device transfer the data ! | 1411 | * oob data, let the device transfer the data ! |
1406 | */ | 1412 | */ |
@@ -1422,20 +1428,20 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t | |||
1422 | this->select_chip(mtd, -1); | 1428 | this->select_chip(mtd, -1); |
1423 | this->select_chip(mtd, chipnr); | 1429 | this->select_chip(mtd, chipnr); |
1424 | } | 1430 | } |
1425 | 1431 | ||
1426 | /* Apply delay or wait for ready/busy pin | 1432 | /* Apply delay or wait for ready/busy pin |
1427 | * Do this before the AUTOINCR check, so no problems | 1433 | * Do this before the AUTOINCR check, so no problems |
1428 | * arise if a chip which does auto increment | 1434 | * arise if a chip which does auto increment |
1429 | * is marked as NOAUTOINCR by the board driver. | 1435 | * is marked as NOAUTOINCR by the board driver. |
1430 | */ | 1436 | */ |
1431 | if (!this->dev_ready) | 1437 | if (!this->dev_ready) |
1432 | udelay (this->chip_delay); | 1438 | udelay (this->chip_delay); |
1433 | else | 1439 | else |
1434 | nand_wait_ready(mtd); | 1440 | nand_wait_ready(mtd); |
1435 | 1441 | ||
1436 | /* Check, if the chip supports auto page increment | 1442 | /* Check, if the chip supports auto page increment |
1437 | * or if we have hit a block boundary. | 1443 | * or if we have hit a block boundary. |
1438 | */ | 1444 | */ |
1439 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { | 1445 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { |
1440 | /* For subsequent page reads set offset to 0 */ | 1446 | /* For subsequent page reads set offset to 0 */ |
1441 | this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); | 1447 | this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); |
@@ -1481,27 +1487,27 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, | |||
1481 | nand_get_device (this, mtd , FL_READING); | 1487 | nand_get_device (this, mtd , FL_READING); |
1482 | 1488 | ||
1483 | this->select_chip (mtd, chip); | 1489 | this->select_chip (mtd, chip); |
1484 | 1490 | ||
1485 | /* Add requested oob length */ | 1491 | /* Add requested oob length */ |
1486 | len += ooblen; | 1492 | len += ooblen; |
1487 | 1493 | ||
1488 | while (len) { | 1494 | while (len) { |
1489 | if (sndcmd) | 1495 | if (sndcmd) |
1490 | this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); | 1496 | this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); |
1491 | sndcmd = 0; | 1497 | sndcmd = 0; |
1492 | 1498 | ||
1493 | this->read_buf (mtd, &buf[cnt], pagesize); | 1499 | this->read_buf (mtd, &buf[cnt], pagesize); |
1494 | 1500 | ||
1495 | len -= pagesize; | 1501 | len -= pagesize; |
1496 | cnt += pagesize; | 1502 | cnt += pagesize; |
1497 | page++; | 1503 | page++; |
1498 | 1504 | ||
1499 | if (!this->dev_ready) | 1505 | if (!this->dev_ready) |
1500 | udelay (this->chip_delay); | 1506 | udelay (this->chip_delay); |
1501 | else | 1507 | else |
1502 | nand_wait_ready(mtd); | 1508 | nand_wait_ready(mtd); |
1503 | 1509 | ||
1504 | /* Check, if the chip supports auto page increment */ | 1510 | /* Check, if the chip supports auto page increment */ |
1505 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) | 1511 | if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) |
1506 | sndcmd = 1; | 1512 | sndcmd = 1; |
1507 | } | 1513 | } |
@@ -1512,8 +1518,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, | |||
1512 | } | 1518 | } |
1513 | 1519 | ||
1514 | 1520 | ||
1515 | /** | 1521 | /** |
1516 | * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer | 1522 | * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer |
1517 | * @mtd: MTD device structure | 1523 | * @mtd: MTD device structure |
1518 | * @fsbuf: buffer given by fs driver | 1524 | * @fsbuf: buffer given by fs driver |
1519 | * @oobsel: out of band selection structre | 1525 | * @oobsel: out of band selection structre |
@@ -1542,20 +1548,20 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct | |||
1542 | int i, len, ofs; | 1548 | int i, len, ofs; |
1543 | 1549 | ||
1544 | /* Zero copy fs supplied buffer */ | 1550 | /* Zero copy fs supplied buffer */ |
1545 | if (fsbuf && !autoplace) | 1551 | if (fsbuf && !autoplace) |
1546 | return fsbuf; | 1552 | return fsbuf; |
1547 | 1553 | ||
1548 | /* Check, if the buffer must be filled with ff again */ | 1554 | /* Check, if the buffer must be filled with ff again */ |
1549 | if (this->oobdirty) { | 1555 | if (this->oobdirty) { |
1550 | memset (this->oob_buf, 0xff, | 1556 | memset (this->oob_buf, 0xff, |
1551 | mtd->oobsize << (this->phys_erase_shift - this->page_shift)); | 1557 | mtd->oobsize << (this->phys_erase_shift - this->page_shift)); |
1552 | this->oobdirty = 0; | 1558 | this->oobdirty = 0; |
1553 | } | 1559 | } |
1554 | 1560 | ||
1555 | /* If we have no autoplacement or no fs buffer use the internal one */ | 1561 | /* If we have no autoplacement or no fs buffer use the internal one */ |
1556 | if (!autoplace || !fsbuf) | 1562 | if (!autoplace || !fsbuf) |
1557 | return this->oob_buf; | 1563 | return this->oob_buf; |
1558 | 1564 | ||
1559 | /* Walk through the pages and place the data */ | 1565 | /* Walk through the pages and place the data */ |
1560 | this->oobdirty = 1; | 1566 | this->oobdirty = 1; |
1561 | ofs = 0; | 1567 | ofs = 0; |
@@ -1589,7 +1595,7 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret | |||
1589 | { | 1595 | { |
1590 | return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); | 1596 | return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); |
1591 | } | 1597 | } |
1592 | 1598 | ||
1593 | /** | 1599 | /** |
1594 | * nand_write_ecc - [MTD Interface] NAND write with ECC | 1600 | * nand_write_ecc - [MTD Interface] NAND write with ECC |
1595 | * @mtd: MTD device structure | 1601 | * @mtd: MTD device structure |
@@ -1622,7 +1628,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1622 | return -EINVAL; | 1628 | return -EINVAL; |
1623 | } | 1629 | } |
1624 | 1630 | ||
1625 | /* reject writes, which are not page aligned */ | 1631 | /* reject writes, which are not page aligned */ |
1626 | if (NOTALIGNED (to) || NOTALIGNED(len)) { | 1632 | if (NOTALIGNED (to) || NOTALIGNED(len)) { |
1627 | printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); | 1633 | printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); |
1628 | return -EINVAL; | 1634 | return -EINVAL; |
@@ -1641,14 +1647,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1641 | goto out; | 1647 | goto out; |
1642 | 1648 | ||
1643 | /* if oobsel is NULL, use chip defaults */ | 1649 | /* if oobsel is NULL, use chip defaults */ |
1644 | if (oobsel == NULL) | 1650 | if (oobsel == NULL) |
1645 | oobsel = &mtd->oobinfo; | 1651 | oobsel = &mtd->oobinfo; |
1646 | 1652 | ||
1647 | /* Autoplace of oob data ? Use the default placement scheme */ | 1653 | /* Autoplace of oob data ? Use the default placement scheme */ |
1648 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { | 1654 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { |
1649 | oobsel = this->autooob; | 1655 | oobsel = this->autooob; |
1650 | autoplace = 1; | 1656 | autoplace = 1; |
1651 | } | 1657 | } |
1652 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) | 1658 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) |
1653 | autoplace = 1; | 1659 | autoplace = 1; |
1654 | 1660 | ||
@@ -1656,9 +1662,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1656 | totalpages = len >> this->page_shift; | 1662 | totalpages = len >> this->page_shift; |
1657 | page = (int) (to >> this->page_shift); | 1663 | page = (int) (to >> this->page_shift); |
1658 | /* Invalidate the page cache, if we write to the cached page */ | 1664 | /* Invalidate the page cache, if we write to the cached page */ |
1659 | if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) | 1665 | if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) |
1660 | this->pagebuf = -1; | 1666 | this->pagebuf = -1; |
1661 | 1667 | ||
1662 | /* Set it relative to chip */ | 1668 | /* Set it relative to chip */ |
1663 | page &= this->pagemask; | 1669 | page &= this->pagemask; |
1664 | startpage = page; | 1670 | startpage = page; |
@@ -1680,14 +1686,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1680 | if (ret) { | 1686 | if (ret) { |
1681 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); | 1687 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); |
1682 | goto out; | 1688 | goto out; |
1683 | } | 1689 | } |
1684 | /* Next oob page */ | 1690 | /* Next oob page */ |
1685 | oob += mtd->oobsize; | 1691 | oob += mtd->oobsize; |
1686 | /* Update written bytes count */ | 1692 | /* Update written bytes count */ |
1687 | written += mtd->oobblock; | 1693 | written += mtd->oobblock; |
1688 | if (written == len) | 1694 | if (written == len) |
1689 | goto cmp; | 1695 | goto cmp; |
1690 | 1696 | ||
1691 | /* Increment page address */ | 1697 | /* Increment page address */ |
1692 | page++; | 1698 | page++; |
1693 | 1699 | ||
@@ -1698,13 +1704,13 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1698 | if (!(page & (ppblock - 1))){ | 1704 | if (!(page & (ppblock - 1))){ |
1699 | int ofs; | 1705 | int ofs; |
1700 | this->data_poi = bufstart; | 1706 | this->data_poi = bufstart; |
1701 | ret = nand_verify_pages (mtd, this, startpage, | 1707 | ret = nand_verify_pages (mtd, this, startpage, |
1702 | page - startpage, | 1708 | page - startpage, |
1703 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); | 1709 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); |
1704 | if (ret) { | 1710 | if (ret) { |
1705 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); | 1711 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); |
1706 | goto out; | 1712 | goto out; |
1707 | } | 1713 | } |
1708 | *retlen = written; | 1714 | *retlen = written; |
1709 | 1715 | ||
1710 | ofs = autoplace ? mtd->oobavail : mtd->oobsize; | 1716 | ofs = autoplace ? mtd->oobavail : mtd->oobsize; |
@@ -1714,8 +1720,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | |||
1714 | numpages = min (totalpages, ppblock); | 1720 | numpages = min (totalpages, ppblock); |
1715 | page &= this->pagemask; | 1721 | page &= this->pagemask; |
1716 | startpage = page; | 1722 | startpage = page; |
1717 | oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, | 1723 | oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, |
1718 | autoplace, numpages); | 1724 | autoplace, numpages); |
1725 | oob = 0; | ||
1719 | /* Check, if we cross a chip boundary */ | 1726 | /* Check, if we cross a chip boundary */ |
1720 | if (!page) { | 1727 | if (!page) { |
1721 | chipnr++; | 1728 | chipnr++; |
@@ -1731,7 +1738,7 @@ cmp: | |||
1731 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); | 1738 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); |
1732 | if (!ret) | 1739 | if (!ret) |
1733 | *retlen = written; | 1740 | *retlen = written; |
1734 | else | 1741 | else |
1735 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); | 1742 | DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); |
1736 | 1743 | ||
1737 | out: | 1744 | out: |
@@ -1791,7 +1798,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * | |||
1791 | /* Check, if it is write protected */ | 1798 | /* Check, if it is write protected */ |
1792 | if (nand_check_wp(mtd)) | 1799 | if (nand_check_wp(mtd)) |
1793 | goto out; | 1800 | goto out; |
1794 | 1801 | ||
1795 | /* Invalidate the page cache, if we write to the cached page */ | 1802 | /* Invalidate the page cache, if we write to the cached page */ |
1796 | if (page == this->pagebuf) | 1803 | if (page == this->pagebuf) |
1797 | this->pagebuf = -1; | 1804 | this->pagebuf = -1; |
@@ -1854,10 +1861,10 @@ out: | |||
1854 | * | 1861 | * |
1855 | * NAND write with kvec. This just calls the ecc function | 1862 | * NAND write with kvec. This just calls the ecc function |
1856 | */ | 1863 | */ |
1857 | static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, | 1864 | static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, |
1858 | loff_t to, size_t * retlen) | 1865 | loff_t to, size_t * retlen) |
1859 | { | 1866 | { |
1860 | return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); | 1867 | return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); |
1861 | } | 1868 | } |
1862 | 1869 | ||
1863 | /** | 1870 | /** |
@@ -1872,7 +1879,7 @@ static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned | |||
1872 | * | 1879 | * |
1873 | * NAND write with iovec with ecc | 1880 | * NAND write with iovec with ecc |
1874 | */ | 1881 | */ |
1875 | static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, | 1882 | static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, |
1876 | loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) | 1883 | loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) |
1877 | { | 1884 | { |
1878 | int i, page, len, total_len, ret = -EIO, written = 0, chipnr; | 1885 | int i, page, len, total_len, ret = -EIO, written = 0, chipnr; |
@@ -1898,7 +1905,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1898 | return -EINVAL; | 1905 | return -EINVAL; |
1899 | } | 1906 | } |
1900 | 1907 | ||
1901 | /* reject writes, which are not page aligned */ | 1908 | /* reject writes, which are not page aligned */ |
1902 | if (NOTALIGNED (to) || NOTALIGNED(total_len)) { | 1909 | if (NOTALIGNED (to) || NOTALIGNED(total_len)) { |
1903 | printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); | 1910 | printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); |
1904 | return -EINVAL; | 1911 | return -EINVAL; |
@@ -1917,21 +1924,21 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1917 | goto out; | 1924 | goto out; |
1918 | 1925 | ||
1919 | /* if oobsel is NULL, use chip defaults */ | 1926 | /* if oobsel is NULL, use chip defaults */ |
1920 | if (oobsel == NULL) | 1927 | if (oobsel == NULL) |
1921 | oobsel = &mtd->oobinfo; | 1928 | oobsel = &mtd->oobinfo; |
1922 | 1929 | ||
1923 | /* Autoplace of oob data ? Use the default placement scheme */ | 1930 | /* Autoplace of oob data ? Use the default placement scheme */ |
1924 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { | 1931 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { |
1925 | oobsel = this->autooob; | 1932 | oobsel = this->autooob; |
1926 | autoplace = 1; | 1933 | autoplace = 1; |
1927 | } | 1934 | } |
1928 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) | 1935 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) |
1929 | autoplace = 1; | 1936 | autoplace = 1; |
1930 | 1937 | ||
1931 | /* Setup start page */ | 1938 | /* Setup start page */ |
1932 | page = (int) (to >> this->page_shift); | 1939 | page = (int) (to >> this->page_shift); |
1933 | /* Invalidate the page cache, if we write to the cached page */ | 1940 | /* Invalidate the page cache, if we write to the cached page */ |
1934 | if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) | 1941 | if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) |
1935 | this->pagebuf = -1; | 1942 | this->pagebuf = -1; |
1936 | 1943 | ||
1937 | startpage = page & this->pagemask; | 1944 | startpage = page & this->pagemask; |
@@ -1955,10 +1962,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1955 | oob = 0; | 1962 | oob = 0; |
1956 | for (i = 1; i <= numpages; i++) { | 1963 | for (i = 1; i <= numpages; i++) { |
1957 | /* Write one page. If this is the last page to write | 1964 | /* Write one page. If this is the last page to write |
1958 | * then use the real pageprogram command, else select | 1965 | * then use the real pageprogram command, else select |
1959 | * cached programming if supported by the chip. | 1966 | * cached programming if supported by the chip. |
1960 | */ | 1967 | */ |
1961 | ret = nand_write_page (mtd, this, page & this->pagemask, | 1968 | ret = nand_write_page (mtd, this, page & this->pagemask, |
1962 | &oobbuf[oob], oobsel, i != numpages); | 1969 | &oobbuf[oob], oobsel, i != numpages); |
1963 | if (ret) | 1970 | if (ret) |
1964 | goto out; | 1971 | goto out; |
@@ -1974,12 +1981,12 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1974 | count--; | 1981 | count--; |
1975 | } | 1982 | } |
1976 | } else { | 1983 | } else { |
1977 | /* We must use the internal buffer, read data out of each | 1984 | /* We must use the internal buffer, read data out of each |
1978 | * tuple until we have a full page to write | 1985 | * tuple until we have a full page to write |
1979 | */ | 1986 | */ |
1980 | int cnt = 0; | 1987 | int cnt = 0; |
1981 | while (cnt < mtd->oobblock) { | 1988 | while (cnt < mtd->oobblock) { |
1982 | if (vecs->iov_base != NULL && vecs->iov_len) | 1989 | if (vecs->iov_base != NULL && vecs->iov_len) |
1983 | this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; | 1990 | this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; |
1984 | /* Check, if we have to switch to the next tuple */ | 1991 | /* Check, if we have to switch to the next tuple */ |
1985 | if (len >= (int) vecs->iov_len) { | 1992 | if (len >= (int) vecs->iov_len) { |
@@ -1988,10 +1995,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
1988 | count--; | 1995 | count--; |
1989 | } | 1996 | } |
1990 | } | 1997 | } |
1991 | this->pagebuf = page; | 1998 | this->pagebuf = page; |
1992 | this->data_poi = this->data_buf; | 1999 | this->data_poi = this->data_buf; |
1993 | bufstart = this->data_poi; | 2000 | bufstart = this->data_poi; |
1994 | numpages = 1; | 2001 | numpages = 1; |
1995 | oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); | 2002 | oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); |
1996 | ret = nand_write_page (mtd, this, page & this->pagemask, | 2003 | ret = nand_write_page (mtd, this, page & this->pagemask, |
1997 | oobbuf, oobsel, 0); | 2004 | oobbuf, oobsel, 0); |
@@ -2004,7 +2011,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig | |||
2004 | ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); | 2011 | ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); |
2005 | if (ret) | 2012 | if (ret) |
2006 | goto out; | 2013 | goto out; |
2007 | 2014 | ||
2008 | written += mtd->oobblock * numpages; | 2015 | written += mtd->oobblock * numpages; |
2009 | /* All done ? */ | 2016 | /* All done ? */ |
2010 | if (!count) | 2017 | if (!count) |
@@ -2072,7 +2079,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) | |||
2072 | { | 2079 | { |
2073 | return nand_erase_nand (mtd, instr, 0); | 2080 | return nand_erase_nand (mtd, instr, 0); |
2074 | } | 2081 | } |
2075 | 2082 | ||
2076 | #define BBT_PAGE_MASK 0xffffff3f | 2083 | #define BBT_PAGE_MASK 0xffffff3f |
2077 | /** | 2084 | /** |
2078 | * nand_erase_intern - [NAND Interface] erase block(s) | 2085 | * nand_erase_intern - [NAND Interface] erase block(s) |
@@ -2154,14 +2161,14 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2154 | instr->state = MTD_ERASE_FAILED; | 2161 | instr->state = MTD_ERASE_FAILED; |
2155 | goto erase_exit; | 2162 | goto erase_exit; |
2156 | } | 2163 | } |
2157 | 2164 | ||
2158 | /* Invalidate the page cache, if we erase the block which contains | 2165 | /* Invalidate the page cache, if we erase the block which contains |
2159 | the current cached page */ | 2166 | the current cached page */ |
2160 | if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) | 2167 | if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) |
2161 | this->pagebuf = -1; | 2168 | this->pagebuf = -1; |
2162 | 2169 | ||
2163 | this->erase_cmd (mtd, page & this->pagemask); | 2170 | this->erase_cmd (mtd, page & this->pagemask); |
2164 | 2171 | ||
2165 | status = this->waitfunc (mtd, this, FL_ERASING); | 2172 | status = this->waitfunc (mtd, this, FL_ERASING); |
2166 | 2173 | ||
2167 | /* See if operation failed and additional status checks are available */ | 2174 | /* See if operation failed and additional status checks are available */ |
@@ -2179,12 +2186,12 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2179 | 2186 | ||
2180 | /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ | 2187 | /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ |
2181 | if (this->options & BBT_AUTO_REFRESH) { | 2188 | if (this->options & BBT_AUTO_REFRESH) { |
2182 | if (((page & BBT_PAGE_MASK) == bbt_masked_page) && | 2189 | if (((page & BBT_PAGE_MASK) == bbt_masked_page) && |
2183 | (page != this->bbt_td->pages[chipnr])) { | 2190 | (page != this->bbt_td->pages[chipnr])) { |
2184 | rewrite_bbt[chipnr] = (page << this->page_shift); | 2191 | rewrite_bbt[chipnr] = (page << this->page_shift); |
2185 | } | 2192 | } |
2186 | } | 2193 | } |
2187 | 2194 | ||
2188 | /* Increment page address and decrement length */ | 2195 | /* Increment page address and decrement length */ |
2189 | len -= (1 << this->phys_erase_shift); | 2196 | len -= (1 << this->phys_erase_shift); |
2190 | page += pages_per_block; | 2197 | page += pages_per_block; |
@@ -2195,7 +2202,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb | |||
2195 | this->select_chip(mtd, -1); | 2202 | this->select_chip(mtd, -1); |
2196 | this->select_chip(mtd, chipnr); | 2203 | this->select_chip(mtd, chipnr); |
2197 | 2204 | ||
2198 | /* if BBT requires refresh and BBT-PERCHIP, | 2205 | /* if BBT requires refresh and BBT-PERCHIP, |
2199 | * set the BBT page mask to see if this BBT should be rewritten */ | 2206 | * set the BBT page mask to see if this BBT should be rewritten */ |
2200 | if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { | 2207 | if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { |
2201 | bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; | 2208 | bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; |
@@ -2220,7 +2227,7 @@ erase_exit: | |||
2220 | for (chipnr = 0; chipnr < this->numchips; chipnr++) { | 2227 | for (chipnr = 0; chipnr < this->numchips; chipnr++) { |
2221 | if (rewrite_bbt[chipnr]) { | 2228 | if (rewrite_bbt[chipnr]) { |
2222 | /* update the BBT for chip */ | 2229 | /* update the BBT for chip */ |
2223 | DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", | 2230 | DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", |
2224 | chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); | 2231 | chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); |
2225 | nand_update_bbt (mtd, rewrite_bbt[chipnr]); | 2232 | nand_update_bbt (mtd, rewrite_bbt[chipnr]); |
2226 | } | 2233 | } |
@@ -2258,9 +2265,9 @@ static void nand_sync (struct mtd_info *mtd) | |||
2258 | static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) | 2265 | static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) |
2259 | { | 2266 | { |
2260 | /* Check for invalid offset */ | 2267 | /* Check for invalid offset */ |
2261 | if (ofs > mtd->size) | 2268 | if (ofs > mtd->size) |
2262 | return -EINVAL; | 2269 | return -EINVAL; |
2263 | 2270 | ||
2264 | return nand_block_checkbad (mtd, ofs, 1, 0); | 2271 | return nand_block_checkbad (mtd, ofs, 1, 0); |
2265 | } | 2272 | } |
2266 | 2273 | ||
@@ -2285,6 +2292,34 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) | |||
2285 | } | 2292 | } |
2286 | 2293 | ||
2287 | /** | 2294 | /** |
2295 | * nand_suspend - [MTD Interface] Suspend the NAND flash | ||
2296 | * @mtd: MTD device structure | ||
2297 | */ | ||
2298 | static int nand_suspend(struct mtd_info *mtd) | ||
2299 | { | ||
2300 | struct nand_chip *this = mtd->priv; | ||
2301 | |||
2302 | return nand_get_device (this, mtd, FL_PM_SUSPENDED); | ||
2303 | } | ||
2304 | |||
2305 | /** | ||
2306 | * nand_resume - [MTD Interface] Resume the NAND flash | ||
2307 | * @mtd: MTD device structure | ||
2308 | */ | ||
2309 | static void nand_resume(struct mtd_info *mtd) | ||
2310 | { | ||
2311 | struct nand_chip *this = mtd->priv; | ||
2312 | |||
2313 | if (this->state == FL_PM_SUSPENDED) | ||
2314 | nand_release_device(mtd); | ||
2315 | else | ||
2316 | printk(KERN_ERR "resume() called for the chip which is not " | ||
2317 | "in suspended state\n"); | ||
2318 | |||
2319 | } | ||
2320 | |||
2321 | |||
2322 | /** | ||
2288 | * nand_scan - [NAND Interface] Scan for the NAND device | 2323 | * nand_scan - [NAND Interface] Scan for the NAND device |
2289 | * @mtd: MTD device structure | 2324 | * @mtd: MTD device structure |
2290 | * @maxchips: Number of chips to scan for | 2325 | * @maxchips: Number of chips to scan for |
@@ -2351,13 +2386,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2351 | 2386 | ||
2352 | /* Print and store flash device information */ | 2387 | /* Print and store flash device information */ |
2353 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 2388 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
2354 | 2389 | ||
2355 | if (nand_dev_id != nand_flash_ids[i].id) | 2390 | if (nand_dev_id != nand_flash_ids[i].id) |
2356 | continue; | 2391 | continue; |
2357 | 2392 | ||
2358 | if (!mtd->name) mtd->name = nand_flash_ids[i].name; | 2393 | if (!mtd->name) mtd->name = nand_flash_ids[i].name; |
2359 | this->chipsize = nand_flash_ids[i].chipsize << 20; | 2394 | this->chipsize = nand_flash_ids[i].chipsize << 20; |
2360 | 2395 | ||
2361 | /* New devices have all the information in additional id bytes */ | 2396 | /* New devices have all the information in additional id bytes */ |
2362 | if (!nand_flash_ids[i].pagesize) { | 2397 | if (!nand_flash_ids[i].pagesize) { |
2363 | int extid; | 2398 | int extid; |
@@ -2369,14 +2404,14 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2369 | mtd->oobblock = 1024 << (extid & 0x3); | 2404 | mtd->oobblock = 1024 << (extid & 0x3); |
2370 | extid >>= 2; | 2405 | extid >>= 2; |
2371 | /* Calc oobsize */ | 2406 | /* Calc oobsize */ |
2372 | mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512); | 2407 | mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9); |
2373 | extid >>= 2; | 2408 | extid >>= 2; |
2374 | /* Calc blocksize. Blocksize is multiples of 64KiB */ | 2409 | /* Calc blocksize. Blocksize is multiples of 64KiB */ |
2375 | mtd->erasesize = (64 * 1024) << (extid & 0x03); | 2410 | mtd->erasesize = (64 * 1024) << (extid & 0x03); |
2376 | extid >>= 2; | 2411 | extid >>= 2; |
2377 | /* Get buswidth information */ | 2412 | /* Get buswidth information */ |
2378 | busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; | 2413 | busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; |
2379 | 2414 | ||
2380 | } else { | 2415 | } else { |
2381 | /* Old devices have this data hardcoded in the | 2416 | /* Old devices have this data hardcoded in the |
2382 | * device id table */ | 2417 | * device id table */ |
@@ -2396,23 +2431,23 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2396 | * this correct ! */ | 2431 | * this correct ! */ |
2397 | if (busw != (this->options & NAND_BUSWIDTH_16)) { | 2432 | if (busw != (this->options & NAND_BUSWIDTH_16)) { |
2398 | printk (KERN_INFO "NAND device: Manufacturer ID:" | 2433 | printk (KERN_INFO "NAND device: Manufacturer ID:" |
2399 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, | 2434 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, |
2400 | nand_manuf_ids[maf_id].name , mtd->name); | 2435 | nand_manuf_ids[maf_id].name , mtd->name); |
2401 | printk (KERN_WARNING | 2436 | printk (KERN_WARNING |
2402 | "NAND bus width %d instead %d bit\n", | 2437 | "NAND bus width %d instead %d bit\n", |
2403 | (this->options & NAND_BUSWIDTH_16) ? 16 : 8, | 2438 | (this->options & NAND_BUSWIDTH_16) ? 16 : 8, |
2404 | busw ? 16 : 8); | 2439 | busw ? 16 : 8); |
2405 | this->select_chip(mtd, -1); | 2440 | this->select_chip(mtd, -1); |
2406 | return 1; | 2441 | return 1; |
2407 | } | 2442 | } |
2408 | 2443 | ||
2409 | /* Calculate the address shift from the page size */ | 2444 | /* Calculate the address shift from the page size */ |
2410 | this->page_shift = ffs(mtd->oobblock) - 1; | 2445 | this->page_shift = ffs(mtd->oobblock) - 1; |
2411 | this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; | 2446 | this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; |
2412 | this->chip_shift = ffs(this->chipsize) - 1; | 2447 | this->chip_shift = ffs(this->chipsize) - 1; |
2413 | 2448 | ||
2414 | /* Set the bad block position */ | 2449 | /* Set the bad block position */ |
2415 | this->badblockpos = mtd->oobblock > 512 ? | 2450 | this->badblockpos = mtd->oobblock > 512 ? |
2416 | NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; | 2451 | NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; |
2417 | 2452 | ||
2418 | /* Get chip options, preserve non chip based options */ | 2453 | /* Get chip options, preserve non chip based options */ |
@@ -2422,10 +2457,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2422 | this->options |= NAND_NO_AUTOINCR; | 2457 | this->options |= NAND_NO_AUTOINCR; |
2423 | /* Check if this is a not a samsung device. Do not clear the options | 2458 | /* Check if this is a not a samsung device. Do not clear the options |
2424 | * for chips which are not having an extended id. | 2459 | * for chips which are not having an extended id. |
2425 | */ | 2460 | */ |
2426 | if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) | 2461 | if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) |
2427 | this->options &= ~NAND_SAMSUNG_LP_OPTIONS; | 2462 | this->options &= ~NAND_SAMSUNG_LP_OPTIONS; |
2428 | 2463 | ||
2429 | /* Check for AND chips with 4 page planes */ | 2464 | /* Check for AND chips with 4 page planes */ |
2430 | if (this->options & NAND_4PAGE_ARRAY) | 2465 | if (this->options & NAND_4PAGE_ARRAY) |
2431 | this->erase_cmd = multi_erase_cmd; | 2466 | this->erase_cmd = multi_erase_cmd; |
@@ -2435,9 +2470,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2435 | /* Do not replace user supplied command function ! */ | 2470 | /* Do not replace user supplied command function ! */ |
2436 | if (mtd->oobblock > 512 && this->cmdfunc == nand_command) | 2471 | if (mtd->oobblock > 512 && this->cmdfunc == nand_command) |
2437 | this->cmdfunc = nand_command_lp; | 2472 | this->cmdfunc = nand_command_lp; |
2438 | 2473 | ||
2439 | printk (KERN_INFO "NAND device: Manufacturer ID:" | 2474 | printk (KERN_INFO "NAND device: Manufacturer ID:" |
2440 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, | 2475 | " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, |
2441 | nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); | 2476 | nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); |
2442 | break; | 2477 | break; |
2443 | } | 2478 | } |
@@ -2461,7 +2496,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2461 | } | 2496 | } |
2462 | if (i > 1) | 2497 | if (i > 1) |
2463 | printk(KERN_INFO "%d NAND chips detected\n", i); | 2498 | printk(KERN_INFO "%d NAND chips detected\n", i); |
2464 | 2499 | ||
2465 | /* Allocate buffers, if neccecary */ | 2500 | /* Allocate buffers, if neccecary */ |
2466 | if (!this->oob_buf) { | 2501 | if (!this->oob_buf) { |
2467 | size_t len; | 2502 | size_t len; |
@@ -2473,7 +2508,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2473 | } | 2508 | } |
2474 | this->options |= NAND_OOBBUF_ALLOC; | 2509 | this->options |= NAND_OOBBUF_ALLOC; |
2475 | } | 2510 | } |
2476 | 2511 | ||
2477 | if (!this->data_buf) { | 2512 | if (!this->data_buf) { |
2478 | size_t len; | 2513 | size_t len; |
2479 | len = mtd->oobblock + mtd->oobsize; | 2514 | len = mtd->oobblock + mtd->oobsize; |
@@ -2500,7 +2535,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2500 | if (!this->autooob) { | 2535 | if (!this->autooob) { |
2501 | /* Select the appropriate default oob placement scheme for | 2536 | /* Select the appropriate default oob placement scheme for |
2502 | * placement agnostic filesystems */ | 2537 | * placement agnostic filesystems */ |
2503 | switch (mtd->oobsize) { | 2538 | switch (mtd->oobsize) { |
2504 | case 8: | 2539 | case 8: |
2505 | this->autooob = &nand_oob_8; | 2540 | this->autooob = &nand_oob_8; |
2506 | break; | 2541 | break; |
@@ -2516,19 +2551,19 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2516 | BUG(); | 2551 | BUG(); |
2517 | } | 2552 | } |
2518 | } | 2553 | } |
2519 | 2554 | ||
2520 | /* The number of bytes available for the filesystem to place fs dependend | 2555 | /* The number of bytes available for the filesystem to place fs dependend |
2521 | * oob data */ | 2556 | * oob data */ |
2522 | mtd->oobavail = 0; | 2557 | mtd->oobavail = 0; |
2523 | for (i = 0; this->autooob->oobfree[i][1]; i++) | 2558 | for (i = 0; this->autooob->oobfree[i][1]; i++) |
2524 | mtd->oobavail += this->autooob->oobfree[i][1]; | 2559 | mtd->oobavail += this->autooob->oobfree[i][1]; |
2525 | 2560 | ||
2526 | /* | 2561 | /* |
2527 | * check ECC mode, default to software | 2562 | * check ECC mode, default to software |
2528 | * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize | 2563 | * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize |
2529 | * fallback to software ECC | 2564 | * fallback to software ECC |
2530 | */ | 2565 | */ |
2531 | this->eccsize = 256; /* set default eccsize */ | 2566 | this->eccsize = 256; /* set default eccsize */ |
2532 | this->eccbytes = 3; | 2567 | this->eccbytes = 3; |
2533 | 2568 | ||
2534 | switch (this->eccmode) { | 2569 | switch (this->eccmode) { |
@@ -2543,56 +2578,56 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2543 | this->eccsize = 2048; | 2578 | this->eccsize = 2048; |
2544 | break; | 2579 | break; |
2545 | 2580 | ||
2546 | case NAND_ECC_HW3_512: | 2581 | case NAND_ECC_HW3_512: |
2547 | case NAND_ECC_HW6_512: | 2582 | case NAND_ECC_HW6_512: |
2548 | case NAND_ECC_HW8_512: | 2583 | case NAND_ECC_HW8_512: |
2549 | if (mtd->oobblock == 256) { | 2584 | if (mtd->oobblock == 256) { |
2550 | printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); | 2585 | printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); |
2551 | this->eccmode = NAND_ECC_SOFT; | 2586 | this->eccmode = NAND_ECC_SOFT; |
2552 | this->calculate_ecc = nand_calculate_ecc; | 2587 | this->calculate_ecc = nand_calculate_ecc; |
2553 | this->correct_data = nand_correct_data; | 2588 | this->correct_data = nand_correct_data; |
2554 | } else | 2589 | } else |
2555 | this->eccsize = 512; /* set eccsize to 512 */ | 2590 | this->eccsize = 512; /* set eccsize to 512 */ |
2556 | break; | 2591 | break; |
2557 | 2592 | ||
2558 | case NAND_ECC_HW3_256: | 2593 | case NAND_ECC_HW3_256: |
2559 | break; | 2594 | break; |
2560 | 2595 | ||
2561 | case NAND_ECC_NONE: | 2596 | case NAND_ECC_NONE: |
2562 | printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); | 2597 | printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); |
2563 | this->eccmode = NAND_ECC_NONE; | 2598 | this->eccmode = NAND_ECC_NONE; |
2564 | break; | 2599 | break; |
2565 | 2600 | ||
2566 | case NAND_ECC_SOFT: | 2601 | case NAND_ECC_SOFT: |
2567 | this->calculate_ecc = nand_calculate_ecc; | 2602 | this->calculate_ecc = nand_calculate_ecc; |
2568 | this->correct_data = nand_correct_data; | 2603 | this->correct_data = nand_correct_data; |
2569 | break; | 2604 | break; |
2570 | 2605 | ||
2571 | default: | 2606 | default: |
2572 | printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); | 2607 | printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); |
2573 | BUG(); | 2608 | BUG(); |
2574 | } | 2609 | } |
2575 | 2610 | ||
2576 | /* Check hardware ecc function availability and adjust number of ecc bytes per | 2611 | /* Check hardware ecc function availability and adjust number of ecc bytes per |
2577 | * calculation step | 2612 | * calculation step |
2578 | */ | 2613 | */ |
2579 | switch (this->eccmode) { | 2614 | switch (this->eccmode) { |
2580 | case NAND_ECC_HW12_2048: | 2615 | case NAND_ECC_HW12_2048: |
2581 | this->eccbytes += 4; | 2616 | this->eccbytes += 4; |
2582 | case NAND_ECC_HW8_512: | 2617 | case NAND_ECC_HW8_512: |
2583 | this->eccbytes += 2; | 2618 | this->eccbytes += 2; |
2584 | case NAND_ECC_HW6_512: | 2619 | case NAND_ECC_HW6_512: |
2585 | this->eccbytes += 3; | 2620 | this->eccbytes += 3; |
2586 | case NAND_ECC_HW3_512: | 2621 | case NAND_ECC_HW3_512: |
2587 | case NAND_ECC_HW3_256: | 2622 | case NAND_ECC_HW3_256: |
2588 | if (this->calculate_ecc && this->correct_data && this->enable_hwecc) | 2623 | if (this->calculate_ecc && this->correct_data && this->enable_hwecc) |
2589 | break; | 2624 | break; |
2590 | printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); | 2625 | printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); |
2591 | BUG(); | 2626 | BUG(); |
2592 | } | 2627 | } |
2593 | 2628 | ||
2594 | mtd->eccsize = this->eccsize; | 2629 | mtd->eccsize = this->eccsize; |
2595 | 2630 | ||
2596 | /* Set the number of read / write steps for one page to ensure ECC generation */ | 2631 | /* Set the number of read / write steps for one page to ensure ECC generation */ |
2597 | switch (this->eccmode) { | 2632 | switch (this->eccmode) { |
2598 | case NAND_ECC_HW12_2048: | 2633 | case NAND_ECC_HW12_2048: |
@@ -2604,15 +2639,15 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2604 | this->eccsteps = mtd->oobblock / 512; | 2639 | this->eccsteps = mtd->oobblock / 512; |
2605 | break; | 2640 | break; |
2606 | case NAND_ECC_HW3_256: | 2641 | case NAND_ECC_HW3_256: |
2607 | case NAND_ECC_SOFT: | 2642 | case NAND_ECC_SOFT: |
2608 | this->eccsteps = mtd->oobblock / 256; | 2643 | this->eccsteps = mtd->oobblock / 256; |
2609 | break; | 2644 | break; |
2610 | 2645 | ||
2611 | case NAND_ECC_NONE: | 2646 | case NAND_ECC_NONE: |
2612 | this->eccsteps = 1; | 2647 | this->eccsteps = 1; |
2613 | break; | 2648 | break; |
2614 | } | 2649 | } |
2615 | 2650 | ||
2616 | /* Initialize state, waitqueue and spinlock */ | 2651 | /* Initialize state, waitqueue and spinlock */ |
2617 | this->state = FL_READY; | 2652 | this->state = FL_READY; |
2618 | init_waitqueue_head (&this->wq); | 2653 | init_waitqueue_head (&this->wq); |
@@ -2643,8 +2678,8 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2643 | mtd->sync = nand_sync; | 2678 | mtd->sync = nand_sync; |
2644 | mtd->lock = NULL; | 2679 | mtd->lock = NULL; |
2645 | mtd->unlock = NULL; | 2680 | mtd->unlock = NULL; |
2646 | mtd->suspend = NULL; | 2681 | mtd->suspend = nand_suspend; |
2647 | mtd->resume = NULL; | 2682 | mtd->resume = nand_resume; |
2648 | mtd->block_isbad = nand_block_isbad; | 2683 | mtd->block_isbad = nand_block_isbad; |
2649 | mtd->block_markbad = nand_block_markbad; | 2684 | mtd->block_markbad = nand_block_markbad; |
2650 | 2685 | ||
@@ -2652,7 +2687,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2652 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); | 2687 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); |
2653 | 2688 | ||
2654 | mtd->owner = THIS_MODULE; | 2689 | mtd->owner = THIS_MODULE; |
2655 | 2690 | ||
2656 | /* Check, if we should skip the bad block table scan */ | 2691 | /* Check, if we should skip the bad block table scan */ |
2657 | if (this->options & NAND_SKIP_BBTSCAN) | 2692 | if (this->options & NAND_SKIP_BBTSCAN) |
2658 | return 0; | 2693 | return 0; |
@@ -2662,7 +2697,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) | |||
2662 | } | 2697 | } |
2663 | 2698 | ||
2664 | /** | 2699 | /** |
2665 | * nand_release - [NAND Interface] Free resources held by the NAND device | 2700 | * nand_release - [NAND Interface] Free resources held by the NAND device |
2666 | * @mtd: MTD device structure | 2701 | * @mtd: MTD device structure |
2667 | */ | 2702 | */ |
2668 | void nand_release (struct mtd_info *mtd) | 2703 | void nand_release (struct mtd_info *mtd) |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 7535ef53685e..ca286999fe08 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -3,10 +3,10 @@ | |||
3 | * | 3 | * |
4 | * Overview: | 4 | * Overview: |
5 | * Bad block table support for the NAND driver | 5 | * Bad block table support for the NAND driver |
6 | * | 6 | * |
7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
8 | * | 8 | * |
9 | * $Id: nand_bbt.c,v 1.35 2005/07/15 13:53:47 gleixner Exp $ | 9 | * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -14,23 +14,23 @@ | |||
14 | * | 14 | * |
15 | * Description: | 15 | * Description: |
16 | * | 16 | * |
17 | * When nand_scan_bbt is called, then it tries to find the bad block table | 17 | * When nand_scan_bbt is called, then it tries to find the bad block table |
18 | * depending on the options in the bbt descriptor(s). If a bbt is found | 18 | * depending on the options in the bbt descriptor(s). If a bbt is found |
19 | * then the contents are read and the memory based bbt is created. If a | 19 | * then the contents are read and the memory based bbt is created. If a |
20 | * mirrored bbt is selected then the mirror is searched too and the | 20 | * mirrored bbt is selected then the mirror is searched too and the |
21 | * versions are compared. If the mirror has a greater version number | 21 | * versions are compared. If the mirror has a greater version number |
22 | * than the mirror bbt is used to build the memory based bbt. | 22 | * than the mirror bbt is used to build the memory based bbt. |
23 | * If the tables are not versioned, then we "or" the bad block information. | 23 | * If the tables are not versioned, then we "or" the bad block information. |
24 | * If one of the bbt's is out of date or does not exist it is (re)created. | 24 | * If one of the bbt's is out of date or does not exist it is (re)created. |
25 | * If no bbt exists at all then the device is scanned for factory marked | 25 | * If no bbt exists at all then the device is scanned for factory marked |
26 | * good / bad blocks and the bad block tables are created. | 26 | * good / bad blocks and the bad block tables are created. |
27 | * | 27 | * |
28 | * For manufacturer created bbts like the one found on M-SYS DOC devices | 28 | * For manufacturer created bbts like the one found on M-SYS DOC devices |
29 | * the bbt is searched and read but never created | 29 | * the bbt is searched and read but never created |
30 | * | 30 | * |
31 | * The autogenerated bad block table is located in the last good blocks | 31 | * The autogenerated bad block table is located in the last good blocks |
32 | * of the device. The table is mirrored, so it can be updated eventually. | 32 | * of the device. The table is mirrored, so it can be updated eventually. |
33 | * The table is marked in the oob area with an ident pattern and a version | 33 | * The table is marked in the oob area with an ident pattern and a version |
34 | * number which indicates which of both tables is more up to date. | 34 | * number which indicates which of both tables is more up to date. |
35 | * | 35 | * |
36 | * The table uses 2 bits per block | 36 | * The table uses 2 bits per block |
@@ -43,13 +43,13 @@ | |||
43 | * 01b: block is marked bad due to wear | 43 | * 01b: block is marked bad due to wear |
44 | * 10b: block is reserved (to protect the bbt area) | 44 | * 10b: block is reserved (to protect the bbt area) |
45 | * 11b: block is factory marked bad | 45 | * 11b: block is factory marked bad |
46 | * | 46 | * |
47 | * Multichip devices like DOC store the bad block info per floor. | 47 | * Multichip devices like DOC store the bad block info per floor. |
48 | * | 48 | * |
49 | * Following assumptions are made: | 49 | * Following assumptions are made: |
50 | * - bbts start at a page boundary, if autolocated on a block boundary | 50 | * - bbts start at a page boundary, if autolocated on a block boundary |
51 | * - the space neccecary for a bbt in FLASH does not exceed a block boundary | 51 | * - the space neccecary for a bbt in FLASH does not exceed a block boundary |
52 | * | 52 | * |
53 | */ | 53 | */ |
54 | 54 | ||
55 | #include <linux/slab.h> | 55 | #include <linux/slab.h> |
@@ -62,7 +62,7 @@ | |||
62 | #include <linux/delay.h> | 62 | #include <linux/delay.h> |
63 | 63 | ||
64 | 64 | ||
65 | /** | 65 | /** |
66 | * check_pattern - [GENERIC] check if a pattern is in the buffer | 66 | * check_pattern - [GENERIC] check if a pattern is in the buffer |
67 | * @buf: the buffer to search | 67 | * @buf: the buffer to search |
68 | * @len: the length of buffer to search | 68 | * @len: the length of buffer to search |
@@ -86,9 +86,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des | |||
86 | if (p[i] != 0xff) | 86 | if (p[i] != 0xff) |
87 | return -1; | 87 | return -1; |
88 | } | 88 | } |
89 | } | 89 | } |
90 | p += end; | 90 | p += end; |
91 | 91 | ||
92 | /* Compare the pattern */ | 92 | /* Compare the pattern */ |
93 | for (i = 0; i < td->len; i++) { | 93 | for (i = 0; i < td->len; i++) { |
94 | if (p[i] != td->pattern[i]) | 94 | if (p[i] != td->pattern[i]) |
@@ -106,13 +106,13 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des | |||
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
108 | 108 | ||
109 | /** | 109 | /** |
110 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer | 110 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer |
111 | * @buf: the buffer to search | 111 | * @buf: the buffer to search |
112 | * @td: search pattern descriptor | 112 | * @td: search pattern descriptor |
113 | * | 113 | * |
114 | * Check for a pattern at the given place. Used to search bad block | 114 | * Check for a pattern at the given place. Used to search bad block |
115 | * tables and good / bad block identifiers. Same as check_pattern, but | 115 | * tables and good / bad block identifiers. Same as check_pattern, but |
116 | * no optional empty check | 116 | * no optional empty check |
117 | * | 117 | * |
118 | */ | 118 | */ |
@@ -142,7 +142,7 @@ static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td) | |||
142 | * Read the bad block table starting from page. | 142 | * Read the bad block table starting from page. |
143 | * | 143 | * |
144 | */ | 144 | */ |
145 | static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | 145 | static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, |
146 | int bits, int offs, int reserved_block_code) | 146 | int bits, int offs, int reserved_block_code) |
147 | { | 147 | { |
148 | int res, i, j, act = 0; | 148 | int res, i, j, act = 0; |
@@ -153,7 +153,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
153 | 153 | ||
154 | totlen = (num * bits) >> 3; | 154 | totlen = (num * bits) >> 3; |
155 | from = ((loff_t)page) << this->page_shift; | 155 | from = ((loff_t)page) << this->page_shift; |
156 | 156 | ||
157 | while (totlen) { | 157 | while (totlen) { |
158 | len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); | 158 | len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); |
159 | res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); | 159 | res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); |
@@ -163,7 +163,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
163 | return res; | 163 | return res; |
164 | } | 164 | } |
165 | printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); | 165 | printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); |
166 | } | 166 | } |
167 | 167 | ||
168 | /* Analyse data */ | 168 | /* Analyse data */ |
169 | for (i = 0; i < len; i++) { | 169 | for (i = 0; i < len; i++) { |
@@ -183,12 +183,12 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
183 | * message to MTD_DEBUG_LEVEL0 */ | 183 | * message to MTD_DEBUG_LEVEL0 */ |
184 | printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", | 184 | printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", |
185 | ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); | 185 | ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); |
186 | /* Factory marked bad or worn out ? */ | 186 | /* Factory marked bad or worn out ? */ |
187 | if (tmp == 0) | 187 | if (tmp == 0) |
188 | this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); | 188 | this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); |
189 | else | 189 | else |
190 | this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); | 190 | this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); |
191 | } | 191 | } |
192 | } | 192 | } |
193 | totlen -= len; | 193 | totlen -= len; |
194 | from += len; | 194 | from += len; |
@@ -200,7 +200,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
200 | * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page | 200 | * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page |
201 | * @mtd: MTD device structure | 201 | * @mtd: MTD device structure |
202 | * @buf: temporary buffer | 202 | * @buf: temporary buffer |
203 | * @td: descriptor for the bad block table | 203 | * @td: descriptor for the bad block table |
204 | * @chip: read the table for a specific chip, -1 read all chips. | 204 | * @chip: read the table for a specific chip, -1 read all chips. |
205 | * Applies only if NAND_BBT_PERCHIP option is set | 205 | * Applies only if NAND_BBT_PERCHIP option is set |
206 | * | 206 | * |
@@ -235,7 +235,7 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
235 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page | 235 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page |
236 | * @mtd: MTD device structure | 236 | * @mtd: MTD device structure |
237 | * @buf: temporary buffer | 237 | * @buf: temporary buffer |
238 | * @td: descriptor for the bad block table | 238 | * @td: descriptor for the bad block table |
239 | * @md: descriptor for the bad block table mirror | 239 | * @md: descriptor for the bad block table mirror |
240 | * | 240 | * |
241 | * Read the bad block table(s) for all chips starting at a given page | 241 | * Read the bad block table(s) for all chips starting at a given page |
@@ -247,16 +247,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de | |||
247 | { | 247 | { |
248 | struct nand_chip *this = mtd->priv; | 248 | struct nand_chip *this = mtd->priv; |
249 | 249 | ||
250 | /* Read the primary version, if available */ | 250 | /* Read the primary version, if available */ |
251 | if (td->options & NAND_BBT_VERSION) { | 251 | if (td->options & NAND_BBT_VERSION) { |
252 | nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); | 252 | nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); |
253 | td->version[0] = buf[mtd->oobblock + td->veroffs]; | 253 | td->version[0] = buf[mtd->oobblock + td->veroffs]; |
254 | printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); | 254 | printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); |
255 | } | 255 | } |
256 | 256 | ||
257 | /* Read the mirror version, if available */ | 257 | /* Read the mirror version, if available */ |
258 | if (md && (md->options & NAND_BBT_VERSION)) { | 258 | if (md && (md->options & NAND_BBT_VERSION)) { |
259 | nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); | 259 | nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); |
260 | md->version[0] = buf[mtd->oobblock + md->veroffs]; | 260 | md->version[0] = buf[mtd->oobblock + md->veroffs]; |
261 | printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); | 261 | printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); |
262 | } | 262 | } |
@@ -290,7 +290,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
290 | else { | 290 | else { |
291 | if (bd->options & NAND_BBT_SCAN2NDPAGE) | 291 | if (bd->options & NAND_BBT_SCAN2NDPAGE) |
292 | len = 2; | 292 | len = 2; |
293 | else | 293 | else |
294 | len = 1; | 294 | len = 1; |
295 | } | 295 | } |
296 | 296 | ||
@@ -322,10 +322,10 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
322 | numblocks += startblock; | 322 | numblocks += startblock; |
323 | from = startblock << (this->bbt_erase_shift - 1); | 323 | from = startblock << (this->bbt_erase_shift - 1); |
324 | } | 324 | } |
325 | 325 | ||
326 | for (i = startblock; i < numblocks;) { | 326 | for (i = startblock; i < numblocks;) { |
327 | int ret; | 327 | int ret; |
328 | 328 | ||
329 | if (bd->options & NAND_BBT_SCANEMPTY) | 329 | if (bd->options & NAND_BBT_SCANEMPTY) |
330 | if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) | 330 | if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) |
331 | return ret; | 331 | return ret; |
@@ -333,8 +333,8 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
333 | for (j = 0; j < len; j++) { | 333 | for (j = 0; j < len; j++) { |
334 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { | 334 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
335 | size_t retlen; | 335 | size_t retlen; |
336 | 336 | ||
337 | /* Read the full oob until read_oob is fixed to | 337 | /* Read the full oob until read_oob is fixed to |
338 | * handle single byte reads for 16 bit buswidth */ | 338 | * handle single byte reads for 16 bit buswidth */ |
339 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock, | 339 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock, |
340 | mtd->oobsize, &retlen, buf); | 340 | mtd->oobsize, &retlen, buf); |
@@ -343,14 +343,14 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
343 | 343 | ||
344 | if (check_short_pattern (buf, bd)) { | 344 | if (check_short_pattern (buf, bd)) { |
345 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 345 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
346 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 346 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
347 | i >> 1, (unsigned int) from); | 347 | i >> 1, (unsigned int) from); |
348 | break; | 348 | break; |
349 | } | 349 | } |
350 | } else { | 350 | } else { |
351 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | 351 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { |
352 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 352 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
353 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 353 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
354 | i >> 1, (unsigned int) from); | 354 | i >> 1, (unsigned int) from); |
355 | break; | 355 | break; |
356 | } | 356 | } |
@@ -369,15 +369,15 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
369 | * @td: descriptor for the bad block table | 369 | * @td: descriptor for the bad block table |
370 | * | 370 | * |
371 | * Read the bad block table by searching for a given ident pattern. | 371 | * Read the bad block table by searching for a given ident pattern. |
372 | * Search is preformed either from the beginning up or from the end of | 372 | * Search is preformed either from the beginning up or from the end of |
373 | * the device downwards. The search starts always at the start of a | 373 | * the device downwards. The search starts always at the start of a |
374 | * block. | 374 | * block. |
375 | * If the option NAND_BBT_PERCHIP is given, each chip is searched | 375 | * If the option NAND_BBT_PERCHIP is given, each chip is searched |
376 | * for a bbt, which contains the bad block information of this chip. | 376 | * for a bbt, which contains the bad block information of this chip. |
377 | * This is neccecary to provide support for certain DOC devices. | 377 | * This is neccecary to provide support for certain DOC devices. |
378 | * | 378 | * |
379 | * The bbt ident pattern resides in the oob area of the first page | 379 | * The bbt ident pattern resides in the oob area of the first page |
380 | * in a block. | 380 | * in a block. |
381 | */ | 381 | */ |
382 | static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) | 382 | static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) |
383 | { | 383 | { |
@@ -392,10 +392,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
392 | startblock = (mtd->size >> this->bbt_erase_shift) -1; | 392 | startblock = (mtd->size >> this->bbt_erase_shift) -1; |
393 | dir = -1; | 393 | dir = -1; |
394 | } else { | 394 | } else { |
395 | startblock = 0; | 395 | startblock = 0; |
396 | dir = 1; | 396 | dir = 1; |
397 | } | 397 | } |
398 | 398 | ||
399 | /* Do we have a bbt per chip ? */ | 399 | /* Do we have a bbt per chip ? */ |
400 | if (td->options & NAND_BBT_PERCHIP) { | 400 | if (td->options & NAND_BBT_PERCHIP) { |
401 | chips = this->numchips; | 401 | chips = this->numchips; |
@@ -405,19 +405,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
405 | chips = 1; | 405 | chips = 1; |
406 | bbtblocks = mtd->size >> this->bbt_erase_shift; | 406 | bbtblocks = mtd->size >> this->bbt_erase_shift; |
407 | } | 407 | } |
408 | 408 | ||
409 | /* Number of bits for each erase block in the bbt */ | 409 | /* Number of bits for each erase block in the bbt */ |
410 | bits = td->options & NAND_BBT_NRBITS_MSK; | 410 | bits = td->options & NAND_BBT_NRBITS_MSK; |
411 | 411 | ||
412 | for (i = 0; i < chips; i++) { | 412 | for (i = 0; i < chips; i++) { |
413 | /* Reset version information */ | 413 | /* Reset version information */ |
414 | td->version[i] = 0; | 414 | td->version[i] = 0; |
415 | td->pages[i] = -1; | 415 | td->pages[i] = -1; |
416 | /* Scan the maximum number of blocks */ | 416 | /* Scan the maximum number of blocks */ |
417 | for (block = 0; block < td->maxblocks; block++) { | 417 | for (block = 0; block < td->maxblocks; block++) { |
418 | int actblock = startblock + dir * block; | 418 | int actblock = startblock + dir * block; |
419 | /* Read first page */ | 419 | /* Read first page */ |
420 | nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); | 420 | nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); |
421 | if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { | 421 | if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { |
422 | td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); | 422 | td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); |
423 | if (td->options & NAND_BBT_VERSION) { | 423 | if (td->options & NAND_BBT_VERSION) { |
@@ -435,46 +435,46 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
435 | else | 435 | else |
436 | printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); | 436 | printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); |
437 | } | 437 | } |
438 | return 0; | 438 | return 0; |
439 | } | 439 | } |
440 | 440 | ||
441 | /** | 441 | /** |
442 | * search_read_bbts - [GENERIC] scan the device for bad block table(s) | 442 | * search_read_bbts - [GENERIC] scan the device for bad block table(s) |
443 | * @mtd: MTD device structure | 443 | * @mtd: MTD device structure |
444 | * @buf: temporary buffer | 444 | * @buf: temporary buffer |
445 | * @td: descriptor for the bad block table | 445 | * @td: descriptor for the bad block table |
446 | * @md: descriptor for the bad block table mirror | 446 | * @md: descriptor for the bad block table mirror |
447 | * | 447 | * |
448 | * Search and read the bad block table(s) | 448 | * Search and read the bad block table(s) |
449 | */ | 449 | */ |
450 | static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, | 450 | static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, |
451 | struct nand_bbt_descr *td, struct nand_bbt_descr *md) | 451 | struct nand_bbt_descr *td, struct nand_bbt_descr *md) |
452 | { | 452 | { |
453 | /* Search the primary table */ | 453 | /* Search the primary table */ |
454 | search_bbt (mtd, buf, td); | 454 | search_bbt (mtd, buf, td); |
455 | 455 | ||
456 | /* Search the mirror table */ | 456 | /* Search the mirror table */ |
457 | if (md) | 457 | if (md) |
458 | search_bbt (mtd, buf, md); | 458 | search_bbt (mtd, buf, md); |
459 | 459 | ||
460 | /* Force result check */ | 460 | /* Force result check */ |
461 | return 1; | 461 | return 1; |
462 | } | 462 | } |
463 | |||
464 | 463 | ||
465 | /** | 464 | |
465 | /** | ||
466 | * write_bbt - [GENERIC] (Re)write the bad block table | 466 | * write_bbt - [GENERIC] (Re)write the bad block table |
467 | * | 467 | * |
468 | * @mtd: MTD device structure | 468 | * @mtd: MTD device structure |
469 | * @buf: temporary buffer | 469 | * @buf: temporary buffer |
470 | * @td: descriptor for the bad block table | 470 | * @td: descriptor for the bad block table |
471 | * @md: descriptor for the bad block table mirror | 471 | * @md: descriptor for the bad block table mirror |
472 | * @chipsel: selector for a specific chip, -1 for all | 472 | * @chipsel: selector for a specific chip, -1 for all |
473 | * | 473 | * |
474 | * (Re)write the bad block table | 474 | * (Re)write the bad block table |
475 | * | 475 | * |
476 | */ | 476 | */ |
477 | static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | 477 | static int write_bbt (struct mtd_info *mtd, uint8_t *buf, |
478 | struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) | 478 | struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) |
479 | { | 479 | { |
480 | struct nand_chip *this = mtd->priv; | 480 | struct nand_chip *this = mtd->priv; |
@@ -493,7 +493,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | |||
493 | /* Write bad block table per chip rather than per device ? */ | 493 | /* Write bad block table per chip rather than per device ? */ |
494 | if (td->options & NAND_BBT_PERCHIP) { | 494 | if (td->options & NAND_BBT_PERCHIP) { |
495 | numblocks = (int) (this->chipsize >> this->bbt_erase_shift); | 495 | numblocks = (int) (this->chipsize >> this->bbt_erase_shift); |
496 | /* Full device write or specific chip ? */ | 496 | /* Full device write or specific chip ? */ |
497 | if (chipsel == -1) { | 497 | if (chipsel == -1) { |
498 | nrchips = this->numchips; | 498 | nrchips = this->numchips; |
499 | } else { | 499 | } else { |
@@ -503,19 +503,19 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | |||
503 | } else { | 503 | } else { |
504 | numblocks = (int) (mtd->size >> this->bbt_erase_shift); | 504 | numblocks = (int) (mtd->size >> this->bbt_erase_shift); |
505 | nrchips = 1; | 505 | nrchips = 1; |
506 | } | 506 | } |
507 | 507 | ||
508 | /* Loop through the chips */ | 508 | /* Loop through the chips */ |
509 | for (; chip < nrchips; chip++) { | 509 | for (; chip < nrchips; chip++) { |
510 | 510 | ||
511 | /* There was already a version of the table, reuse the page | 511 | /* There was already a version of the table, reuse the page |
512 | * This applies for absolute placement too, as we have the | 512 | * This applies for absolute placement too, as we have the |
513 | * page nr. in td->pages. | 513 | * page nr. in td->pages. |
514 | */ | 514 | */ |
515 | if (td->pages[chip] != -1) { | 515 | if (td->pages[chip] != -1) { |
516 | page = td->pages[chip]; | 516 | page = td->pages[chip]; |
517 | goto write; | 517 | goto write; |
518 | } | 518 | } |
519 | 519 | ||
520 | /* Automatic placement of the bad block table */ | 520 | /* Automatic placement of the bad block table */ |
521 | /* Search direction top -> down ? */ | 521 | /* Search direction top -> down ? */ |
@@ -525,7 +525,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | |||
525 | } else { | 525 | } else { |
526 | startblock = chip * numblocks; | 526 | startblock = chip * numblocks; |
527 | dir = 1; | 527 | dir = 1; |
528 | } | 528 | } |
529 | 529 | ||
530 | for (i = 0; i < td->maxblocks; i++) { | 530 | for (i = 0; i < td->maxblocks; i++) { |
531 | int block = startblock + dir * i; | 531 | int block = startblock + dir * i; |
@@ -542,7 +542,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, | |||
542 | } | 542 | } |
543 | printk (KERN_ERR "No space left to write bad block table\n"); | 543 | printk (KERN_ERR "No space left to write bad block table\n"); |
544 | return -ENOSPC; | 544 | return -ENOSPC; |
545 | write: | 545 | write: |
546 | 546 | ||
547 | /* Set up shift count and masks for the flash table */ | 547 | /* Set up shift count and masks for the flash table */ |
548 | bits = td->options & NAND_BBT_NRBITS_MSK; | 548 | bits = td->options & NAND_BBT_NRBITS_MSK; |
@@ -553,14 +553,14 @@ write: | |||
553 | case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; | 553 | case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; |
554 | default: return -EINVAL; | 554 | default: return -EINVAL; |
555 | } | 555 | } |
556 | 556 | ||
557 | bbtoffs = chip * (numblocks >> 2); | 557 | bbtoffs = chip * (numblocks >> 2); |
558 | 558 | ||
559 | to = ((loff_t) page) << this->page_shift; | 559 | to = ((loff_t) page) << this->page_shift; |
560 | 560 | ||
561 | memcpy (&oobinfo, this->autooob, sizeof(oobinfo)); | 561 | memcpy (&oobinfo, this->autooob, sizeof(oobinfo)); |
562 | oobinfo.useecc = MTD_NANDECC_PLACEONLY; | 562 | oobinfo.useecc = MTD_NANDECC_PLACEONLY; |
563 | 563 | ||
564 | /* Must we save the block contents ? */ | 564 | /* Must we save the block contents ? */ |
565 | if (td->options & NAND_BBT_SAVECONTENT) { | 565 | if (td->options & NAND_BBT_SAVECONTENT) { |
566 | /* Make it block aligned */ | 566 | /* Make it block aligned */ |
@@ -599,7 +599,7 @@ write: | |||
599 | buf[len + td->veroffs] = td->version[chip]; | 599 | buf[len + td->veroffs] = td->version[chip]; |
600 | } | 600 | } |
601 | } | 601 | } |
602 | 602 | ||
603 | /* walk through the memory table */ | 603 | /* walk through the memory table */ |
604 | for (i = 0; i < numblocks; ) { | 604 | for (i = 0; i < numblocks; ) { |
605 | uint8_t dat; | 605 | uint8_t dat; |
@@ -611,7 +611,7 @@ write: | |||
611 | dat >>= 2; | 611 | dat >>= 2; |
612 | } | 612 | } |
613 | } | 613 | } |
614 | 614 | ||
615 | memset (&einfo, 0, sizeof (einfo)); | 615 | memset (&einfo, 0, sizeof (einfo)); |
616 | einfo.mtd = mtd; | 616 | einfo.mtd = mtd; |
617 | einfo.addr = (unsigned long) to; | 617 | einfo.addr = (unsigned long) to; |
@@ -621,18 +621,18 @@ write: | |||
621 | printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); | 621 | printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); |
622 | return res; | 622 | return res; |
623 | } | 623 | } |
624 | 624 | ||
625 | res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); | 625 | res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); |
626 | if (res < 0) { | 626 | if (res < 0) { |
627 | printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); | 627 | printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); |
628 | return res; | 628 | return res; |
629 | } | 629 | } |
630 | printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", | 630 | printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", |
631 | (unsigned int) to, td->version[chip]); | 631 | (unsigned int) to, td->version[chip]); |
632 | 632 | ||
633 | /* Mark it as used */ | 633 | /* Mark it as used */ |
634 | td->pages[chip] = page; | 634 | td->pages[chip] = page; |
635 | } | 635 | } |
636 | return 0; | 636 | return 0; |
637 | } | 637 | } |
638 | 638 | ||
@@ -641,7 +641,7 @@ write: | |||
641 | * @mtd: MTD device structure | 641 | * @mtd: MTD device structure |
642 | * @bd: descriptor for the good/bad block search pattern | 642 | * @bd: descriptor for the good/bad block search pattern |
643 | * | 643 | * |
644 | * The function creates a memory based bbt by scanning the device | 644 | * The function creates a memory based bbt by scanning the device |
645 | * for manufacturer / software marked good / bad blocks | 645 | * for manufacturer / software marked good / bad blocks |
646 | */ | 646 | */ |
647 | static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | 647 | static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) |
@@ -673,11 +673,11 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
673 | struct nand_bbt_descr *rd, *rd2; | 673 | struct nand_bbt_descr *rd, *rd2; |
674 | 674 | ||
675 | /* Do we have a bbt per chip ? */ | 675 | /* Do we have a bbt per chip ? */ |
676 | if (td->options & NAND_BBT_PERCHIP) | 676 | if (td->options & NAND_BBT_PERCHIP) |
677 | chips = this->numchips; | 677 | chips = this->numchips; |
678 | else | 678 | else |
679 | chips = 1; | 679 | chips = 1; |
680 | 680 | ||
681 | for (i = 0; i < chips; i++) { | 681 | for (i = 0; i < chips; i++) { |
682 | writeops = 0; | 682 | writeops = 0; |
683 | rd = NULL; | 683 | rd = NULL; |
@@ -692,7 +692,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
692 | } | 692 | } |
693 | 693 | ||
694 | if (td->pages[i] == -1) { | 694 | if (td->pages[i] == -1) { |
695 | rd = md; | 695 | rd = md; |
696 | td->version[i] = md->version[i]; | 696 | td->version[i] = md->version[i]; |
697 | writeops = 1; | 697 | writeops = 1; |
698 | goto writecheck; | 698 | goto writecheck; |
@@ -710,7 +710,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
710 | if (!(td->options & NAND_BBT_VERSION)) | 710 | if (!(td->options & NAND_BBT_VERSION)) |
711 | rd2 = md; | 711 | rd2 = md; |
712 | goto writecheck; | 712 | goto writecheck; |
713 | } | 713 | } |
714 | 714 | ||
715 | if (((int8_t) (td->version[i] - md->version[i])) > 0) { | 715 | if (((int8_t) (td->version[i] - md->version[i])) > 0) { |
716 | rd = td; | 716 | rd = td; |
@@ -735,15 +735,15 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
735 | create: | 735 | create: |
736 | /* Create the bad block table by scanning the device ? */ | 736 | /* Create the bad block table by scanning the device ? */ |
737 | if (!(td->options & NAND_BBT_CREATE)) | 737 | if (!(td->options & NAND_BBT_CREATE)) |
738 | continue; | 738 | continue; |
739 | 739 | ||
740 | /* Create the table in memory by scanning the chip(s) */ | 740 | /* Create the table in memory by scanning the chip(s) */ |
741 | create_bbt (mtd, buf, bd, chipsel); | 741 | create_bbt (mtd, buf, bd, chipsel); |
742 | 742 | ||
743 | td->version[i] = 1; | 743 | td->version[i] = 1; |
744 | if (md) | 744 | if (md) |
745 | md->version[i] = 1; | 745 | md->version[i] = 1; |
746 | writecheck: | 746 | writecheck: |
747 | /* read back first ? */ | 747 | /* read back first ? */ |
748 | if (rd) | 748 | if (rd) |
749 | read_abs_bbt (mtd, buf, rd, chipsel); | 749 | read_abs_bbt (mtd, buf, rd, chipsel); |
@@ -757,7 +757,7 @@ writecheck: | |||
757 | if (res < 0) | 757 | if (res < 0) |
758 | return res; | 758 | return res; |
759 | } | 759 | } |
760 | 760 | ||
761 | /* Write the mirror bad block table to the device ? */ | 761 | /* Write the mirror bad block table to the device ? */ |
762 | if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { | 762 | if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { |
763 | res = write_bbt (mtd, buf, md, td, chipsel); | 763 | res = write_bbt (mtd, buf, md, td, chipsel); |
@@ -765,11 +765,11 @@ writecheck: | |||
765 | return res; | 765 | return res; |
766 | } | 766 | } |
767 | } | 767 | } |
768 | return 0; | 768 | return 0; |
769 | } | 769 | } |
770 | 770 | ||
771 | /** | 771 | /** |
772 | * mark_bbt_regions - [GENERIC] mark the bad block table regions | 772 | * mark_bbt_regions - [GENERIC] mark the bad block table regions |
773 | * @mtd: MTD device structure | 773 | * @mtd: MTD device structure |
774 | * @td: bad block table descriptor | 774 | * @td: bad block table descriptor |
775 | * | 775 | * |
@@ -790,14 +790,14 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
790 | } else { | 790 | } else { |
791 | chips = 1; | 791 | chips = 1; |
792 | nrblocks = (int)(mtd->size >> this->bbt_erase_shift); | 792 | nrblocks = (int)(mtd->size >> this->bbt_erase_shift); |
793 | } | 793 | } |
794 | 794 | ||
795 | for (i = 0; i < chips; i++) { | 795 | for (i = 0; i < chips; i++) { |
796 | if ((td->options & NAND_BBT_ABSPAGE) || | 796 | if ((td->options & NAND_BBT_ABSPAGE) || |
797 | !(td->options & NAND_BBT_WRITE)) { | 797 | !(td->options & NAND_BBT_WRITE)) { |
798 | if (td->pages[i] == -1) continue; | 798 | if (td->pages[i] == -1) continue; |
799 | block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); | 799 | block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); |
800 | block <<= 1; | 800 | block <<= 1; |
801 | oldval = this->bbt[(block >> 3)]; | 801 | oldval = this->bbt[(block >> 3)]; |
802 | newval = oldval | (0x2 << (block & 0x06)); | 802 | newval = oldval | (0x2 << (block & 0x06)); |
803 | this->bbt[(block >> 3)] = newval; | 803 | this->bbt[(block >> 3)] = newval; |
@@ -808,16 +808,16 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
808 | update = 0; | 808 | update = 0; |
809 | if (td->options & NAND_BBT_LASTBLOCK) | 809 | if (td->options & NAND_BBT_LASTBLOCK) |
810 | block = ((i + 1) * nrblocks) - td->maxblocks; | 810 | block = ((i + 1) * nrblocks) - td->maxblocks; |
811 | else | 811 | else |
812 | block = i * nrblocks; | 812 | block = i * nrblocks; |
813 | block <<= 1; | 813 | block <<= 1; |
814 | for (j = 0; j < td->maxblocks; j++) { | 814 | for (j = 0; j < td->maxblocks; j++) { |
815 | oldval = this->bbt[(block >> 3)]; | 815 | oldval = this->bbt[(block >> 3)]; |
816 | newval = oldval | (0x2 << (block & 0x06)); | 816 | newval = oldval | (0x2 << (block & 0x06)); |
817 | this->bbt[(block >> 3)] = newval; | 817 | this->bbt[(block >> 3)] = newval; |
818 | if (oldval != newval) update = 1; | 818 | if (oldval != newval) update = 1; |
819 | block += 2; | 819 | block += 2; |
820 | } | 820 | } |
821 | /* If we want reserved blocks to be recorded to flash, and some | 821 | /* If we want reserved blocks to be recorded to flash, and some |
822 | new ones have been marked, then we need to update the stored | 822 | new ones have been marked, then we need to update the stored |
823 | bbts. This should only happen once. */ | 823 | bbts. This should only happen once. */ |
@@ -831,7 +831,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
831 | * @mtd: MTD device structure | 831 | * @mtd: MTD device structure |
832 | * @bd: descriptor for the good/bad block search pattern | 832 | * @bd: descriptor for the good/bad block search pattern |
833 | * | 833 | * |
834 | * The function checks, if a bad block table(s) is/are already | 834 | * The function checks, if a bad block table(s) is/are already |
835 | * available. If not it scans the device for manufacturer | 835 | * available. If not it scans the device for manufacturer |
836 | * marked good / bad blocks and writes the bad block table(s) to | 836 | * marked good / bad blocks and writes the bad block table(s) to |
837 | * the selected place. | 837 | * the selected place. |
@@ -880,30 +880,30 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | |||
880 | this->bbt = NULL; | 880 | this->bbt = NULL; |
881 | return -ENOMEM; | 881 | return -ENOMEM; |
882 | } | 882 | } |
883 | 883 | ||
884 | /* Is the bbt at a given page ? */ | 884 | /* Is the bbt at a given page ? */ |
885 | if (td->options & NAND_BBT_ABSPAGE) { | 885 | if (td->options & NAND_BBT_ABSPAGE) { |
886 | res = read_abs_bbts (mtd, buf, td, md); | 886 | res = read_abs_bbts (mtd, buf, td, md); |
887 | } else { | 887 | } else { |
888 | /* Search the bad block table using a pattern in oob */ | 888 | /* Search the bad block table using a pattern in oob */ |
889 | res = search_read_bbts (mtd, buf, td, md); | 889 | res = search_read_bbts (mtd, buf, td, md); |
890 | } | 890 | } |
891 | 891 | ||
892 | if (res) | 892 | if (res) |
893 | res = check_create (mtd, buf, bd); | 893 | res = check_create (mtd, buf, bd); |
894 | 894 | ||
895 | /* Prevent the bbt regions from erasing / writing */ | 895 | /* Prevent the bbt regions from erasing / writing */ |
896 | mark_bbt_region (mtd, td); | 896 | mark_bbt_region (mtd, td); |
897 | if (md) | 897 | if (md) |
898 | mark_bbt_region (mtd, md); | 898 | mark_bbt_region (mtd, md); |
899 | 899 | ||
900 | kfree (buf); | 900 | kfree (buf); |
901 | return res; | 901 | return res; |
902 | } | 902 | } |
903 | 903 | ||
904 | 904 | ||
905 | /** | 905 | /** |
906 | * nand_update_bbt - [NAND Interface] update bad block table(s) | 906 | * nand_update_bbt - [NAND Interface] update bad block table(s) |
907 | * @mtd: MTD device structure | 907 | * @mtd: MTD device structure |
908 | * @offs: the offset of the newly marked block | 908 | * @offs: the offset of the newly marked block |
909 | * | 909 | * |
@@ -930,7 +930,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) | |||
930 | printk (KERN_ERR "nand_update_bbt: Out of memory\n"); | 930 | printk (KERN_ERR "nand_update_bbt: Out of memory\n"); |
931 | return -ENOMEM; | 931 | return -ENOMEM; |
932 | } | 932 | } |
933 | 933 | ||
934 | writeops = md != NULL ? 0x03 : 0x01; | 934 | writeops = md != NULL ? 0x03 : 0x01; |
935 | 935 | ||
936 | /* Do we have a bbt per chip ? */ | 936 | /* Do we have a bbt per chip ? */ |
@@ -944,7 +944,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) | |||
944 | 944 | ||
945 | td->version[chip]++; | 945 | td->version[chip]++; |
946 | if (md) | 946 | if (md) |
947 | md->version[chip]++; | 947 | md->version[chip]++; |
948 | 948 | ||
949 | /* Write the bad block table to the device ? */ | 949 | /* Write the bad block table to the device ? */ |
950 | if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { | 950 | if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { |
@@ -957,12 +957,12 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) | |||
957 | res = write_bbt (mtd, buf, md, td, chipsel); | 957 | res = write_bbt (mtd, buf, md, td, chipsel); |
958 | } | 958 | } |
959 | 959 | ||
960 | out: | 960 | out: |
961 | kfree (buf); | 961 | kfree (buf); |
962 | return res; | 962 | return res; |
963 | } | 963 | } |
964 | 964 | ||
965 | /* Define some generic bad / good block scan pattern which are used | 965 | /* Define some generic bad / good block scan pattern which are used |
966 | * while scanning a device for factory marked good / bad blocks. */ | 966 | * while scanning a device for factory marked good / bad blocks. */ |
967 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 967 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
968 | 968 | ||
@@ -1009,7 +1009,7 @@ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; | |||
1009 | static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; | 1009 | static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; |
1010 | 1010 | ||
1011 | static struct nand_bbt_descr bbt_main_descr = { | 1011 | static struct nand_bbt_descr bbt_main_descr = { |
1012 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | 1012 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
1013 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | 1013 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, |
1014 | .offs = 8, | 1014 | .offs = 8, |
1015 | .len = 4, | 1015 | .len = 4, |
@@ -1019,7 +1019,7 @@ static struct nand_bbt_descr bbt_main_descr = { | |||
1019 | }; | 1019 | }; |
1020 | 1020 | ||
1021 | static struct nand_bbt_descr bbt_mirror_descr = { | 1021 | static struct nand_bbt_descr bbt_mirror_descr = { |
1022 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | 1022 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
1023 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, | 1023 | | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, |
1024 | .offs = 8, | 1024 | .offs = 8, |
1025 | .len = 4, | 1025 | .len = 4, |
@@ -1029,7 +1029,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
1029 | }; | 1029 | }; |
1030 | 1030 | ||
1031 | /** | 1031 | /** |
1032 | * nand_default_bbt - [NAND Interface] Select a default bad block table for the device | 1032 | * nand_default_bbt - [NAND Interface] Select a default bad block table for the device |
1033 | * @mtd: MTD device structure | 1033 | * @mtd: MTD device structure |
1034 | * | 1034 | * |
1035 | * This function selects the default bad block table | 1035 | * This function selects the default bad block table |
@@ -1039,29 +1039,29 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
1039 | int nand_default_bbt (struct mtd_info *mtd) | 1039 | int nand_default_bbt (struct mtd_info *mtd) |
1040 | { | 1040 | { |
1041 | struct nand_chip *this = mtd->priv; | 1041 | struct nand_chip *this = mtd->priv; |
1042 | 1042 | ||
1043 | /* Default for AG-AND. We must use a flash based | 1043 | /* Default for AG-AND. We must use a flash based |
1044 | * bad block table as the devices have factory marked | 1044 | * bad block table as the devices have factory marked |
1045 | * _good_ blocks. Erasing those blocks leads to loss | 1045 | * _good_ blocks. Erasing those blocks leads to loss |
1046 | * of the good / bad information, so we _must_ store | 1046 | * of the good / bad information, so we _must_ store |
1047 | * this information in a good / bad table during | 1047 | * this information in a good / bad table during |
1048 | * startup | 1048 | * startup |
1049 | */ | 1049 | */ |
1050 | if (this->options & NAND_IS_AND) { | 1050 | if (this->options & NAND_IS_AND) { |
1051 | /* Use the default pattern descriptors */ | 1051 | /* Use the default pattern descriptors */ |
1052 | if (!this->bbt_td) { | 1052 | if (!this->bbt_td) { |
1053 | this->bbt_td = &bbt_main_descr; | 1053 | this->bbt_td = &bbt_main_descr; |
1054 | this->bbt_md = &bbt_mirror_descr; | 1054 | this->bbt_md = &bbt_mirror_descr; |
1055 | } | 1055 | } |
1056 | this->options |= NAND_USE_FLASH_BBT; | 1056 | this->options |= NAND_USE_FLASH_BBT; |
1057 | return nand_scan_bbt (mtd, &agand_flashbased); | 1057 | return nand_scan_bbt (mtd, &agand_flashbased); |
1058 | } | 1058 | } |
1059 | 1059 | ||
1060 | 1060 | ||
1061 | /* Is a flash based bad block table requested ? */ | 1061 | /* Is a flash based bad block table requested ? */ |
1062 | if (this->options & NAND_USE_FLASH_BBT) { | 1062 | if (this->options & NAND_USE_FLASH_BBT) { |
1063 | /* Use the default pattern descriptors */ | 1063 | /* Use the default pattern descriptors */ |
1064 | if (!this->bbt_td) { | 1064 | if (!this->bbt_td) { |
1065 | this->bbt_td = &bbt_main_descr; | 1065 | this->bbt_td = &bbt_main_descr; |
1066 | this->bbt_md = &bbt_mirror_descr; | 1066 | this->bbt_md = &bbt_mirror_descr; |
1067 | } | 1067 | } |
@@ -1081,7 +1081,7 @@ int nand_default_bbt (struct mtd_info *mtd) | |||
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | /** | 1083 | /** |
1084 | * nand_isbad_bbt - [NAND Interface] Check if a block is bad | 1084 | * nand_isbad_bbt - [NAND Interface] Check if a block is bad |
1085 | * @mtd: MTD device structure | 1085 | * @mtd: MTD device structure |
1086 | * @offs: offset in the device | 1086 | * @offs: offset in the device |
1087 | * @allowbbt: allow access to bad block table region | 1087 | * @allowbbt: allow access to bad block table region |
@@ -1092,12 +1092,12 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) | |||
1092 | struct nand_chip *this = mtd->priv; | 1092 | struct nand_chip *this = mtd->priv; |
1093 | int block; | 1093 | int block; |
1094 | uint8_t res; | 1094 | uint8_t res; |
1095 | 1095 | ||
1096 | /* Get block number * 2 */ | 1096 | /* Get block number * 2 */ |
1097 | block = (int) (offs >> (this->bbt_erase_shift - 1)); | 1097 | block = (int) (offs >> (this->bbt_erase_shift - 1)); |
1098 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; | 1098 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; |
1099 | 1099 | ||
1100 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", | 1100 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", |
1101 | (unsigned int)offs, block >> 1, res); | 1101 | (unsigned int)offs, block >> 1, res); |
1102 | 1102 | ||
1103 | switch ((int)res) { | 1103 | switch ((int)res) { |
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 2e341b75437a..40ac909150a3 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c | |||
@@ -7,22 +7,22 @@ | |||
7 | * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * Toshiba America Electronics Components, Inc. | 8 | * Toshiba America Electronics Components, Inc. |
9 | * | 9 | * |
10 | * $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $ | 10 | * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ |
11 | * | 11 | * |
12 | * This file is free software; you can redistribute it and/or modify it | 12 | * This file is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
14 | * Free Software Foundation; either version 2 or (at your option) any | 14 | * Free Software Foundation; either version 2 or (at your option) any |
15 | * later version. | 15 | * later version. |
16 | * | 16 | * |
17 | * This file is distributed in the hope that it will be useful, but WITHOUT | 17 | * This file is distributed in the hope that it will be useful, but WITHOUT |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | 19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
20 | * for more details. | 20 | * for more details. |
21 | * | 21 | * |
22 | * You should have received a copy of the GNU General Public License along | 22 | * You should have received a copy of the GNU General Public License along |
23 | * with this file; if not, write to the Free Software Foundation, Inc., | 23 | * with this file; if not, write to the Free Software Foundation, Inc., |
24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
25 | * | 25 | * |
26 | * As a special exception, if other files instantiate templates or use | 26 | * As a special exception, if other files instantiate templates or use |
27 | * macros or inline functions from these files, or you compile these | 27 | * macros or inline functions from these files, or you compile these |
28 | * files and link them with other works to produce a work based on these | 28 | * files and link them with other works to produce a work based on these |
@@ -30,7 +30,7 @@ | |||
30 | * covered by the GNU General Public License. However the source code for | 30 | * covered by the GNU General Public License. However the source code for |
31 | * these files must still be made available in accordance with section (3) | 31 | * these files must still be made available in accordance with section (3) |
32 | * of the GNU General Public License. | 32 | * of the GNU General Public License. |
33 | * | 33 | * |
34 | * This exception does not invalidate any other reasons why a work based on | 34 | * This exception does not invalidate any other reasons why a work based on |
35 | * this file might be covered by the GNU General Public License. | 35 | * this file might be covered by the GNU General Public License. |
36 | */ | 36 | */ |
@@ -67,7 +67,7 @@ static const u_char nand_ecc_precalc_table[] = { | |||
67 | * nand_trans_result - [GENERIC] create non-inverted ECC | 67 | * nand_trans_result - [GENERIC] create non-inverted ECC |
68 | * @reg2: line parity reg 2 | 68 | * @reg2: line parity reg 2 |
69 | * @reg3: line parity reg 3 | 69 | * @reg3: line parity reg 3 |
70 | * @ecc_code: ecc | 70 | * @ecc_code: ecc |
71 | * | 71 | * |
72 | * Creates non-inverted ECC code from line parity | 72 | * Creates non-inverted ECC code from line parity |
73 | */ | 73 | */ |
@@ -75,11 +75,11 @@ static void nand_trans_result(u_char reg2, u_char reg3, | |||
75 | u_char *ecc_code) | 75 | u_char *ecc_code) |
76 | { | 76 | { |
77 | u_char a, b, i, tmp1, tmp2; | 77 | u_char a, b, i, tmp1, tmp2; |
78 | 78 | ||
79 | /* Initialize variables */ | 79 | /* Initialize variables */ |
80 | a = b = 0x80; | 80 | a = b = 0x80; |
81 | tmp1 = tmp2 = 0; | 81 | tmp1 = tmp2 = 0; |
82 | 82 | ||
83 | /* Calculate first ECC byte */ | 83 | /* Calculate first ECC byte */ |
84 | for (i = 0; i < 4; i++) { | 84 | for (i = 0; i < 4; i++) { |
85 | if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ | 85 | if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ |
@@ -90,7 +90,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, | |||
90 | b >>= 1; | 90 | b >>= 1; |
91 | a >>= 1; | 91 | a >>= 1; |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Calculate second ECC byte */ | 94 | /* Calculate second ECC byte */ |
95 | b = 0x80; | 95 | b = 0x80; |
96 | for (i = 0; i < 4; i++) { | 96 | for (i = 0; i < 4; i++) { |
@@ -102,7 +102,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, | |||
102 | b >>= 1; | 102 | b >>= 1; |
103 | a >>= 1; | 103 | a >>= 1; |
104 | } | 104 | } |
105 | 105 | ||
106 | /* Store two of the ECC bytes */ | 106 | /* Store two of the ECC bytes */ |
107 | ecc_code[0] = tmp1; | 107 | ecc_code[0] = tmp1; |
108 | ecc_code[1] = tmp2; | 108 | ecc_code[1] = tmp2; |
@@ -118,28 +118,28 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code | |||
118 | { | 118 | { |
119 | u_char idx, reg1, reg2, reg3; | 119 | u_char idx, reg1, reg2, reg3; |
120 | int j; | 120 | int j; |
121 | 121 | ||
122 | /* Initialize variables */ | 122 | /* Initialize variables */ |
123 | reg1 = reg2 = reg3 = 0; | 123 | reg1 = reg2 = reg3 = 0; |
124 | ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; | 124 | ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; |
125 | 125 | ||
126 | /* Build up column parity */ | 126 | /* Build up column parity */ |
127 | for(j = 0; j < 256; j++) { | 127 | for(j = 0; j < 256; j++) { |
128 | 128 | ||
129 | /* Get CP0 - CP5 from table */ | 129 | /* Get CP0 - CP5 from table */ |
130 | idx = nand_ecc_precalc_table[dat[j]]; | 130 | idx = nand_ecc_precalc_table[dat[j]]; |
131 | reg1 ^= (idx & 0x3f); | 131 | reg1 ^= (idx & 0x3f); |
132 | 132 | ||
133 | /* All bit XOR = 1 ? */ | 133 | /* All bit XOR = 1 ? */ |
134 | if (idx & 0x40) { | 134 | if (idx & 0x40) { |
135 | reg3 ^= (u_char) j; | 135 | reg3 ^= (u_char) j; |
136 | reg2 ^= ~((u_char) j); | 136 | reg2 ^= ~((u_char) j); |
137 | } | 137 | } |
138 | } | 138 | } |
139 | 139 | ||
140 | /* Create non-inverted ECC code from line parity */ | 140 | /* Create non-inverted ECC code from line parity */ |
141 | nand_trans_result(reg2, reg3, ecc_code); | 141 | nand_trans_result(reg2, reg3, ecc_code); |
142 | 142 | ||
143 | /* Calculate final ECC code */ | 143 | /* Calculate final ECC code */ |
144 | ecc_code[0] = ~ecc_code[0]; | 144 | ecc_code[0] = ~ecc_code[0]; |
145 | ecc_code[1] = ~ecc_code[1]; | 145 | ecc_code[1] = ~ecc_code[1]; |
@@ -159,12 +159,12 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code | |||
159 | int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) | 159 | int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) |
160 | { | 160 | { |
161 | u_char a, b, c, d1, d2, d3, add, bit, i; | 161 | u_char a, b, c, d1, d2, d3, add, bit, i; |
162 | 162 | ||
163 | /* Do error detection */ | 163 | /* Do error detection */ |
164 | d1 = calc_ecc[0] ^ read_ecc[0]; | 164 | d1 = calc_ecc[0] ^ read_ecc[0]; |
165 | d2 = calc_ecc[1] ^ read_ecc[1]; | 165 | d2 = calc_ecc[1] ^ read_ecc[1]; |
166 | d3 = calc_ecc[2] ^ read_ecc[2]; | 166 | d3 = calc_ecc[2] ^ read_ecc[2]; |
167 | 167 | ||
168 | if ((d1 | d2 | d3) == 0) { | 168 | if ((d1 | d2 | d3) == 0) { |
169 | /* No errors */ | 169 | /* No errors */ |
170 | return 0; | 170 | return 0; |
@@ -173,7 +173,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha | |||
173 | a = (d1 ^ (d1 >> 1)) & 0x55; | 173 | a = (d1 ^ (d1 >> 1)) & 0x55; |
174 | b = (d2 ^ (d2 >> 1)) & 0x55; | 174 | b = (d2 ^ (d2 >> 1)) & 0x55; |
175 | c = (d3 ^ (d3 >> 1)) & 0x54; | 175 | c = (d3 ^ (d3 >> 1)) & 0x54; |
176 | 176 | ||
177 | /* Found and will correct single bit error in the data */ | 177 | /* Found and will correct single bit error in the data */ |
178 | if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { | 178 | if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { |
179 | c = 0x80; | 179 | c = 0x80; |
@@ -237,7 +237,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha | |||
237 | } | 237 | } |
238 | } | 238 | } |
239 | } | 239 | } |
240 | 240 | ||
241 | /* Should never happen */ | 241 | /* Should never happen */ |
242 | return -1; | 242 | return -1; |
243 | } | 243 | } |
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index efe246961b69..dbc7e55a4247 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) | 4 | * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) |
5 | * | 5 | * |
6 | * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $ | 6 | * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
@@ -14,14 +14,14 @@ | |||
14 | #include <linux/mtd/nand.h> | 14 | #include <linux/mtd/nand.h> |
15 | /* | 15 | /* |
16 | * Chip ID list | 16 | * Chip ID list |
17 | * | 17 | * |
18 | * Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, | 18 | * Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, |
19 | * options | 19 | * options |
20 | * | 20 | * |
21 | * Pagesize; 0, 256, 512 | 21 | * Pagesize; 0, 256, 512 |
22 | * 0 get this information from the extended chip ID | 22 | * 0 get this information from the extended chip ID |
23 | + 256 256 Byte page size | 23 | + 256 256 Byte page size |
24 | * 512 512 Byte page size | 24 | * 512 512 Byte page size |
25 | */ | 25 | */ |
26 | struct nand_flash_dev nand_flash_ids[] = { | 26 | struct nand_flash_dev nand_flash_ids[] = { |
27 | {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, | 27 | {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, |
@@ -34,27 +34,27 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
34 | {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, | 34 | {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, |
35 | {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, | 35 | {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, |
36 | {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, | 36 | {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, |
37 | 37 | ||
38 | {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, | 38 | {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, |
39 | {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, | 39 | {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, |
40 | {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, | 40 | {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, |
41 | {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, | 41 | {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, |
42 | 42 | ||
43 | {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, | 43 | {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, |
44 | {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, | 44 | {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, |
45 | {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, | 45 | {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, |
46 | {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, | 46 | {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, |
47 | 47 | ||
48 | {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, | 48 | {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, |
49 | {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, | 49 | {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, |
50 | {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, | 50 | {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, |
51 | {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, | 51 | {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, |
52 | 52 | ||
53 | {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, | 53 | {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, |
54 | {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, | 54 | {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, |
55 | {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, | 55 | {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, |
56 | {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, | 56 | {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, |
57 | 57 | ||
58 | {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, | 58 | {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, |
59 | {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, | 59 | {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, |
60 | {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, | 60 | {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, |
@@ -62,7 +62,7 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
62 | {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | 62 | {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, |
63 | {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | 63 | {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, |
64 | {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, | 64 | {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, |
65 | 65 | ||
66 | {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, | 66 | {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, |
67 | 67 | ||
68 | /* These are the new chips with large page size. The pagesize | 68 | /* These are the new chips with large page size. The pagesize |
@@ -73,7 +73,7 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
73 | {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 73 | {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
74 | {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 74 | {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
75 | {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 75 | {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
76 | 76 | ||
77 | /* 1 Gigabit */ | 77 | /* 1 Gigabit */ |
78 | {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 78 | {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
79 | {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 79 | {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
@@ -85,13 +85,13 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
85 | {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 85 | {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
86 | {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 86 | {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
87 | {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 87 | {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
88 | 88 | ||
89 | /* 4 Gigabit */ | 89 | /* 4 Gigabit */ |
90 | {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 90 | {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
91 | {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 91 | {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
92 | {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 92 | {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
93 | {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 93 | {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
94 | 94 | ||
95 | /* 8 Gigabit */ | 95 | /* 8 Gigabit */ |
96 | {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 96 | {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
97 | {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, | 97 | {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, |
@@ -104,11 +104,11 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
104 | {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 104 | {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
105 | {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, | 105 | {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, |
106 | 106 | ||
107 | /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! | 107 | /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! |
108 | * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes | 108 | * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes |
109 | * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 | 109 | * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 |
110 | * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go | 110 | * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go |
111 | * There are more speed improvements for reads and writes possible, but not implemented now | 111 | * There are more speed improvements for reads and writes possible, but not implemented now |
112 | */ | 112 | */ |
113 | {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, | 113 | {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, |
114 | 114 | ||
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 754b6ed7ce14..de4500395300 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org> | 4 | * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org> |
5 | * | 5 | * |
6 | * Copyright (C) 2004 Nokia Corporation | 6 | * Copyright (C) 2004 Nokia Corporation |
7 | * | 7 | * |
8 | * Note: NS means "NAND Simulator". | 8 | * Note: NS means "NAND Simulator". |
9 | * Note: Input means input TO flash chip, output means output FROM chip. | 9 | * Note: Input means input TO flash chip, output means output FROM chip. |
@@ -126,7 +126,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
126 | 126 | ||
127 | /* The largest possible page size */ | 127 | /* The largest possible page size */ |
128 | #define NS_LARGEST_PAGE_SIZE 2048 | 128 | #define NS_LARGEST_PAGE_SIZE 2048 |
129 | 129 | ||
130 | /* The prefix for simulator output */ | 130 | /* The prefix for simulator output */ |
131 | #define NS_OUTPUT_PREFIX "[nandsim]" | 131 | #define NS_OUTPUT_PREFIX "[nandsim]" |
132 | 132 | ||
@@ -145,7 +145,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
145 | do { if (do_delays) udelay(us); } while(0) | 145 | do { if (do_delays) udelay(us); } while(0) |
146 | #define NS_MDELAY(us) \ | 146 | #define NS_MDELAY(us) \ |
147 | do { if (do_delays) mdelay(us); } while(0) | 147 | do { if (do_delays) mdelay(us); } while(0) |
148 | 148 | ||
149 | /* Is the nandsim structure initialized ? */ | 149 | /* Is the nandsim structure initialized ? */ |
150 | #define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0) | 150 | #define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0) |
151 | 151 | ||
@@ -153,12 +153,12 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
153 | #define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0))) | 153 | #define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0))) |
154 | 154 | ||
155 | /* Operation failed completion status */ | 155 | /* Operation failed completion status */ |
156 | #define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) | 156 | #define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) |
157 | 157 | ||
158 | /* Calculate the page offset in flash RAM image by (row, column) address */ | 158 | /* Calculate the page offset in flash RAM image by (row, column) address */ |
159 | #define NS_RAW_OFFSET(ns) \ | 159 | #define NS_RAW_OFFSET(ns) \ |
160 | (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column) | 160 | (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column) |
161 | 161 | ||
162 | /* Calculate the OOB offset in flash RAM image by (row, column) address */ | 162 | /* Calculate the OOB offset in flash RAM image by (row, column) address */ |
163 | #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz) | 163 | #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz) |
164 | 164 | ||
@@ -223,15 +223,15 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
223 | 223 | ||
224 | /* Remove action bits ftom state */ | 224 | /* Remove action bits ftom state */ |
225 | #define NS_STATE(x) ((x) & ~ACTION_MASK) | 225 | #define NS_STATE(x) ((x) & ~ACTION_MASK) |
226 | 226 | ||
227 | /* | 227 | /* |
228 | * Maximum previous states which need to be saved. Currently saving is | 228 | * Maximum previous states which need to be saved. Currently saving is |
229 | * only needed for page programm operation with preceeded read command | 229 | * only needed for page programm operation with preceeded read command |
230 | * (which is only valid for 512-byte pages). | 230 | * (which is only valid for 512-byte pages). |
231 | */ | 231 | */ |
232 | #define NS_MAX_PREVSTATES 1 | 232 | #define NS_MAX_PREVSTATES 1 |
233 | 233 | ||
234 | /* | 234 | /* |
235 | * The structure which describes all the internal simulator data. | 235 | * The structure which describes all the internal simulator data. |
236 | */ | 236 | */ |
237 | struct nandsim { | 237 | struct nandsim { |
@@ -242,7 +242,7 @@ struct nandsim { | |||
242 | uint32_t options; /* chip's characteristic bits */ | 242 | uint32_t options; /* chip's characteristic bits */ |
243 | uint32_t state; /* current chip state */ | 243 | uint32_t state; /* current chip state */ |
244 | uint32_t nxstate; /* next expected state */ | 244 | uint32_t nxstate; /* next expected state */ |
245 | 245 | ||
246 | uint32_t *op; /* current operation, NULL operations isn't known yet */ | 246 | uint32_t *op; /* current operation, NULL operations isn't known yet */ |
247 | uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */ | 247 | uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */ |
248 | uint16_t npstates; /* number of previous states saved */ | 248 | uint16_t npstates; /* number of previous states saved */ |
@@ -413,7 +413,7 @@ init_nandsim(struct mtd_info *mtd) | |||
413 | ns->geom.secaddrbytes = 3; | 413 | ns->geom.secaddrbytes = 3; |
414 | } | 414 | } |
415 | } | 415 | } |
416 | 416 | ||
417 | /* Detect how many ID bytes the NAND chip outputs */ | 417 | /* Detect how many ID bytes the NAND chip outputs */ |
418 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 418 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
419 | if (second_id_byte != nand_flash_ids[i].id) | 419 | if (second_id_byte != nand_flash_ids[i].id) |
@@ -444,7 +444,7 @@ init_nandsim(struct mtd_info *mtd) | |||
444 | #ifdef CONFIG_NS_ABS_POS | 444 | #ifdef CONFIG_NS_ABS_POS |
445 | ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob); | 445 | ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob); |
446 | if (!ns->mem.byte) { | 446 | if (!ns->mem.byte) { |
447 | NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", | 447 | NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", |
448 | (void *)CONFIG_NS_ABS_POS); | 448 | (void *)CONFIG_NS_ABS_POS); |
449 | return -ENOMEM; | 449 | return -ENOMEM; |
450 | } | 450 | } |
@@ -567,7 +567,7 @@ static int | |||
567 | check_command(int cmd) | 567 | check_command(int cmd) |
568 | { | 568 | { |
569 | switch (cmd) { | 569 | switch (cmd) { |
570 | 570 | ||
571 | case NAND_CMD_READ0: | 571 | case NAND_CMD_READ0: |
572 | case NAND_CMD_READSTART: | 572 | case NAND_CMD_READSTART: |
573 | case NAND_CMD_PAGEPROG: | 573 | case NAND_CMD_PAGEPROG: |
@@ -580,7 +580,7 @@ check_command(int cmd) | |||
580 | case NAND_CMD_RESET: | 580 | case NAND_CMD_RESET: |
581 | case NAND_CMD_READ1: | 581 | case NAND_CMD_READ1: |
582 | return 0; | 582 | return 0; |
583 | 583 | ||
584 | case NAND_CMD_STATUS_MULTI: | 584 | case NAND_CMD_STATUS_MULTI: |
585 | default: | 585 | default: |
586 | return 1; | 586 | return 1; |
@@ -631,7 +631,7 @@ static inline void | |||
631 | accept_addr_byte(struct nandsim *ns, u_char bt) | 631 | accept_addr_byte(struct nandsim *ns, u_char bt) |
632 | { | 632 | { |
633 | uint byte = (uint)bt; | 633 | uint byte = (uint)bt; |
634 | 634 | ||
635 | if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | 635 | if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) |
636 | ns->regs.column |= (byte << 8 * ns->regs.count); | 636 | ns->regs.column |= (byte << 8 * ns->regs.count); |
637 | else { | 637 | else { |
@@ -642,11 +642,11 @@ accept_addr_byte(struct nandsim *ns, u_char bt) | |||
642 | 642 | ||
643 | return; | 643 | return; |
644 | } | 644 | } |
645 | 645 | ||
646 | /* | 646 | /* |
647 | * Switch to STATE_READY state. | 647 | * Switch to STATE_READY state. |
648 | */ | 648 | */ |
649 | static inline void | 649 | static inline void |
650 | switch_to_ready_state(struct nandsim *ns, u_char status) | 650 | switch_to_ready_state(struct nandsim *ns, u_char status) |
651 | { | 651 | { |
652 | NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); | 652 | NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); |
@@ -675,7 +675,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) | |||
675 | * (for example program from the second half and read from the | 675 | * (for example program from the second half and read from the |
676 | * second half operations both begin with the READ1 command). In this | 676 | * second half operations both begin with the READ1 command). In this |
677 | * case the ns->pstates[] array contains previous states. | 677 | * case the ns->pstates[] array contains previous states. |
678 | * | 678 | * |
679 | * Thus, the function tries to find operation containing the following | 679 | * Thus, the function tries to find operation containing the following |
680 | * states (if the 'flag' parameter is 0): | 680 | * states (if the 'flag' parameter is 0): |
681 | * ns->pstates[0], ... ns->pstates[ns->npstates], ns->state | 681 | * ns->pstates[0], ... ns->pstates[ns->npstates], ns->state |
@@ -683,7 +683,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) | |||
683 | * If (one and only one) matching operation is found, it is accepted ( | 683 | * If (one and only one) matching operation is found, it is accepted ( |
684 | * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is | 684 | * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is |
685 | * zeroed). | 685 | * zeroed). |
686 | * | 686 | * |
687 | * If there are several maches, the current state is pushed to the | 687 | * If there are several maches, the current state is pushed to the |
688 | * ns->pstates. | 688 | * ns->pstates. |
689 | * | 689 | * |
@@ -692,7 +692,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) | |||
692 | * In such situation the function is called with 'flag' != 0, and the | 692 | * In such situation the function is called with 'flag' != 0, and the |
693 | * operation is searched using the following pattern: | 693 | * operation is searched using the following pattern: |
694 | * ns->pstates[0], ... ns->pstates[ns->npstates], <address input> | 694 | * ns->pstates[0], ... ns->pstates[ns->npstates], <address input> |
695 | * | 695 | * |
696 | * It is supposed that this pattern must either match one operation on | 696 | * It is supposed that this pattern must either match one operation on |
697 | * none. There can't be ambiguity in that case. | 697 | * none. There can't be ambiguity in that case. |
698 | * | 698 | * |
@@ -711,15 +711,15 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
711 | { | 711 | { |
712 | int opsfound = 0; | 712 | int opsfound = 0; |
713 | int i, j, idx = 0; | 713 | int i, j, idx = 0; |
714 | 714 | ||
715 | for (i = 0; i < NS_OPER_NUM; i++) { | 715 | for (i = 0; i < NS_OPER_NUM; i++) { |
716 | 716 | ||
717 | int found = 1; | 717 | int found = 1; |
718 | 718 | ||
719 | if (!(ns->options & ops[i].reqopts)) | 719 | if (!(ns->options & ops[i].reqopts)) |
720 | /* Ignore operations we can't perform */ | 720 | /* Ignore operations we can't perform */ |
721 | continue; | 721 | continue; |
722 | 722 | ||
723 | if (flag) { | 723 | if (flag) { |
724 | if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK)) | 724 | if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK)) |
725 | continue; | 725 | continue; |
@@ -728,7 +728,7 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
728 | continue; | 728 | continue; |
729 | } | 729 | } |
730 | 730 | ||
731 | for (j = 0; j < ns->npstates; j++) | 731 | for (j = 0; j < ns->npstates; j++) |
732 | if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j]) | 732 | if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j]) |
733 | && (ns->options & ops[idx].reqopts)) { | 733 | && (ns->options & ops[idx].reqopts)) { |
734 | found = 0; | 734 | found = 0; |
@@ -745,7 +745,7 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
745 | /* Exact match */ | 745 | /* Exact match */ |
746 | ns->op = &ops[idx].states[0]; | 746 | ns->op = &ops[idx].states[0]; |
747 | if (flag) { | 747 | if (flag) { |
748 | /* | 748 | /* |
749 | * In this case the find_operation function was | 749 | * In this case the find_operation function was |
750 | * called when address has just began input. But it isn't | 750 | * called when address has just began input. But it isn't |
751 | * yet fully input and the current state must | 751 | * yet fully input and the current state must |
@@ -763,7 +763,7 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
763 | idx, get_state_name(ns->state), get_state_name(ns->nxstate)); | 763 | idx, get_state_name(ns->state), get_state_name(ns->nxstate)); |
764 | return 0; | 764 | return 0; |
765 | } | 765 | } |
766 | 766 | ||
767 | if (opsfound == 0) { | 767 | if (opsfound == 0) { |
768 | /* Nothing was found. Try to ignore previous commands (if any) and search again */ | 768 | /* Nothing was found. Try to ignore previous commands (if any) and search again */ |
769 | if (ns->npstates != 0) { | 769 | if (ns->npstates != 0) { |
@@ -777,13 +777,13 @@ find_operation(struct nandsim *ns, uint32_t flag) | |||
777 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 777 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
778 | return -2; | 778 | return -2; |
779 | } | 779 | } |
780 | 780 | ||
781 | if (flag) { | 781 | if (flag) { |
782 | /* This shouldn't happen */ | 782 | /* This shouldn't happen */ |
783 | NS_DBG("find_operation: BUG, operation must be known if address is input\n"); | 783 | NS_DBG("find_operation: BUG, operation must be known if address is input\n"); |
784 | return -2; | 784 | return -2; |
785 | } | 785 | } |
786 | 786 | ||
787 | NS_DBG("find_operation: there is still ambiguity\n"); | 787 | NS_DBG("find_operation: there is still ambiguity\n"); |
788 | 788 | ||
789 | ns->pstates[ns->npstates++] = ns->state; | 789 | ns->pstates[ns->npstates++] = ns->state; |
@@ -803,7 +803,7 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
803 | int busdiv = ns->busw == 8 ? 1 : 2; | 803 | int busdiv = ns->busw == 8 ? 1 : 2; |
804 | 804 | ||
805 | action &= ACTION_MASK; | 805 | action &= ACTION_MASK; |
806 | 806 | ||
807 | /* Check that page address input is correct */ | 807 | /* Check that page address input is correct */ |
808 | if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) { | 808 | if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) { |
809 | NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row); | 809 | NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row); |
@@ -827,14 +827,14 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
827 | 827 | ||
828 | NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", | 828 | NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", |
829 | num, NS_RAW_OFFSET(ns) + ns->regs.off); | 829 | num, NS_RAW_OFFSET(ns) + ns->regs.off); |
830 | 830 | ||
831 | if (ns->regs.off == 0) | 831 | if (ns->regs.off == 0) |
832 | NS_LOG("read page %d\n", ns->regs.row); | 832 | NS_LOG("read page %d\n", ns->regs.row); |
833 | else if (ns->regs.off < ns->geom.pgsz) | 833 | else if (ns->regs.off < ns->geom.pgsz) |
834 | NS_LOG("read page %d (second half)\n", ns->regs.row); | 834 | NS_LOG("read page %d (second half)\n", ns->regs.row); |
835 | else | 835 | else |
836 | NS_LOG("read OOB of page %d\n", ns->regs.row); | 836 | NS_LOG("read OOB of page %d\n", ns->regs.row); |
837 | 837 | ||
838 | NS_UDELAY(access_delay); | 838 | NS_UDELAY(access_delay); |
839 | NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv); | 839 | NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv); |
840 | 840 | ||
@@ -844,30 +844,30 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
844 | /* | 844 | /* |
845 | * Erase sector. | 845 | * Erase sector. |
846 | */ | 846 | */ |
847 | 847 | ||
848 | if (ns->lines.wp) { | 848 | if (ns->lines.wp) { |
849 | NS_ERR("do_state_action: device is write-protected, ignore sector erase\n"); | 849 | NS_ERR("do_state_action: device is write-protected, ignore sector erase\n"); |
850 | return -1; | 850 | return -1; |
851 | } | 851 | } |
852 | 852 | ||
853 | if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec | 853 | if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec |
854 | || (ns->regs.row & ~(ns->geom.secsz - 1))) { | 854 | || (ns->regs.row & ~(ns->geom.secsz - 1))) { |
855 | NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row); | 855 | NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row); |
856 | return -1; | 856 | return -1; |
857 | } | 857 | } |
858 | 858 | ||
859 | ns->regs.row = (ns->regs.row << | 859 | ns->regs.row = (ns->regs.row << |
860 | 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; | 860 | 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; |
861 | ns->regs.column = 0; | 861 | ns->regs.column = 0; |
862 | 862 | ||
863 | NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", | 863 | NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", |
864 | ns->regs.row, NS_RAW_OFFSET(ns)); | 864 | ns->regs.row, NS_RAW_OFFSET(ns)); |
865 | NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); | 865 | NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); |
866 | 866 | ||
867 | memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob); | 867 | memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob); |
868 | 868 | ||
869 | NS_MDELAY(erase_delay); | 869 | NS_MDELAY(erase_delay); |
870 | 870 | ||
871 | break; | 871 | break; |
872 | 872 | ||
873 | case ACTION_PRGPAGE: | 873 | case ACTION_PRGPAGE: |
@@ -893,12 +893,12 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
893 | NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", | 893 | NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", |
894 | num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); | 894 | num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); |
895 | NS_LOG("programm page %d\n", ns->regs.row); | 895 | NS_LOG("programm page %d\n", ns->regs.row); |
896 | 896 | ||
897 | NS_UDELAY(programm_delay); | 897 | NS_UDELAY(programm_delay); |
898 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); | 898 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); |
899 | 899 | ||
900 | break; | 900 | break; |
901 | 901 | ||
902 | case ACTION_ZEROOFF: | 902 | case ACTION_ZEROOFF: |
903 | NS_DBG("do_state_action: set internal offset to 0\n"); | 903 | NS_DBG("do_state_action: set internal offset to 0\n"); |
904 | ns->regs.off = 0; | 904 | ns->regs.off = 0; |
@@ -918,7 +918,7 @@ do_state_action(struct nandsim *ns, uint32_t action) | |||
918 | NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz); | 918 | NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz); |
919 | ns->regs.off = ns->geom.pgsz; | 919 | ns->regs.off = ns->geom.pgsz; |
920 | break; | 920 | break; |
921 | 921 | ||
922 | default: | 922 | default: |
923 | NS_DBG("do_state_action: BUG! unknown action\n"); | 923 | NS_DBG("do_state_action: BUG! unknown action\n"); |
924 | } | 924 | } |
@@ -937,7 +937,7 @@ switch_state(struct nandsim *ns) | |||
937 | * The current operation have already been identified. | 937 | * The current operation have already been identified. |
938 | * Just follow the states chain. | 938 | * Just follow the states chain. |
939 | */ | 939 | */ |
940 | 940 | ||
941 | ns->stateidx += 1; | 941 | ns->stateidx += 1; |
942 | ns->state = ns->nxstate; | 942 | ns->state = ns->nxstate; |
943 | ns->nxstate = ns->op[ns->stateidx + 1]; | 943 | ns->nxstate = ns->op[ns->stateidx + 1]; |
@@ -951,14 +951,14 @@ switch_state(struct nandsim *ns) | |||
951 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 951 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
952 | return; | 952 | return; |
953 | } | 953 | } |
954 | 954 | ||
955 | } else { | 955 | } else { |
956 | /* | 956 | /* |
957 | * We don't yet know which operation we perform. | 957 | * We don't yet know which operation we perform. |
958 | * Try to identify it. | 958 | * Try to identify it. |
959 | */ | 959 | */ |
960 | 960 | ||
961 | /* | 961 | /* |
962 | * The only event causing the switch_state function to | 962 | * The only event causing the switch_state function to |
963 | * be called with yet unknown operation is new command. | 963 | * be called with yet unknown operation is new command. |
964 | */ | 964 | */ |
@@ -987,7 +987,7 @@ switch_state(struct nandsim *ns) | |||
987 | */ | 987 | */ |
988 | 988 | ||
989 | u_char status = NS_STATUS_OK(ns); | 989 | u_char status = NS_STATUS_OK(ns); |
990 | 990 | ||
991 | /* In case of data states, see if all bytes were input/output */ | 991 | /* In case of data states, see if all bytes were input/output */ |
992 | if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) | 992 | if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) |
993 | && ns->regs.count != ns->regs.num) { | 993 | && ns->regs.count != ns->regs.num) { |
@@ -995,17 +995,17 @@ switch_state(struct nandsim *ns) | |||
995 | ns->regs.num - ns->regs.count); | 995 | ns->regs.num - ns->regs.count); |
996 | status = NS_STATUS_FAILED(ns); | 996 | status = NS_STATUS_FAILED(ns); |
997 | } | 997 | } |
998 | 998 | ||
999 | NS_DBG("switch_state: operation complete, switch to STATE_READY state\n"); | 999 | NS_DBG("switch_state: operation complete, switch to STATE_READY state\n"); |
1000 | 1000 | ||
1001 | switch_to_ready_state(ns, status); | 1001 | switch_to_ready_state(ns, status); |
1002 | 1002 | ||
1003 | return; | 1003 | return; |
1004 | } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) { | 1004 | } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) { |
1005 | /* | 1005 | /* |
1006 | * If the next state is data input/output, switch to it now | 1006 | * If the next state is data input/output, switch to it now |
1007 | */ | 1007 | */ |
1008 | 1008 | ||
1009 | ns->state = ns->nxstate; | 1009 | ns->state = ns->nxstate; |
1010 | ns->nxstate = ns->op[++ns->stateidx + 1]; | 1010 | ns->nxstate = ns->op[++ns->stateidx + 1]; |
1011 | ns->regs.num = ns->regs.count = 0; | 1011 | ns->regs.num = ns->regs.count = 0; |
@@ -1023,16 +1023,16 @@ switch_state(struct nandsim *ns) | |||
1023 | case STATE_DATAOUT: | 1023 | case STATE_DATAOUT: |
1024 | ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; | 1024 | ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; |
1025 | break; | 1025 | break; |
1026 | 1026 | ||
1027 | case STATE_DATAOUT_ID: | 1027 | case STATE_DATAOUT_ID: |
1028 | ns->regs.num = ns->geom.idbytes; | 1028 | ns->regs.num = ns->geom.idbytes; |
1029 | break; | 1029 | break; |
1030 | 1030 | ||
1031 | case STATE_DATAOUT_STATUS: | 1031 | case STATE_DATAOUT_STATUS: |
1032 | case STATE_DATAOUT_STATUS_M: | 1032 | case STATE_DATAOUT_STATUS_M: |
1033 | ns->regs.count = ns->regs.num = 0; | 1033 | ns->regs.count = ns->regs.num = 0; |
1034 | break; | 1034 | break; |
1035 | 1035 | ||
1036 | default: | 1036 | default: |
1037 | NS_ERR("switch_state: BUG! unknown data state\n"); | 1037 | NS_ERR("switch_state: BUG! unknown data state\n"); |
1038 | } | 1038 | } |
@@ -1044,16 +1044,16 @@ switch_state(struct nandsim *ns) | |||
1044 | */ | 1044 | */ |
1045 | 1045 | ||
1046 | ns->regs.count = 0; | 1046 | ns->regs.count = 0; |
1047 | 1047 | ||
1048 | switch (NS_STATE(ns->nxstate)) { | 1048 | switch (NS_STATE(ns->nxstate)) { |
1049 | case STATE_ADDR_PAGE: | 1049 | case STATE_ADDR_PAGE: |
1050 | ns->regs.num = ns->geom.pgaddrbytes; | 1050 | ns->regs.num = ns->geom.pgaddrbytes; |
1051 | 1051 | ||
1052 | break; | 1052 | break; |
1053 | case STATE_ADDR_SEC: | 1053 | case STATE_ADDR_SEC: |
1054 | ns->regs.num = ns->geom.secaddrbytes; | 1054 | ns->regs.num = ns->geom.secaddrbytes; |
1055 | break; | 1055 | break; |
1056 | 1056 | ||
1057 | case STATE_ADDR_ZERO: | 1057 | case STATE_ADDR_ZERO: |
1058 | ns->regs.num = 1; | 1058 | ns->regs.num = 1; |
1059 | break; | 1059 | break; |
@@ -1062,7 +1062,7 @@ switch_state(struct nandsim *ns) | |||
1062 | NS_ERR("switch_state: BUG! unknown address state\n"); | 1062 | NS_ERR("switch_state: BUG! unknown address state\n"); |
1063 | } | 1063 | } |
1064 | } else { | 1064 | } else { |
1065 | /* | 1065 | /* |
1066 | * Just reset internal counters. | 1066 | * Just reset internal counters. |
1067 | */ | 1067 | */ |
1068 | 1068 | ||
@@ -1184,7 +1184,7 @@ ns_nand_read_byte(struct mtd_info *mtd) | |||
1184 | default: | 1184 | default: |
1185 | BUG(); | 1185 | BUG(); |
1186 | } | 1186 | } |
1187 | 1187 | ||
1188 | if (ns->regs.count == ns->regs.num) { | 1188 | if (ns->regs.count == ns->regs.num) { |
1189 | NS_DBG("read_byte: all bytes were read\n"); | 1189 | NS_DBG("read_byte: all bytes were read\n"); |
1190 | 1190 | ||
@@ -1201,9 +1201,9 @@ ns_nand_read_byte(struct mtd_info *mtd) | |||
1201 | } | 1201 | } |
1202 | else if (NS_STATE(ns->nxstate) == STATE_READY) | 1202 | else if (NS_STATE(ns->nxstate) == STATE_READY) |
1203 | switch_state(ns); | 1203 | switch_state(ns); |
1204 | 1204 | ||
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | return outb; | 1207 | return outb; |
1208 | } | 1208 | } |
1209 | 1209 | ||
@@ -1211,7 +1211,7 @@ static void | |||
1211 | ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | 1211 | ns_nand_write_byte(struct mtd_info *mtd, u_char byte) |
1212 | { | 1212 | { |
1213 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; | 1213 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; |
1214 | 1214 | ||
1215 | /* Sanity and correctness checks */ | 1215 | /* Sanity and correctness checks */ |
1216 | if (!ns->lines.ce) { | 1216 | if (!ns->lines.ce) { |
1217 | NS_ERR("write_byte: chip is disabled, ignore write\n"); | 1217 | NS_ERR("write_byte: chip is disabled, ignore write\n"); |
@@ -1221,7 +1221,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1221 | NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n"); | 1221 | NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n"); |
1222 | return; | 1222 | return; |
1223 | } | 1223 | } |
1224 | 1224 | ||
1225 | if (ns->lines.cle == 1) { | 1225 | if (ns->lines.cle == 1) { |
1226 | /* | 1226 | /* |
1227 | * The byte written is a command. | 1227 | * The byte written is a command. |
@@ -1233,7 +1233,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1233 | return; | 1233 | return; |
1234 | } | 1234 | } |
1235 | 1235 | ||
1236 | /* | 1236 | /* |
1237 | * Chip might still be in STATE_DATAOUT | 1237 | * Chip might still be in STATE_DATAOUT |
1238 | * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or | 1238 | * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or |
1239 | * STATE_DATAOUT_STATUS_M state. If so, switch state. | 1239 | * STATE_DATAOUT_STATUS_M state. If so, switch state. |
@@ -1254,13 +1254,13 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1254 | "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); | 1254 | "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); |
1255 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 1255 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
1256 | } | 1256 | } |
1257 | 1257 | ||
1258 | /* Check that the command byte is correct */ | 1258 | /* Check that the command byte is correct */ |
1259 | if (check_command(byte)) { | 1259 | if (check_command(byte)) { |
1260 | NS_ERR("write_byte: unknown command %#x\n", (uint)byte); | 1260 | NS_ERR("write_byte: unknown command %#x\n", (uint)byte); |
1261 | return; | 1261 | return; |
1262 | } | 1262 | } |
1263 | 1263 | ||
1264 | NS_DBG("command byte corresponding to %s state accepted\n", | 1264 | NS_DBG("command byte corresponding to %s state accepted\n", |
1265 | get_state_name(get_state_by_command(byte))); | 1265 | get_state_name(get_state_by_command(byte))); |
1266 | ns->regs.command = byte; | 1266 | ns->regs.command = byte; |
@@ -1277,12 +1277,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1277 | 1277 | ||
1278 | if (find_operation(ns, 1) < 0) | 1278 | if (find_operation(ns, 1) < 0) |
1279 | return; | 1279 | return; |
1280 | 1280 | ||
1281 | if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { | 1281 | if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { |
1282 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 1282 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
1283 | return; | 1283 | return; |
1284 | } | 1284 | } |
1285 | 1285 | ||
1286 | ns->regs.count = 0; | 1286 | ns->regs.count = 0; |
1287 | switch (NS_STATE(ns->nxstate)) { | 1287 | switch (NS_STATE(ns->nxstate)) { |
1288 | case STATE_ADDR_PAGE: | 1288 | case STATE_ADDR_PAGE: |
@@ -1306,7 +1306,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1306 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); | 1306 | switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); |
1307 | return; | 1307 | return; |
1308 | } | 1308 | } |
1309 | 1309 | ||
1310 | /* Check if this is expected byte */ | 1310 | /* Check if this is expected byte */ |
1311 | if (ns->regs.count == ns->regs.num) { | 1311 | if (ns->regs.count == ns->regs.num) { |
1312 | NS_ERR("write_byte: no more address bytes expected\n"); | 1312 | NS_ERR("write_byte: no more address bytes expected\n"); |
@@ -1325,12 +1325,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1325 | NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column); | 1325 | NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column); |
1326 | switch_state(ns); | 1326 | switch_state(ns); |
1327 | } | 1327 | } |
1328 | 1328 | ||
1329 | } else { | 1329 | } else { |
1330 | /* | 1330 | /* |
1331 | * The byte written is an input data. | 1331 | * The byte written is an input data. |
1332 | */ | 1332 | */ |
1333 | 1333 | ||
1334 | /* Check that chip is expecting data input */ | 1334 | /* Check that chip is expecting data input */ |
1335 | if (!(ns->state & STATE_DATAIN_MASK)) { | 1335 | if (!(ns->state & STATE_DATAIN_MASK)) { |
1336 | NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, " | 1336 | NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, " |
@@ -1372,7 +1372,7 @@ ns_nand_read_word(struct mtd_info *mtd) | |||
1372 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 1372 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
1373 | 1373 | ||
1374 | NS_DBG("read_word\n"); | 1374 | NS_DBG("read_word\n"); |
1375 | 1375 | ||
1376 | return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); | 1376 | return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); |
1377 | } | 1377 | } |
1378 | 1378 | ||
@@ -1380,14 +1380,14 @@ static void | |||
1380 | ns_nand_write_word(struct mtd_info *mtd, uint16_t word) | 1380 | ns_nand_write_word(struct mtd_info *mtd, uint16_t word) |
1381 | { | 1381 | { |
1382 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 1382 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
1383 | 1383 | ||
1384 | NS_DBG("write_word\n"); | 1384 | NS_DBG("write_word\n"); |
1385 | 1385 | ||
1386 | chip->write_byte(mtd, word & 0xFF); | 1386 | chip->write_byte(mtd, word & 0xFF); |
1387 | chip->write_byte(mtd, word >> 8); | 1387 | chip->write_byte(mtd, word >> 8); |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | static void | 1390 | static void |
1391 | ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | 1391 | ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) |
1392 | { | 1392 | { |
1393 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; | 1393 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; |
@@ -1409,13 +1409,13 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | |||
1409 | 1409 | ||
1410 | memcpy(ns->buf.byte + ns->regs.count, buf, len); | 1410 | memcpy(ns->buf.byte + ns->regs.count, buf, len); |
1411 | ns->regs.count += len; | 1411 | ns->regs.count += len; |
1412 | 1412 | ||
1413 | if (ns->regs.count == ns->regs.num) { | 1413 | if (ns->regs.count == ns->regs.num) { |
1414 | NS_DBG("write_buf: %d bytes were written\n", ns->regs.count); | 1414 | NS_DBG("write_buf: %d bytes were written\n", ns->regs.count); |
1415 | } | 1415 | } |
1416 | } | 1416 | } |
1417 | 1417 | ||
1418 | static void | 1418 | static void |
1419 | ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | 1419 | ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) |
1420 | { | 1420 | { |
1421 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; | 1421 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; |
@@ -1453,7 +1453,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
1453 | 1453 | ||
1454 | memcpy(buf, ns->buf.byte + ns->regs.count, len); | 1454 | memcpy(buf, ns->buf.byte + ns->regs.count, len); |
1455 | ns->regs.count += len; | 1455 | ns->regs.count += len; |
1456 | 1456 | ||
1457 | if (ns->regs.count == ns->regs.num) { | 1457 | if (ns->regs.count == ns->regs.num) { |
1458 | if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { | 1458 | if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { |
1459 | ns->regs.count = 0; | 1459 | ns->regs.count = 0; |
@@ -1465,11 +1465,11 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |||
1465 | else if (NS_STATE(ns->nxstate) == STATE_READY) | 1465 | else if (NS_STATE(ns->nxstate) == STATE_READY) |
1466 | switch_state(ns); | 1466 | switch_state(ns); |
1467 | } | 1467 | } |
1468 | 1468 | ||
1469 | return; | 1469 | return; |
1470 | } | 1470 | } |
1471 | 1471 | ||
1472 | static int | 1472 | static int |
1473 | ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | 1473 | ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) |
1474 | { | 1474 | { |
1475 | ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len); | 1475 | ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len); |
@@ -1496,7 +1496,7 @@ int __init ns_init_module(void) | |||
1496 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); | 1496 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); |
1497 | return -EINVAL; | 1497 | return -EINVAL; |
1498 | } | 1498 | } |
1499 | 1499 | ||
1500 | /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ | 1500 | /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ |
1501 | nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) | 1501 | nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) |
1502 | + sizeof(struct nandsim), GFP_KERNEL); | 1502 | + sizeof(struct nandsim), GFP_KERNEL); |
@@ -1509,7 +1509,7 @@ int __init ns_init_module(void) | |||
1509 | chip = (struct nand_chip *)(nsmtd + 1); | 1509 | chip = (struct nand_chip *)(nsmtd + 1); |
1510 | nsmtd->priv = (void *)chip; | 1510 | nsmtd->priv = (void *)chip; |
1511 | nand = (struct nandsim *)(chip + 1); | 1511 | nand = (struct nandsim *)(chip + 1); |
1512 | chip->priv = (void *)nand; | 1512 | chip->priv = (void *)nand; |
1513 | 1513 | ||
1514 | /* | 1514 | /* |
1515 | * Register simulator's callbacks. | 1515 | * Register simulator's callbacks. |
@@ -1526,9 +1526,9 @@ int __init ns_init_module(void) | |||
1526 | chip->eccmode = NAND_ECC_SOFT; | 1526 | chip->eccmode = NAND_ECC_SOFT; |
1527 | chip->options |= NAND_SKIP_BBTSCAN; | 1527 | chip->options |= NAND_SKIP_BBTSCAN; |
1528 | 1528 | ||
1529 | /* | 1529 | /* |
1530 | * Perform minimum nandsim structure initialization to handle | 1530 | * Perform minimum nandsim structure initialization to handle |
1531 | * the initial ID read command correctly | 1531 | * the initial ID read command correctly |
1532 | */ | 1532 | */ |
1533 | if (third_id_byte != 0xFF || fourth_id_byte != 0xFF) | 1533 | if (third_id_byte != 0xFF || fourth_id_byte != 0xFF) |
1534 | nand->geom.idbytes = 4; | 1534 | nand->geom.idbytes = 4; |
@@ -1557,7 +1557,7 @@ int __init ns_init_module(void) | |||
1557 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); | 1557 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); |
1558 | goto error; | 1558 | goto error; |
1559 | } | 1559 | } |
1560 | 1560 | ||
1561 | if ((retval = nand_default_bbt(nsmtd)) != 0) { | 1561 | if ((retval = nand_default_bbt(nsmtd)) != 0) { |
1562 | free_nandsim(nand); | 1562 | free_nandsim(nand); |
1563 | goto error; | 1563 | goto error; |
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index e510a83d7bdb..91a95f34a6ee 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Derived from drivers/mtd/nand/edb7312.c | 6 | * Derived from drivers/mtd/nand/edb7312.c |
7 | * | 7 | * |
8 | * | 8 | * |
9 | * $Id: ppchameleonevb.c,v 1.6 2004/11/05 16:07:16 kalev Exp $ | 9 | * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -338,7 +338,7 @@ nand_evb_init: | |||
338 | out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0); | 338 | out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0); |
339 | out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF); | 339 | out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF); |
340 | /* enable output driver */ | 340 | /* enable output driver */ |
341 | out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | | 341 | out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | |
342 | NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); | 342 | NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); |
343 | #ifdef USE_READY_BUSY_PIN | 343 | #ifdef USE_READY_BUSY_PIN |
344 | /* three-state select */ | 344 | /* three-state select */ |
@@ -402,7 +402,7 @@ static void __exit ppchameleonevb_cleanup (void) | |||
402 | /* Release resources, unregister device(s) */ | 402 | /* Release resources, unregister device(s) */ |
403 | nand_release (ppchameleon_mtd); | 403 | nand_release (ppchameleon_mtd); |
404 | nand_release (ppchameleonevb_mtd); | 404 | nand_release (ppchameleonevb_mtd); |
405 | 405 | ||
406 | /* Release iomaps */ | 406 | /* Release iomaps */ |
407 | this = (struct nand_chip *) &ppchameleon_mtd[1]; | 407 | this = (struct nand_chip *) &ppchameleon_mtd[1]; |
408 | iounmap((void *) this->IO_ADDR_R; | 408 | iounmap((void *) this->IO_ADDR_R; |
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 031051cbde76..3a5841c9d950 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
@@ -2,11 +2,11 @@ | |||
2 | * drivers/mtd/nand/rtc_from4.c | 2 | * drivers/mtd/nand/rtc_from4.c |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Red Hat, Inc. | 4 | * Copyright (C) 2004 Red Hat, Inc. |
5 | * | 5 | * |
6 | * Derived from drivers/mtd/nand/spia.c | 6 | * Derived from drivers/mtd/nand/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $ | 9 | * $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 gleixner Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -14,8 +14,8 @@ | |||
14 | * | 14 | * |
15 | * Overview: | 15 | * Overview: |
16 | * This is a device driver for the AG-AND flash device found on the | 16 | * This is a device driver for the AG-AND flash device found on the |
17 | * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), | 17 | * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), |
18 | * which utilizes the Renesas HN29V1G91T-30 part. | 18 | * which utilizes the Renesas HN29V1G91T-30 part. |
19 | * This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device. | 19 | * This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device. |
20 | */ | 20 | */ |
21 | 21 | ||
@@ -105,9 +105,9 @@ const static struct mtd_partition partition_info[] = { | |||
105 | }; | 105 | }; |
106 | #define NUM_PARTITIONS 1 | 106 | #define NUM_PARTITIONS 1 |
107 | 107 | ||
108 | /* | 108 | /* |
109 | * hardware specific flash bbt decriptors | 109 | * hardware specific flash bbt decriptors |
110 | * Note: this is to allow debugging by disabling | 110 | * Note: this is to allow debugging by disabling |
111 | * NAND_BBT_CREATE and/or NAND_BBT_WRITE | 111 | * NAND_BBT_CREATE and/or NAND_BBT_WRITE |
112 | * | 112 | * |
113 | */ | 113 | */ |
@@ -141,7 +141,7 @@ static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = { | |||
141 | /* the Reed Solomon control structure */ | 141 | /* the Reed Solomon control structure */ |
142 | static struct rs_control *rs_decoder; | 142 | static struct rs_control *rs_decoder; |
143 | 143 | ||
144 | /* | 144 | /* |
145 | * hardware specific Out Of Band information | 145 | * hardware specific Out Of Band information |
146 | */ | 146 | */ |
147 | static struct nand_oobinfo rtc_from4_nand_oobinfo = { | 147 | static struct nand_oobinfo rtc_from4_nand_oobinfo = { |
@@ -200,38 +200,38 @@ static uint8_t revbits[256] = { | |||
200 | 200 | ||
201 | 201 | ||
202 | 202 | ||
203 | /* | 203 | /* |
204 | * rtc_from4_hwcontrol - hardware specific access to control-lines | 204 | * rtc_from4_hwcontrol - hardware specific access to control-lines |
205 | * @mtd: MTD device structure | 205 | * @mtd: MTD device structure |
206 | * @cmd: hardware control command | 206 | * @cmd: hardware control command |
207 | * | 207 | * |
208 | * Address lines (A5 and A4) are used to control Command and Address Latch | 208 | * Address lines (A5 and A4) are used to control Command and Address Latch |
209 | * Enable on this board, so set the read/write address appropriately. | 209 | * Enable on this board, so set the read/write address appropriately. |
210 | * | 210 | * |
211 | * Chip Enable is also controlled by the Chip Select (CS5) and | 211 | * Chip Enable is also controlled by the Chip Select (CS5) and |
212 | * Address lines (A24-A22), so no action is required here. | 212 | * Address lines (A24-A22), so no action is required here. |
213 | * | 213 | * |
214 | */ | 214 | */ |
215 | static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) | 215 | static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) |
216 | { | 216 | { |
217 | struct nand_chip* this = (struct nand_chip *) (mtd->priv); | 217 | struct nand_chip* this = (struct nand_chip *) (mtd->priv); |
218 | 218 | ||
219 | switch(cmd) { | 219 | switch(cmd) { |
220 | 220 | ||
221 | case NAND_CTL_SETCLE: | 221 | case NAND_CTL_SETCLE: |
222 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); | 222 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); |
223 | break; | 223 | break; |
224 | case NAND_CTL_CLRCLE: | 224 | case NAND_CTL_CLRCLE: |
225 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE); | 225 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE); |
226 | break; | 226 | break; |
227 | 227 | ||
228 | case NAND_CTL_SETALE: | 228 | case NAND_CTL_SETALE: |
229 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE); | 229 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE); |
230 | break; | 230 | break; |
231 | case NAND_CTL_CLRALE: | 231 | case NAND_CTL_CLRALE: |
232 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE); | 232 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE); |
233 | break; | 233 | break; |
234 | 234 | ||
235 | case NAND_CTL_SETNCE: | 235 | case NAND_CTL_SETNCE: |
236 | break; | 236 | break; |
237 | case NAND_CTL_CLRNCE: | 237 | case NAND_CTL_CLRNCE: |
@@ -296,7 +296,7 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd) | |||
296 | * @mtd: MTD device structure | 296 | * @mtd: MTD device structure |
297 | * @chip: Chip to select (0 == slot 3, 1 == slot 4) | 297 | * @chip: Chip to select (0 == slot 3, 1 == slot 4) |
298 | * | 298 | * |
299 | * If there was a sudden loss of power during an erase operation, a | 299 | * If there was a sudden loss of power during an erase operation, a |
300 | * "device recovery" operation must be performed when power is restored | 300 | * "device recovery" operation must be performed when power is restored |
301 | * to ensure correct operation. This routine performs the required steps | 301 | * to ensure correct operation. This routine performs the required steps |
302 | * for the requested chip. | 302 | * for the requested chip. |
@@ -312,7 +312,7 @@ static void deplete(struct mtd_info *mtd, int chip) | |||
312 | while (!this->dev_ready(mtd)); | 312 | while (!this->dev_ready(mtd)); |
313 | 313 | ||
314 | this->select_chip(mtd, chip); | 314 | this->select_chip(mtd, chip); |
315 | 315 | ||
316 | /* Send the commands for device recovery, phase 1 */ | 316 | /* Send the commands for device recovery, phase 1 */ |
317 | this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); | 317 | this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); |
318 | this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); | 318 | this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); |
@@ -330,7 +330,7 @@ static void deplete(struct mtd_info *mtd, int chip) | |||
330 | * @mtd: MTD device structure | 330 | * @mtd: MTD device structure |
331 | * @mode: I/O mode; read or write | 331 | * @mode: I/O mode; read or write |
332 | * | 332 | * |
333 | * enable hardware ECC for data read or write | 333 | * enable hardware ECC for data read or write |
334 | * | 334 | * |
335 | */ | 335 | */ |
336 | static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | 336 | static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) |
@@ -340,7 +340,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | |||
340 | 340 | ||
341 | switch (mode) { | 341 | switch (mode) { |
342 | case NAND_ECC_READ : | 342 | case NAND_ECC_READ : |
343 | status = RTC_FROM4_RS_ECC_CTL_CLR | 343 | status = RTC_FROM4_RS_ECC_CTL_CLR |
344 | | RTC_FROM4_RS_ECC_CTL_FD_E; | 344 | | RTC_FROM4_RS_ECC_CTL_FD_E; |
345 | 345 | ||
346 | *rs_ecc_ctl = status; | 346 | *rs_ecc_ctl = status; |
@@ -353,8 +353,8 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) | |||
353 | break; | 353 | break; |
354 | 354 | ||
355 | case NAND_ECC_WRITE : | 355 | case NAND_ECC_WRITE : |
356 | status = RTC_FROM4_RS_ECC_CTL_CLR | 356 | status = RTC_FROM4_RS_ECC_CTL_CLR |
357 | | RTC_FROM4_RS_ECC_CTL_GEN | 357 | | RTC_FROM4_RS_ECC_CTL_GEN |
358 | | RTC_FROM4_RS_ECC_CTL_FD_E; | 358 | | RTC_FROM4_RS_ECC_CTL_FD_E; |
359 | 359 | ||
360 | *rs_ecc_ctl = status; | 360 | *rs_ecc_ctl = status; |
@@ -411,7 +411,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c | |||
411 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) | 411 | static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) |
412 | { | 412 | { |
413 | int i, j, res; | 413 | int i, j, res; |
414 | unsigned short status; | 414 | unsigned short status; |
415 | uint16_t par[6], syn[6]; | 415 | uint16_t par[6], syn[6]; |
416 | uint8_t ecc[8]; | 416 | uint8_t ecc[8]; |
417 | volatile unsigned short *rs_ecc; | 417 | volatile unsigned short *rs_ecc; |
@@ -430,7 +430,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
430 | } | 430 | } |
431 | 431 | ||
432 | /* convert into 6 10bit syndrome fields */ | 432 | /* convert into 6 10bit syndrome fields */ |
433 | par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | | 433 | par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | |
434 | (((uint16_t)ecc[1] << 8) & 0x300)]; | 434 | (((uint16_t)ecc[1] << 8) & 0x300)]; |
435 | par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) | | 435 | par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) | |
436 | (((uint16_t)ecc[2] << 6) & 0x3c0)]; | 436 | (((uint16_t)ecc[2] << 6) & 0x3c0)]; |
@@ -456,7 +456,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
456 | /* Let the library code do its magic.*/ | 456 | /* Let the library code do its magic.*/ |
457 | res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); | 457 | res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); |
458 | if (res > 0) { | 458 | if (res > 0) { |
459 | DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " | 459 | DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " |
460 | "ECC corrected %d errors on read\n", res); | 460 | "ECC corrected %d errors on read\n", res); |
461 | } | 461 | } |
462 | return res; | 462 | return res; |
@@ -470,9 +470,9 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha | |||
470 | * @state: state or the operation | 470 | * @state: state or the operation |
471 | * @status: status code returned from read status | 471 | * @status: status code returned from read status |
472 | * @page: startpage inside the chip, must be called with (page & this->pagemask) | 472 | * @page: startpage inside the chip, must be called with (page & this->pagemask) |
473 | * | 473 | * |
474 | * Perform additional error status checks on erase and write failures | 474 | * Perform additional error status checks on erase and write failures |
475 | * to determine if errors are correctable. For this device, correctable | 475 | * to determine if errors are correctable. For this device, correctable |
476 | * 1-bit errors on erase and write are considered acceptable. | 476 | * 1-bit errors on erase and write are considered acceptable. |
477 | * | 477 | * |
478 | * note: see pages 34..37 of data sheet for details. | 478 | * note: see pages 34..37 of data sheet for details. |
@@ -633,7 +633,7 @@ int __init rtc_from4_init (void) | |||
633 | 633 | ||
634 | #ifdef RTC_FROM4_HWECC | 634 | #ifdef RTC_FROM4_HWECC |
635 | /* We could create the decoder on demand, if memory is a concern. | 635 | /* We could create the decoder on demand, if memory is a concern. |
636 | * This way we have it handy, if an error happens | 636 | * This way we have it handy, if an error happens |
637 | * | 637 | * |
638 | * Symbolsize is 10 (bits) | 638 | * Symbolsize is 10 (bits) |
639 | * Primitve polynomial is x^10+x^3+1 | 639 | * Primitve polynomial is x^10+x^3+1 |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 2df5e47d1f5c..97e9b7892d29 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -17,8 +17,9 @@ | |||
17 | * 02-May-2005 BJD Reduced hwcontrol decode | 17 | * 02-May-2005 BJD Reduced hwcontrol decode |
18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug | 18 | * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug |
19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied | 19 | * 08-Jul-2005 BJD Fix OOPS when no platform data supplied |
20 | * 20-Oct-2005 BJD Fix timing calculation bug | ||
20 | * | 21 | * |
21 | * $Id: s3c2410.c,v 1.14 2005/07/06 20:05:06 bjd Exp $ | 22 | * $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 gleixner Exp $ |
22 | * | 23 | * |
23 | * This program is free software; you can redistribute it and/or modify | 24 | * This program is free software; you can redistribute it and/or modify |
24 | * it under the terms of the GNU General Public License as published by | 25 | * it under the terms of the GNU General Public License as published by |
@@ -136,13 +137,13 @@ static struct s3c2410_platform_nand *to_nand_plat(struct device *dev) | |||
136 | 137 | ||
137 | /* timing calculations */ | 138 | /* timing calculations */ |
138 | 139 | ||
139 | #define NS_IN_KHZ 10000000 | 140 | #define NS_IN_KHZ 1000000 |
140 | 141 | ||
141 | static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) | 142 | static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) |
142 | { | 143 | { |
143 | int result; | 144 | int result; |
144 | 145 | ||
145 | result = (wanted * NS_IN_KHZ) / clk; | 146 | result = (wanted * clk) / NS_IN_KHZ; |
146 | result++; | 147 | result++; |
147 | 148 | ||
148 | pr_debug("result %d from %ld, %d\n", result, clk, wanted); | 149 | pr_debug("result %d from %ld, %d\n", result, clk, wanted); |
@@ -159,20 +160,22 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) | |||
159 | return result; | 160 | return result; |
160 | } | 161 | } |
161 | 162 | ||
162 | #define to_ns(ticks,clk) (((clk) * (ticks)) / NS_IN_KHZ) | 163 | #define to_ns(ticks,clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk)) |
163 | 164 | ||
164 | /* controller setup */ | 165 | /* controller setup */ |
165 | 166 | ||
166 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | 167 | static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, |
167 | struct device *dev) | 168 | struct device *dev) |
168 | { | 169 | { |
169 | struct s3c2410_platform_nand *plat = to_nand_plat(dev); | 170 | struct s3c2410_platform_nand *plat = to_nand_plat(dev); |
170 | unsigned int tacls, twrph0, twrph1; | ||
171 | unsigned long clkrate = clk_get_rate(info->clk); | 171 | unsigned long clkrate = clk_get_rate(info->clk); |
172 | int tacls, twrph0, twrph1; | ||
172 | unsigned long cfg; | 173 | unsigned long cfg; |
173 | 174 | ||
174 | /* calculate the timing information for the controller */ | 175 | /* calculate the timing information for the controller */ |
175 | 176 | ||
177 | clkrate /= 1000; /* turn clock into kHz for ease of use */ | ||
178 | |||
176 | if (plat != NULL) { | 179 | if (plat != NULL) { |
177 | tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); | 180 | tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); |
178 | twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); | 181 | twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); |
@@ -183,16 +186,16 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | |||
183 | twrph0 = 8; | 186 | twrph0 = 8; |
184 | twrph1 = 8; | 187 | twrph1 = 8; |
185 | } | 188 | } |
186 | 189 | ||
187 | if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { | 190 | if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { |
188 | printk(KERN_ERR PFX "cannot get timings suitable for board\n"); | 191 | printk(KERN_ERR PFX "cannot get timings suitable for board\n"); |
189 | return -EINVAL; | 192 | return -EINVAL; |
190 | } | 193 | } |
191 | 194 | ||
192 | printk(KERN_INFO PFX "timing: Tacls %ldns, Twrph0 %ldns, Twrph1 %ldns\n", | 195 | printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", |
193 | to_ns(tacls, clkrate), | 196 | tacls, to_ns(tacls, clkrate), |
194 | to_ns(twrph0, clkrate), | 197 | twrph0, to_ns(twrph0, clkrate), |
195 | to_ns(twrph1, clkrate)); | 198 | twrph1, to_ns(twrph1, clkrate)); |
196 | 199 | ||
197 | if (!info->is_s3c2440) { | 200 | if (!info->is_s3c2440) { |
198 | cfg = S3C2410_NFCONF_EN; | 201 | cfg = S3C2410_NFCONF_EN; |
@@ -216,7 +219,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, | |||
216 | static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | 219 | static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) |
217 | { | 220 | { |
218 | struct s3c2410_nand_info *info; | 221 | struct s3c2410_nand_info *info; |
219 | struct s3c2410_nand_mtd *nmtd; | 222 | struct s3c2410_nand_mtd *nmtd; |
220 | struct nand_chip *this = mtd->priv; | 223 | struct nand_chip *this = mtd->priv; |
221 | void __iomem *reg; | 224 | void __iomem *reg; |
222 | unsigned long cur; | 225 | unsigned long cur; |
@@ -249,7 +252,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
249 | writel(cur, reg); | 252 | writel(cur, reg); |
250 | } | 253 | } |
251 | 254 | ||
252 | /* command and control functions | 255 | /* command and control functions |
253 | * | 256 | * |
254 | * Note, these all use tglx's method of changing the IO_ADDR_W field | 257 | * Note, these all use tglx's method of changing the IO_ADDR_W field |
255 | * to make the code simpler, and use the nand layer's code to issue the | 258 | * to make the code simpler, and use the nand layer's code to issue the |
@@ -321,7 +324,7 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) | |||
321 | static int s3c2410_nand_devready(struct mtd_info *mtd) | 324 | static int s3c2410_nand_devready(struct mtd_info *mtd) |
322 | { | 325 | { |
323 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 326 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
324 | 327 | ||
325 | if (info->is_s3c2440) | 328 | if (info->is_s3c2440) |
326 | return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; | 329 | return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; |
327 | return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; | 330 | return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; |
@@ -342,7 +345,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
342 | 345 | ||
343 | if (read_ecc[0] == calc_ecc[0] && | 346 | if (read_ecc[0] == calc_ecc[0] && |
344 | read_ecc[1] == calc_ecc[1] && | 347 | read_ecc[1] == calc_ecc[1] && |
345 | read_ecc[2] == calc_ecc[2]) | 348 | read_ecc[2] == calc_ecc[2]) |
346 | return 0; | 349 | return 0; |
347 | 350 | ||
348 | /* we curently have no method for correcting the error */ | 351 | /* we curently have no method for correcting the error */ |
@@ -433,14 +436,14 @@ static int s3c2410_nand_remove(struct device *dev) | |||
433 | 436 | ||
434 | dev_set_drvdata(dev, NULL); | 437 | dev_set_drvdata(dev, NULL); |
435 | 438 | ||
436 | if (info == NULL) | 439 | if (info == NULL) |
437 | return 0; | 440 | return 0; |
438 | 441 | ||
439 | /* first thing we need to do is release all our mtds | 442 | /* first thing we need to do is release all our mtds |
440 | * and their partitions, then go through freeing the | 443 | * and their partitions, then go through freeing the |
441 | * resources used | 444 | * resources used |
442 | */ | 445 | */ |
443 | 446 | ||
444 | if (info->mtds != NULL) { | 447 | if (info->mtds != NULL) { |
445 | struct s3c2410_nand_mtd *ptr = info->mtds; | 448 | struct s3c2410_nand_mtd *ptr = info->mtds; |
446 | int mtdno; | 449 | int mtdno; |
@@ -504,7 +507,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | |||
504 | 507 | ||
505 | /* s3c2410_nand_init_chip | 508 | /* s3c2410_nand_init_chip |
506 | * | 509 | * |
507 | * init a single instance of an chip | 510 | * init a single instance of an chip |
508 | */ | 511 | */ |
509 | 512 | ||
510 | static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | 513 | static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, |
@@ -576,7 +579,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
576 | 579 | ||
577 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 580 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
578 | if (info == NULL) { | 581 | if (info == NULL) { |
579 | printk(KERN_ERR PFX "no memory for flash info\n"); | 582 | dev_err(dev, "no memory for flash info\n"); |
580 | err = -ENOMEM; | 583 | err = -ENOMEM; |
581 | goto exit_error; | 584 | goto exit_error; |
582 | } | 585 | } |
@@ -591,7 +594,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
591 | 594 | ||
592 | info->clk = clk_get(dev, "nand"); | 595 | info->clk = clk_get(dev, "nand"); |
593 | if (IS_ERR(info->clk)) { | 596 | if (IS_ERR(info->clk)) { |
594 | printk(KERN_ERR PFX "failed to get clock"); | 597 | dev_err(dev, "failed to get clock"); |
595 | err = -ENOENT; | 598 | err = -ENOENT; |
596 | goto exit_error; | 599 | goto exit_error; |
597 | } | 600 | } |
@@ -608,7 +611,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
608 | info->area = request_mem_region(res->start, size, pdev->name); | 611 | info->area = request_mem_region(res->start, size, pdev->name); |
609 | 612 | ||
610 | if (info->area == NULL) { | 613 | if (info->area == NULL) { |
611 | printk(KERN_ERR PFX "cannot reserve register region\n"); | 614 | dev_err(dev, "cannot reserve register region\n"); |
612 | err = -ENOENT; | 615 | err = -ENOENT; |
613 | goto exit_error; | 616 | goto exit_error; |
614 | } | 617 | } |
@@ -619,12 +622,12 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
619 | info->is_s3c2440 = is_s3c2440; | 622 | info->is_s3c2440 = is_s3c2440; |
620 | 623 | ||
621 | if (info->regs == NULL) { | 624 | if (info->regs == NULL) { |
622 | printk(KERN_ERR PFX "cannot reserve register region\n"); | 625 | dev_err(dev, "cannot reserve register region\n"); |
623 | err = -EIO; | 626 | err = -EIO; |
624 | goto exit_error; | 627 | goto exit_error; |
625 | } | 628 | } |
626 | 629 | ||
627 | printk(KERN_INFO PFX "mapped registers at %p\n", info->regs); | 630 | dev_dbg(dev, "mapped registers at %p\n", info->regs); |
628 | 631 | ||
629 | /* initialise the hardware */ | 632 | /* initialise the hardware */ |
630 | 633 | ||
@@ -642,7 +645,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
642 | size = nr_sets * sizeof(*info->mtds); | 645 | size = nr_sets * sizeof(*info->mtds); |
643 | info->mtds = kmalloc(size, GFP_KERNEL); | 646 | info->mtds = kmalloc(size, GFP_KERNEL); |
644 | if (info->mtds == NULL) { | 647 | if (info->mtds == NULL) { |
645 | printk(KERN_ERR PFX "failed to allocate mtd storage\n"); | 648 | dev_err(dev, "failed to allocate mtd storage\n"); |
646 | err = -ENOMEM; | 649 | err = -ENOMEM; |
647 | goto exit_error; | 650 | goto exit_error; |
648 | } | 651 | } |
@@ -656,7 +659,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
656 | for (setno = 0; setno < nr_sets; setno++, nmtd++) { | 659 | for (setno = 0; setno < nr_sets; setno++, nmtd++) { |
657 | pr_debug("initialising set %d (%p, info %p)\n", | 660 | pr_debug("initialising set %d (%p, info %p)\n", |
658 | setno, nmtd, info); | 661 | setno, nmtd, info); |
659 | 662 | ||
660 | s3c2410_nand_init_chip(info, nmtd, sets); | 663 | s3c2410_nand_init_chip(info, nmtd, sets); |
661 | 664 | ||
662 | nmtd->scan_res = nand_scan(&nmtd->mtd, | 665 | nmtd->scan_res = nand_scan(&nmtd->mtd, |
@@ -669,7 +672,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) | |||
669 | if (sets != NULL) | 672 | if (sets != NULL) |
670 | sets++; | 673 | sets++; |
671 | } | 674 | } |
672 | 675 | ||
673 | pr_debug("initialised ok\n"); | 676 | pr_debug("initialised ok\n"); |
674 | return 0; | 677 | return 0; |
675 | 678 | ||
@@ -695,6 +698,7 @@ static int s3c2440_nand_probe(struct device *dev) | |||
695 | 698 | ||
696 | static struct device_driver s3c2410_nand_driver = { | 699 | static struct device_driver s3c2410_nand_driver = { |
697 | .name = "s3c2410-nand", | 700 | .name = "s3c2410-nand", |
701 | .owner = THIS_MODULE, | ||
698 | .bus = &platform_bus_type, | 702 | .bus = &platform_bus_type, |
699 | .probe = s3c2410_nand_probe, | 703 | .probe = s3c2410_nand_probe, |
700 | .remove = s3c2410_nand_remove, | 704 | .remove = s3c2410_nand_remove, |
@@ -702,6 +706,7 @@ static struct device_driver s3c2410_nand_driver = { | |||
702 | 706 | ||
703 | static struct device_driver s3c2440_nand_driver = { | 707 | static struct device_driver s3c2440_nand_driver = { |
704 | .name = "s3c2440-nand", | 708 | .name = "s3c2440-nand", |
709 | .owner = THIS_MODULE, | ||
705 | .bus = &platform_bus_type, | 710 | .bus = &platform_bus_type, |
706 | .probe = s3c2440_nand_probe, | 711 | .probe = s3c2440_nand_probe, |
707 | .remove = s3c2410_nand_remove, | 712 | .remove = s3c2410_nand_remove, |
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 88b5b5b40b43..1924a4f137c7 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2004 Richard Purdie | 4 | * Copyright (C) 2004 Richard Purdie |
5 | * | 5 | * |
6 | * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $ | 6 | * $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ |
7 | * | 7 | * |
8 | * Based on Sharp's NAND driver sharp_sl.c | 8 | * Based on Sharp's NAND driver sharp_sl.c |
9 | * | 9 | * |
@@ -76,14 +76,14 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { | |||
76 | }, | 76 | }, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * hardware specific access to control-lines | 80 | * hardware specific access to control-lines |
81 | */ | 81 | */ |
82 | static void | 82 | static void |
83 | sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) | 83 | sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) |
84 | { | 84 | { |
85 | switch (cmd) { | 85 | switch (cmd) { |
86 | case NAND_CTL_SETCLE: | 86 | case NAND_CTL_SETCLE: |
87 | writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); | 87 | writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); |
88 | break; | 88 | break; |
89 | case NAND_CTL_CLRCLE: | 89 | case NAND_CTL_CLRCLE: |
@@ -97,10 +97,10 @@ sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) | |||
97 | writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); | 97 | writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); |
98 | break; | 98 | break; |
99 | 99 | ||
100 | case NAND_CTL_SETNCE: | 100 | case NAND_CTL_SETNCE: |
101 | writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL); | 101 | writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL); |
102 | break; | 102 | break; |
103 | case NAND_CTL_CLRNCE: | 103 | case NAND_CTL_CLRNCE: |
104 | writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL); | 104 | writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL); |
105 | break; | 105 | break; |
106 | } | 106 | } |
@@ -115,6 +115,23 @@ static struct nand_bbt_descr sharpsl_bbt = { | |||
115 | .pattern = scan_ff_pattern | 115 | .pattern = scan_ff_pattern |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static struct nand_bbt_descr sharpsl_akita_bbt = { | ||
119 | .options = 0, | ||
120 | .offs = 4, | ||
121 | .len = 1, | ||
122 | .pattern = scan_ff_pattern | ||
123 | }; | ||
124 | |||
125 | static struct nand_oobinfo akita_oobinfo = { | ||
126 | .useecc = MTD_NANDECC_AUTOPLACE, | ||
127 | .eccbytes = 24, | ||
128 | .eccpos = { | ||
129 | 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, | ||
130 | 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, | ||
131 | 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, | ||
132 | .oobfree = { {0x08, 0x09} } | ||
133 | }; | ||
134 | |||
118 | static int | 135 | static int |
119 | sharpsl_nand_dev_ready(struct mtd_info* mtd) | 136 | sharpsl_nand_dev_ready(struct mtd_info* mtd) |
120 | { | 137 | { |
@@ -160,7 +177,7 @@ sharpsl_nand_init(void) | |||
160 | printk ("Unable to allocate SharpSL NAND MTD device structure.\n"); | 177 | printk ("Unable to allocate SharpSL NAND MTD device structure.\n"); |
161 | return -ENOMEM; | 178 | return -ENOMEM; |
162 | } | 179 | } |
163 | 180 | ||
164 | /* map physical adress */ | 181 | /* map physical adress */ |
165 | sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); | 182 | sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); |
166 | if(!sharpsl_io_base){ | 183 | if(!sharpsl_io_base){ |
@@ -168,7 +185,7 @@ sharpsl_nand_init(void) | |||
168 | kfree(sharpsl_mtd); | 185 | kfree(sharpsl_mtd); |
169 | return -EIO; | 186 | return -EIO; |
170 | } | 187 | } |
171 | 188 | ||
172 | /* Get pointer to private data */ | 189 | /* Get pointer to private data */ |
173 | this = (struct nand_chip *) (&sharpsl_mtd[1]); | 190 | this = (struct nand_chip *) (&sharpsl_mtd[1]); |
174 | 191 | ||
@@ -194,10 +211,14 @@ sharpsl_nand_init(void) | |||
194 | this->chip_delay = 15; | 211 | this->chip_delay = 15; |
195 | /* set eccmode using hardware ECC */ | 212 | /* set eccmode using hardware ECC */ |
196 | this->eccmode = NAND_ECC_HW3_256; | 213 | this->eccmode = NAND_ECC_HW3_256; |
214 | this->badblock_pattern = &sharpsl_bbt; | ||
215 | if (machine_is_akita() || machine_is_borzoi()) { | ||
216 | this->badblock_pattern = &sharpsl_akita_bbt; | ||
217 | this->autooob = &akita_oobinfo; | ||
218 | } | ||
197 | this->enable_hwecc = sharpsl_nand_enable_hwecc; | 219 | this->enable_hwecc = sharpsl_nand_enable_hwecc; |
198 | this->calculate_ecc = sharpsl_nand_calculate_ecc; | 220 | this->calculate_ecc = sharpsl_nand_calculate_ecc; |
199 | this->correct_data = nand_correct_data; | 221 | this->correct_data = nand_correct_data; |
200 | this->badblock_pattern = &sharpsl_bbt; | ||
201 | 222 | ||
202 | /* Scan to find existence of the device */ | 223 | /* Scan to find existence of the device */ |
203 | err=nand_scan(sharpsl_mtd,1); | 224 | err=nand_scan(sharpsl_mtd,1); |
@@ -211,7 +232,7 @@ sharpsl_nand_init(void) | |||
211 | sharpsl_mtd->name = "sharpsl-nand"; | 232 | sharpsl_mtd->name = "sharpsl-nand"; |
212 | nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, | 233 | nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, |
213 | &sharpsl_partition_info, 0); | 234 | &sharpsl_partition_info, 0); |
214 | 235 | ||
215 | if (nr_partitions <= 0) { | 236 | if (nr_partitions <= 0) { |
216 | nr_partitions = DEFAULT_NUM_PARTITIONS; | 237 | nr_partitions = DEFAULT_NUM_PARTITIONS; |
217 | sharpsl_partition_info = sharpsl_nand_default_partition_info; | 238 | sharpsl_partition_info = sharpsl_nand_default_partition_info; |
@@ -230,7 +251,7 @@ sharpsl_nand_init(void) | |||
230 | } | 251 | } |
231 | } | 252 | } |
232 | 253 | ||
233 | if (machine_is_husky() || machine_is_borzoi()) { | 254 | if (machine_is_husky() || machine_is_borzoi() || machine_is_akita()) { |
234 | /* Need to use small eraseblock size for backward compatibility */ | 255 | /* Need to use small eraseblock size for backward compatibility */ |
235 | sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; | 256 | sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; |
236 | } | 257 | } |
diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index b777c412b758..32541cbb0103 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * to controllines (due to change in nand.c) | 8 | * to controllines (due to change in nand.c) |
9 | * page_cache added | 9 | * page_cache added |
10 | * | 10 | * |
11 | * $Id: spia.c,v 1.24 2004/11/04 12:53:10 gleixner Exp $ | 11 | * $Id: spia.c,v 1.25 2005/11/07 11:14:31 gleixner Exp $ |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
@@ -82,7 +82,7 @@ const static struct mtd_partition partition_info[] = { | |||
82 | #define NUM_PARTITIONS 2 | 82 | #define NUM_PARTITIONS 2 |
83 | 83 | ||
84 | 84 | ||
85 | /* | 85 | /* |
86 | * hardware specific access to control-lines | 86 | * hardware specific access to control-lines |
87 | */ | 87 | */ |
88 | static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ | 88 | static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ |
@@ -137,7 +137,7 @@ int __init spia_init (void) | |||
137 | /* Set address of hardware control function */ | 137 | /* Set address of hardware control function */ |
138 | this->hwcontrol = spia_hwcontrol; | 138 | this->hwcontrol = spia_hwcontrol; |
139 | /* 15 us command delay time */ | 139 | /* 15 us command delay time */ |
140 | this->chip_delay = 15; | 140 | this->chip_delay = 15; |
141 | 141 | ||
142 | /* Scan to find existence of the device */ | 142 | /* Scan to find existence of the device */ |
143 | if (nand_scan (spia_mtd, 1)) { | 143 | if (nand_scan (spia_mtd, 1)) { |
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index 52c808fb5fa9..7609c43cb3ec 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * This is a device driver for the NAND flash device found on the | 15 | * This is a device driver for the NAND flash device found on the |
16 | * TI fido board. It supports 32MiB and 64MiB cards | 16 | * TI fido board. It supports 32MiB and 64MiB cards |
17 | * | 17 | * |
18 | * $Id: toto.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ | 18 | * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $ |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
@@ -57,7 +57,7 @@ static unsigned long toto_io_base = OMAP_FLASH_1_BASE; | |||
57 | #endif | 57 | #endif |
58 | #define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0) | 58 | #define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0) |
59 | #define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE) | 59 | #define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE) |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * Define partitions for flash devices | 62 | * Define partitions for flash devices |
63 | */ | 63 | */ |
@@ -91,7 +91,7 @@ static struct mtd_partition partition_info32M[] = { | |||
91 | 91 | ||
92 | #define NUM_PARTITIONS32M 3 | 92 | #define NUM_PARTITIONS32M 3 |
93 | #define NUM_PARTITIONS64M 4 | 93 | #define NUM_PARTITIONS64M 4 |
94 | /* | 94 | /* |
95 | * hardware specific access to control-lines | 95 | * hardware specific access to control-lines |
96 | */ | 96 | */ |
97 | 97 | ||
@@ -146,7 +146,7 @@ int __init toto_init (void) | |||
146 | this->hwcontrol = toto_hwcontrol; | 146 | this->hwcontrol = toto_hwcontrol; |
147 | this->dev_ready = NULL; | 147 | this->dev_ready = NULL; |
148 | /* 25 us command delay time */ | 148 | /* 25 us command delay time */ |
149 | this->chip_delay = 30; | 149 | this->chip_delay = 30; |
150 | this->eccmode = NAND_ECC_SOFT; | 150 | this->eccmode = NAND_ECC_SOFT; |
151 | 151 | ||
152 | /* Scan to find existance of the device */ | 152 | /* Scan to find existance of the device */ |
@@ -157,10 +157,10 @@ int __init toto_init (void) | |||
157 | 157 | ||
158 | /* Register the partitions */ | 158 | /* Register the partitions */ |
159 | switch(toto_mtd->size){ | 159 | switch(toto_mtd->size){ |
160 | case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; | 160 | case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; |
161 | case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; | 161 | case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; |
162 | default: { | 162 | default: { |
163 | printk (KERN_WARNING "Unsupported Nand device\n"); | 163 | printk (KERN_WARNING "Unsupported Nand device\n"); |
164 | err = -ENXIO; | 164 | err = -ENXIO; |
165 | goto out_buf; | 165 | goto out_buf; |
166 | } | 166 | } |
@@ -170,9 +170,9 @@ int __init toto_init (void) | |||
170 | archflashwp(0,0); /* open up flash for writing */ | 170 | archflashwp(0,0); /* open up flash for writing */ |
171 | 171 | ||
172 | goto out; | 172 | goto out; |
173 | 173 | ||
174 | out_buf: | 174 | out_buf: |
175 | kfree (this->data_buf); | 175 | kfree (this->data_buf); |
176 | out_mtd: | 176 | out_mtd: |
177 | kfree (toto_mtd); | 177 | kfree (toto_mtd); |
178 | out: | 178 | out: |
@@ -194,7 +194,7 @@ static void __exit toto_cleanup (void) | |||
194 | 194 | ||
195 | /* stop flash writes */ | 195 | /* stop flash writes */ |
196 | archflashwp(0,1); | 196 | archflashwp(0,1); |
197 | 197 | ||
198 | /* release gpios to system */ | 198 | /* release gpios to system */ |
199 | gpiorelease(NAND_MASK); | 199 | gpiorelease(NAND_MASK); |
200 | } | 200 | } |
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 062ff3877536..d7cd5fa16ba4 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* Linux driver for NAND Flash Translation Layer */ | 1 | /* Linux driver for NAND Flash Translation Layer */ |
2 | /* (c) 1999 Machine Vision Holdings, Inc. */ | 2 | /* (c) 1999 Machine Vision Holdings, Inc. */ |
3 | /* Author: David Woodhouse <dwmw2@infradead.org> */ | 3 | /* Author: David Woodhouse <dwmw2@infradead.org> */ |
4 | /* $Id: nftlcore.c,v 1.97 2004/11/16 18:28:59 dwmw2 Exp $ */ | 4 | /* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */ |
5 | 5 | ||
6 | /* | 6 | /* |
7 | The contents of this file are distributed under the GNU General | 7 | The contents of this file are distributed under the GNU General |
@@ -101,14 +101,14 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
101 | 101 | ||
102 | if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { | 102 | if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { |
103 | /* | 103 | /* |
104 | Oh no we don't have | 104 | Oh no we don't have |
105 | mbd.size == heads * cylinders * sectors | 105 | mbd.size == heads * cylinders * sectors |
106 | */ | 106 | */ |
107 | printk(KERN_WARNING "NFTL: cannot calculate a geometry to " | 107 | printk(KERN_WARNING "NFTL: cannot calculate a geometry to " |
108 | "match size of 0x%lx.\n", nftl->mbd.size); | 108 | "match size of 0x%lx.\n", nftl->mbd.size); |
109 | printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " | 109 | printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " |
110 | "(== 0x%lx sects)\n", | 110 | "(== 0x%lx sects)\n", |
111 | nftl->cylinders, nftl->heads , nftl->sectors, | 111 | nftl->cylinders, nftl->heads , nftl->sectors, |
112 | (long)nftl->cylinders * (long)nftl->heads * | 112 | (long)nftl->cylinders * (long)nftl->heads * |
113 | (long)nftl->sectors ); | 113 | (long)nftl->sectors ); |
114 | } | 114 | } |
@@ -174,7 +174,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) | |||
174 | 174 | ||
175 | if (!silly--) { | 175 | if (!silly--) { |
176 | printk("Argh! No free blocks found! LastFreeEUN = %d, " | 176 | printk("Argh! No free blocks found! LastFreeEUN = %d, " |
177 | "FirstEUN = %d\n", nftl->LastFreeEUN, | 177 | "FirstEUN = %d\n", nftl->LastFreeEUN, |
178 | le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN)); | 178 | le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN)); |
179 | return 0xffff; | 179 | return 0xffff; |
180 | } | 180 | } |
@@ -206,7 +206,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
206 | "Virtual Unit Chain %d!\n", thisVUC); | 206 | "Virtual Unit Chain %d!\n", thisVUC); |
207 | return BLOCK_NIL; | 207 | return BLOCK_NIL; |
208 | } | 208 | } |
209 | 209 | ||
210 | /* Scan to find the Erase Unit which holds the actual data for each | 210 | /* Scan to find the Erase Unit which holds the actual data for each |
211 | 512-byte block within the Chain. | 211 | 512-byte block within the Chain. |
212 | */ | 212 | */ |
@@ -223,7 +223,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
223 | if (block == 2) { | 223 | if (block == 2) { |
224 | foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; | 224 | foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; |
225 | if (foldmark == FOLD_MARK_IN_PROGRESS) { | 225 | if (foldmark == FOLD_MARK_IN_PROGRESS) { |
226 | DEBUG(MTD_DEBUG_LEVEL1, | 226 | DEBUG(MTD_DEBUG_LEVEL1, |
227 | "Write Inhibited on EUN %d\n", thisEUN); | 227 | "Write Inhibited on EUN %d\n", thisEUN); |
228 | inplace = 0; | 228 | inplace = 0; |
229 | } else { | 229 | } else { |
@@ -245,7 +245,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
245 | if (!BlockFreeFound[block]) | 245 | if (!BlockFreeFound[block]) |
246 | BlockMap[block] = thisEUN; | 246 | BlockMap[block] = thisEUN; |
247 | else | 247 | else |
248 | printk(KERN_WARNING | 248 | printk(KERN_WARNING |
249 | "SECTOR_USED found after SECTOR_FREE " | 249 | "SECTOR_USED found after SECTOR_FREE " |
250 | "in Virtual Unit Chain %d for block %d\n", | 250 | "in Virtual Unit Chain %d for block %d\n", |
251 | thisVUC, block); | 251 | thisVUC, block); |
@@ -254,7 +254,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
254 | if (!BlockFreeFound[block]) | 254 | if (!BlockFreeFound[block]) |
255 | BlockMap[block] = BLOCK_NIL; | 255 | BlockMap[block] = BLOCK_NIL; |
256 | else | 256 | else |
257 | printk(KERN_WARNING | 257 | printk(KERN_WARNING |
258 | "SECTOR_DELETED found after SECTOR_FREE " | 258 | "SECTOR_DELETED found after SECTOR_FREE " |
259 | "in Virtual Unit Chain %d for block %d\n", | 259 | "in Virtual Unit Chain %d for block %d\n", |
260 | thisVUC, block); | 260 | thisVUC, block); |
@@ -273,14 +273,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
273 | thisVUC); | 273 | thisVUC); |
274 | return BLOCK_NIL; | 274 | return BLOCK_NIL; |
275 | } | 275 | } |
276 | 276 | ||
277 | thisEUN = nftl->ReplUnitTable[thisEUN]; | 277 | thisEUN = nftl->ReplUnitTable[thisEUN]; |
278 | } | 278 | } |
279 | 279 | ||
280 | if (inplace) { | 280 | if (inplace) { |
281 | /* We're being asked to be a fold-in-place. Check | 281 | /* We're being asked to be a fold-in-place. Check |
282 | that all blocks which actually have data associated | 282 | that all blocks which actually have data associated |
283 | with them (i.e. BlockMap[block] != BLOCK_NIL) are | 283 | with them (i.e. BlockMap[block] != BLOCK_NIL) are |
284 | either already present or SECTOR_FREE in the target | 284 | either already present or SECTOR_FREE in the target |
285 | block. If not, we're going to have to fold out-of-place | 285 | block. If not, we're going to have to fold out-of-place |
286 | anyway. | 286 | anyway. |
@@ -293,7 +293,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
293 | "block %d was %x lastEUN, " | 293 | "block %d was %x lastEUN, " |
294 | "and is in EUN %d (%s) %d\n", | 294 | "and is in EUN %d (%s) %d\n", |
295 | thisVUC, block, BlockLastState[block], | 295 | thisVUC, block, BlockLastState[block], |
296 | BlockMap[block], | 296 | BlockMap[block], |
297 | BlockMap[block]== targetEUN ? "==" : "!=", | 297 | BlockMap[block]== targetEUN ? "==" : "!=", |
298 | targetEUN); | 298 | targetEUN); |
299 | inplace = 0; | 299 | inplace = 0; |
@@ -310,17 +310,17 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
310 | inplace = 0; | 310 | inplace = 0; |
311 | } | 311 | } |
312 | } | 312 | } |
313 | 313 | ||
314 | if (!inplace) { | 314 | if (!inplace) { |
315 | DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " | 315 | DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " |
316 | "Trying out-of-place\n", thisVUC); | 316 | "Trying out-of-place\n", thisVUC); |
317 | /* We need to find a targetEUN to fold into. */ | 317 | /* We need to find a targetEUN to fold into. */ |
318 | targetEUN = NFTL_findfreeblock(nftl, 1); | 318 | targetEUN = NFTL_findfreeblock(nftl, 1); |
319 | if (targetEUN == BLOCK_NIL) { | 319 | if (targetEUN == BLOCK_NIL) { |
320 | /* Ouch. Now we're screwed. We need to do a | 320 | /* Ouch. Now we're screwed. We need to do a |
321 | fold-in-place of another chain to make room | 321 | fold-in-place of another chain to make room |
322 | for this one. We need a better way of selecting | 322 | for this one. We need a better way of selecting |
323 | which chain to fold, because makefreeblock will | 323 | which chain to fold, because makefreeblock will |
324 | only ask us to fold the same one again. | 324 | only ask us to fold the same one again. |
325 | */ | 325 | */ |
326 | printk(KERN_WARNING | 326 | printk(KERN_WARNING |
@@ -334,7 +334,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
334 | chain by selecting the longer one */ | 334 | chain by selecting the longer one */ |
335 | oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); | 335 | oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); |
336 | oob.u.c.unused = 0xffffffff; | 336 | oob.u.c.unused = 0xffffffff; |
337 | MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, | 337 | MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, |
338 | 8, &retlen, (char *)&oob.u); | 338 | 8, &retlen, (char *)&oob.u); |
339 | } | 339 | } |
340 | 340 | ||
@@ -357,14 +357,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
357 | happen in case of media errors or deleted blocks) */ | 357 | happen in case of media errors or deleted blocks) */ |
358 | if (BlockMap[block] == BLOCK_NIL) | 358 | if (BlockMap[block] == BLOCK_NIL) |
359 | continue; | 359 | continue; |
360 | 360 | ||
361 | ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), | 361 | ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), |
362 | 512, &retlen, movebuf); | 362 | 512, &retlen, movebuf); |
363 | if (ret < 0) { | 363 | if (ret < 0) { |
364 | ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) | 364 | ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) |
365 | + (block * 512), 512, &retlen, | 365 | + (block * 512), 512, &retlen, |
366 | movebuf); | 366 | movebuf); |
367 | if (ret != -EIO) | 367 | if (ret != -EIO) |
368 | printk("Error went away on retry.\n"); | 368 | printk("Error went away on retry.\n"); |
369 | } | 369 | } |
370 | memset(&oob, 0xff, sizeof(struct nftl_oob)); | 370 | memset(&oob, 0xff, sizeof(struct nftl_oob)); |
@@ -372,18 +372,18 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
372 | MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), | 372 | MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), |
373 | 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo); | 373 | 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo); |
374 | } | 374 | } |
375 | 375 | ||
376 | /* add the header so that it is now a valid chain */ | 376 | /* add the header so that it is now a valid chain */ |
377 | oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum | 377 | oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum |
378 | = cpu_to_le16(thisVUC); | 378 | = cpu_to_le16(thisVUC); |
379 | oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; | 379 | oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; |
380 | 380 | ||
381 | MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, | 381 | MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, |
382 | 8, &retlen, (char *)&oob.u); | 382 | 8, &retlen, (char *)&oob.u); |
383 | 383 | ||
384 | /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ | 384 | /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ |
385 | 385 | ||
386 | /* At this point, we have two different chains for this Virtual Unit, and no way to tell | 386 | /* At this point, we have two different chains for this Virtual Unit, and no way to tell |
387 | them apart. If we crash now, we get confused. However, both contain the same data, so we | 387 | them apart. If we crash now, we get confused. However, both contain the same data, so we |
388 | shouldn't actually lose data in this case. It's just that when we load up on a medium which | 388 | shouldn't actually lose data in this case. It's just that when we load up on a medium which |
389 | has duplicate chains, we need to free one of the chains because it's not necessary any more. | 389 | has duplicate chains, we need to free one of the chains because it's not necessary any more. |
@@ -391,7 +391,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
391 | thisEUN = nftl->EUNtable[thisVUC]; | 391 | thisEUN = nftl->EUNtable[thisVUC]; |
392 | DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); | 392 | DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); |
393 | 393 | ||
394 | /* For each block in the old chain (except the targetEUN of course), | 394 | /* For each block in the old chain (except the targetEUN of course), |
395 | free it and make it available for future use */ | 395 | free it and make it available for future use */ |
396 | while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) { | 396 | while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) { |
397 | unsigned int EUNtmp; | 397 | unsigned int EUNtmp; |
@@ -409,7 +409,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
409 | } | 409 | } |
410 | thisEUN = EUNtmp; | 410 | thisEUN = EUNtmp; |
411 | } | 411 | } |
412 | 412 | ||
413 | /* Make this the new start of chain for thisVUC */ | 413 | /* Make this the new start of chain for thisVUC */ |
414 | nftl->ReplUnitTable[targetEUN] = BLOCK_NIL; | 414 | nftl->ReplUnitTable[targetEUN] = BLOCK_NIL; |
415 | nftl->EUNtable[thisVUC] = targetEUN; | 415 | nftl->EUNtable[thisVUC] = targetEUN; |
@@ -419,7 +419,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p | |||
419 | 419 | ||
420 | static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) | 420 | static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) |
421 | { | 421 | { |
422 | /* This is the part that needs some cleverness applied. | 422 | /* This is the part that needs some cleverness applied. |
423 | For now, I'm doing the minimum applicable to actually | 423 | For now, I'm doing the minimum applicable to actually |
424 | get the thing to work. | 424 | get the thing to work. |
425 | Wear-levelling and other clever stuff needs to be implemented | 425 | Wear-levelling and other clever stuff needs to be implemented |
@@ -466,7 +466,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) | |||
466 | return NFTL_foldchain (nftl, LongestChain, pendingblock); | 466 | return NFTL_foldchain (nftl, LongestChain, pendingblock); |
467 | } | 467 | } |
468 | 468 | ||
469 | /* NFTL_findwriteunit: Return the unit number into which we can write | 469 | /* NFTL_findwriteunit: Return the unit number into which we can write |
470 | for this block. Make it available if it isn't already | 470 | for this block. Make it available if it isn't already |
471 | */ | 471 | */ |
472 | static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | 472 | static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) |
@@ -484,7 +484,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
484 | a free space for the block in question. | 484 | a free space for the block in question. |
485 | */ | 485 | */ |
486 | 486 | ||
487 | /* This condition catches the 0x[7f]fff cases, as well as | 487 | /* This condition catches the 0x[7f]fff cases, as well as |
488 | being a sanity check for past-end-of-media access | 488 | being a sanity check for past-end-of-media access |
489 | */ | 489 | */ |
490 | lastEUN = BLOCK_NIL; | 490 | lastEUN = BLOCK_NIL; |
@@ -499,7 +499,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
499 | 499 | ||
500 | MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, | 500 | MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, |
501 | 8, &retlen, (char *)&bci); | 501 | 8, &retlen, (char *)&bci); |
502 | 502 | ||
503 | DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", | 503 | DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", |
504 | block , writeEUN, le16_to_cpu(bci.Status)); | 504 | block , writeEUN, le16_to_cpu(bci.Status)); |
505 | 505 | ||
@@ -514,10 +514,10 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
514 | break; | 514 | break; |
515 | default: | 515 | default: |
516 | // Invalid block. Don't use it any more. Must implement. | 516 | // Invalid block. Don't use it any more. Must implement. |
517 | break; | 517 | break; |
518 | } | 518 | } |
519 | 519 | ||
520 | if (!silly--) { | 520 | if (!silly--) { |
521 | printk(KERN_WARNING | 521 | printk(KERN_WARNING |
522 | "Infinite loop in Virtual Unit Chain 0x%x\n", | 522 | "Infinite loop in Virtual Unit Chain 0x%x\n", |
523 | thisVUC); | 523 | thisVUC); |
@@ -528,7 +528,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
528 | writeEUN = nftl->ReplUnitTable[writeEUN]; | 528 | writeEUN = nftl->ReplUnitTable[writeEUN]; |
529 | } | 529 | } |
530 | 530 | ||
531 | /* OK. We didn't find one in the existing chain, or there | 531 | /* OK. We didn't find one in the existing chain, or there |
532 | is no existing chain. */ | 532 | is no existing chain. */ |
533 | 533 | ||
534 | /* Try to find an already-free block */ | 534 | /* Try to find an already-free block */ |
@@ -542,12 +542,12 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
542 | 542 | ||
543 | /* First remember the start of this chain */ | 543 | /* First remember the start of this chain */ |
544 | //u16 startEUN = nftl->EUNtable[thisVUC]; | 544 | //u16 startEUN = nftl->EUNtable[thisVUC]; |
545 | 545 | ||
546 | //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC); | 546 | //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC); |
547 | writeEUN = NFTL_makefreeblock(nftl, 0xffff); | 547 | writeEUN = NFTL_makefreeblock(nftl, 0xffff); |
548 | 548 | ||
549 | if (writeEUN == BLOCK_NIL) { | 549 | if (writeEUN == BLOCK_NIL) { |
550 | /* OK, we accept that the above comment is | 550 | /* OK, we accept that the above comment is |
551 | lying - there may have been free blocks | 551 | lying - there may have been free blocks |
552 | last time we called NFTL_findfreeblock(), | 552 | last time we called NFTL_findfreeblock(), |
553 | but they are reserved for when we're | 553 | but they are reserved for when we're |
@@ -558,21 +558,21 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) | |||
558 | } | 558 | } |
559 | if (writeEUN == BLOCK_NIL) { | 559 | if (writeEUN == BLOCK_NIL) { |
560 | /* Ouch. This should never happen - we should | 560 | /* Ouch. This should never happen - we should |
561 | always be able to make some room somehow. | 561 | always be able to make some room somehow. |
562 | If we get here, we've allocated more storage | 562 | If we get here, we've allocated more storage |
563 | space than actual media, or our makefreeblock | 563 | space than actual media, or our makefreeblock |
564 | routine is missing something. | 564 | routine is missing something. |
565 | */ | 565 | */ |
566 | printk(KERN_WARNING "Cannot make free space.\n"); | 566 | printk(KERN_WARNING "Cannot make free space.\n"); |
567 | return BLOCK_NIL; | 567 | return BLOCK_NIL; |
568 | } | 568 | } |
569 | //printk("Restarting scan\n"); | 569 | //printk("Restarting scan\n"); |
570 | lastEUN = BLOCK_NIL; | 570 | lastEUN = BLOCK_NIL; |
571 | continue; | 571 | continue; |
572 | } | 572 | } |
573 | 573 | ||
574 | /* We've found a free block. Insert it into the chain. */ | 574 | /* We've found a free block. Insert it into the chain. */ |
575 | 575 | ||
576 | if (lastEUN != BLOCK_NIL) { | 576 | if (lastEUN != BLOCK_NIL) { |
577 | thisVUC |= 0x8000; /* It's a replacement block */ | 577 | thisVUC |= 0x8000; /* It's a replacement block */ |
578 | } else { | 578 | } else { |
@@ -745,7 +745,7 @@ extern char nftlmountrev[]; | |||
745 | 745 | ||
746 | static int __init init_nftl(void) | 746 | static int __init init_nftl(void) |
747 | { | 747 | { |
748 | printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c %s\n", nftlmountrev); | 748 | printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev); |
749 | 749 | ||
750 | return register_mtd_blktrans(&nftl_tr); | 750 | return register_mtd_blktrans(&nftl_tr); |
751 | } | 751 | } |
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 84afd9029f53..3b104ebb219a 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * NFTL mount code with extensive checks | 2 | * NFTL mount code with extensive checks |
3 | * | 3 | * |
4 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) | 4 | * Author: Fabrice Bellard (fabrice.bellard@netgem.com) |
5 | * Copyright (C) 2000 Netgem S.A. | 5 | * Copyright (C) 2000 Netgem S.A. |
6 | * | 6 | * |
7 | * $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev Exp $ | 7 | * $Id: nftlmount.c,v 1.41 2005/11/07 11:14:21 gleixner Exp $ |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
@@ -31,7 +31,7 @@ | |||
31 | 31 | ||
32 | #define SECTORSIZE 512 | 32 | #define SECTORSIZE 512 |
33 | 33 | ||
34 | char nftlmountrev[]="$Revision: 1.40 $"; | 34 | char nftlmountrev[]="$Revision: 1.41 $"; |
35 | 35 | ||
36 | /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the | 36 | /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the |
37 | * various device information of the NFTL partition and Bad Unit Table. Update | 37 | * various device information of the NFTL partition and Bad Unit Table. Update |
@@ -47,7 +47,7 @@ static int find_boot_record(struct NFTLrecord *nftl) | |||
47 | struct NFTLMediaHeader *mh = &nftl->MediaHdr; | 47 | struct NFTLMediaHeader *mh = &nftl->MediaHdr; |
48 | unsigned int i; | 48 | unsigned int i; |
49 | 49 | ||
50 | /* Assume logical EraseSize == physical erasesize for starting the scan. | 50 | /* Assume logical EraseSize == physical erasesize for starting the scan. |
51 | We'll sort it out later if we find a MediaHeader which says otherwise */ | 51 | We'll sort it out later if we find a MediaHeader which says otherwise */ |
52 | /* Actually, we won't. The new DiskOnChip driver has already scanned | 52 | /* Actually, we won't. The new DiskOnChip driver has already scanned |
53 | the MediaHeader and adjusted the virtual erasesize it presents in | 53 | the MediaHeader and adjusted the virtual erasesize it presents in |
@@ -83,9 +83,9 @@ static int find_boot_record(struct NFTLrecord *nftl) | |||
83 | if (retlen < 6 || memcmp(buf, "ANAND", 6)) { | 83 | if (retlen < 6 || memcmp(buf, "ANAND", 6)) { |
84 | /* ANAND\0 not found. Continue */ | 84 | /* ANAND\0 not found. Continue */ |
85 | #if 0 | 85 | #if 0 |
86 | printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", | 86 | printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", |
87 | block * nftl->EraseSize, nftl->mbd.mtd->index); | 87 | block * nftl->EraseSize, nftl->mbd.mtd->index); |
88 | #endif | 88 | #endif |
89 | continue; | 89 | continue; |
90 | } | 90 | } |
91 | 91 | ||
@@ -103,7 +103,7 @@ static int find_boot_record(struct NFTLrecord *nftl) | |||
103 | */ | 103 | */ |
104 | if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { | 104 | if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { |
105 | printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", | 105 | printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", |
106 | block * nftl->EraseSize, nftl->mbd.mtd->index, | 106 | block * nftl->EraseSize, nftl->mbd.mtd->index, |
107 | le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); | 107 | le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); |
108 | continue; | 108 | continue; |
109 | } | 109 | } |
@@ -175,7 +175,7 @@ device is already correct. | |||
175 | nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); | 175 | nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); |
176 | if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { | 176 | if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { |
177 | printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n"); | 177 | printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n"); |
178 | printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", | 178 | printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", |
179 | nftl->nb_boot_blocks, nftl->nb_blocks); | 179 | nftl->nb_boot_blocks, nftl->nb_blocks); |
180 | return -1; | 180 | return -1; |
181 | } | 181 | } |
@@ -187,7 +187,7 @@ device is already correct. | |||
187 | nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks); | 187 | nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks); |
188 | return -1; | 188 | return -1; |
189 | } | 189 | } |
190 | 190 | ||
191 | nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); | 191 | nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); |
192 | 192 | ||
193 | /* If we're not using the last sectors in the device for some reason, | 193 | /* If we're not using the last sectors in the device for some reason, |
@@ -210,12 +210,12 @@ device is already correct. | |||
210 | printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n"); | 210 | printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n"); |
211 | return -ENOMEM; | 211 | return -ENOMEM; |
212 | } | 212 | } |
213 | 213 | ||
214 | /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */ | 214 | /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */ |
215 | for (i = 0; i < nftl->nb_boot_blocks; i++) | 215 | for (i = 0; i < nftl->nb_boot_blocks; i++) |
216 | nftl->ReplUnitTable[i] = BLOCK_RESERVED; | 216 | nftl->ReplUnitTable[i] = BLOCK_RESERVED; |
217 | /* mark all remaining blocks as potentially containing data */ | 217 | /* mark all remaining blocks as potentially containing data */ |
218 | for (; i < nftl->nb_blocks; i++) { | 218 | for (; i < nftl->nb_blocks; i++) { |
219 | nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED; | 219 | nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED; |
220 | } | 220 | } |
221 | 221 | ||
@@ -245,12 +245,12 @@ The new DiskOnChip driver already scanned the bad block table. Just query it. | |||
245 | if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize)) | 245 | if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize)) |
246 | nftl->ReplUnitTable[i] = BLOCK_RESERVED; | 246 | nftl->ReplUnitTable[i] = BLOCK_RESERVED; |
247 | } | 247 | } |
248 | 248 | ||
249 | nftl->MediaUnit = block; | 249 | nftl->MediaUnit = block; |
250 | boot_record_count++; | 250 | boot_record_count++; |
251 | 251 | ||
252 | } /* foreach (block) */ | 252 | } /* foreach (block) */ |
253 | 253 | ||
254 | return boot_record_count?0:-1; | 254 | return boot_record_count?0:-1; |
255 | } | 255 | } |
256 | 256 | ||
@@ -265,7 +265,7 @@ static int memcmpb(void *a, int c, int n) | |||
265 | } | 265 | } |
266 | 266 | ||
267 | /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */ | 267 | /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */ |
268 | static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, | 268 | static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, |
269 | int check_oob) | 269 | int check_oob) |
270 | { | 270 | { |
271 | int i; | 271 | int i; |
@@ -293,7 +293,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int | |||
293 | * | 293 | * |
294 | * Return: 0 when succeed, -1 on error. | 294 | * Return: 0 when succeed, -1 on error. |
295 | * | 295 | * |
296 | * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? | 296 | * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? |
297 | */ | 297 | */ |
298 | int NFTL_formatblock(struct NFTLrecord *nftl, int block) | 298 | int NFTL_formatblock(struct NFTLrecord *nftl, int block) |
299 | { | 299 | { |
@@ -385,7 +385,7 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b | |||
385 | /* verify that the sector is really free. If not, mark | 385 | /* verify that the sector is really free. If not, mark |
386 | as ignore */ | 386 | as ignore */ |
387 | if (memcmpb(&bci, 0xff, 8) != 0 || | 387 | if (memcmpb(&bci, 0xff, 8) != 0 || |
388 | check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, | 388 | check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, |
389 | SECTORSIZE, 0) != 0) { | 389 | SECTORSIZE, 0) != 0) { |
390 | printk("Incorrect free sector %d in block %d: " | 390 | printk("Incorrect free sector %d in block %d: " |
391 | "marking it as ignored\n", | 391 | "marking it as ignored\n", |
@@ -486,7 +486,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) | |||
486 | size_t retlen; | 486 | size_t retlen; |
487 | 487 | ||
488 | /* check erase mark. */ | 488 | /* check erase mark. */ |
489 | if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, | 489 | if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, |
490 | &retlen, (char *)&h1) < 0) | 490 | &retlen, (char *)&h1) < 0) |
491 | return -1; | 491 | return -1; |
492 | 492 | ||
@@ -501,7 +501,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) | |||
501 | h1.EraseMark = cpu_to_le16(ERASE_MARK); | 501 | h1.EraseMark = cpu_to_le16(ERASE_MARK); |
502 | h1.EraseMark1 = cpu_to_le16(ERASE_MARK); | 502 | h1.EraseMark1 = cpu_to_le16(ERASE_MARK); |
503 | h1.WearInfo = cpu_to_le32(0); | 503 | h1.WearInfo = cpu_to_le32(0); |
504 | if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, | 504 | if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, |
505 | &retlen, (char *)&h1) < 0) | 505 | &retlen, (char *)&h1) < 0) |
506 | return -1; | 506 | return -1; |
507 | } else { | 507 | } else { |
@@ -582,9 +582,9 @@ int NFTL_mount(struct NFTLrecord *s) | |||
582 | 582 | ||
583 | for (;;) { | 583 | for (;;) { |
584 | /* read the block header. If error, we format the chain */ | 584 | /* read the block header. If error, we format the chain */ |
585 | if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, | 585 | if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, |
586 | &retlen, (char *)&h0) < 0 || | 586 | &retlen, (char *)&h0) < 0 || |
587 | MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, | 587 | MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, |
588 | &retlen, (char *)&h1) < 0) { | 588 | &retlen, (char *)&h1) < 0) { |
589 | s->ReplUnitTable[block] = BLOCK_NIL; | 589 | s->ReplUnitTable[block] = BLOCK_NIL; |
590 | do_format_chain = 1; | 590 | do_format_chain = 1; |
@@ -639,7 +639,7 @@ int NFTL_mount(struct NFTLrecord *s) | |||
639 | first_logical_block = logical_block; | 639 | first_logical_block = logical_block; |
640 | } else { | 640 | } else { |
641 | if (logical_block != first_logical_block) { | 641 | if (logical_block != first_logical_block) { |
642 | printk("Block %d: incorrect logical block: %d expected: %d\n", | 642 | printk("Block %d: incorrect logical block: %d expected: %d\n", |
643 | block, logical_block, first_logical_block); | 643 | block, logical_block, first_logical_block); |
644 | /* the chain is incorrect : we must format it, | 644 | /* the chain is incorrect : we must format it, |
645 | but we need to read it completly */ | 645 | but we need to read it completly */ |
@@ -668,7 +668,7 @@ int NFTL_mount(struct NFTLrecord *s) | |||
668 | s->ReplUnitTable[block] = BLOCK_NIL; | 668 | s->ReplUnitTable[block] = BLOCK_NIL; |
669 | break; | 669 | break; |
670 | } else if (rep_block >= s->nb_blocks) { | 670 | } else if (rep_block >= s->nb_blocks) { |
671 | printk("Block %d: referencing invalid block %d\n", | 671 | printk("Block %d: referencing invalid block %d\n", |
672 | block, rep_block); | 672 | block, rep_block); |
673 | do_format_chain = 1; | 673 | do_format_chain = 1; |
674 | s->ReplUnitTable[block] = BLOCK_NIL; | 674 | s->ReplUnitTable[block] = BLOCK_NIL; |
@@ -688,7 +688,7 @@ int NFTL_mount(struct NFTLrecord *s) | |||
688 | s->ReplUnitTable[block] = rep_block; | 688 | s->ReplUnitTable[block] = rep_block; |
689 | s->EUNtable[first_logical_block] = BLOCK_NIL; | 689 | s->EUNtable[first_logical_block] = BLOCK_NIL; |
690 | } else { | 690 | } else { |
691 | printk("Block %d: referencing block %d already in another chain\n", | 691 | printk("Block %d: referencing block %d already in another chain\n", |
692 | block, rep_block); | 692 | block, rep_block); |
693 | /* XXX: should handle correctly fold in progress chains */ | 693 | /* XXX: should handle correctly fold in progress chains */ |
694 | do_format_chain = 1; | 694 | do_format_chain = 1; |
@@ -710,7 +710,7 @@ int NFTL_mount(struct NFTLrecord *s) | |||
710 | } else { | 710 | } else { |
711 | unsigned int first_block1, chain_to_format, chain_length1; | 711 | unsigned int first_block1, chain_to_format, chain_length1; |
712 | int fold_mark; | 712 | int fold_mark; |
713 | 713 | ||
714 | /* valid chain : get foldmark */ | 714 | /* valid chain : get foldmark */ |
715 | fold_mark = get_fold_mark(s, first_block); | 715 | fold_mark = get_fold_mark(s, first_block); |
716 | if (fold_mark == 0) { | 716 | if (fold_mark == 0) { |
@@ -729,9 +729,9 @@ int NFTL_mount(struct NFTLrecord *s) | |||
729 | if (first_block1 != BLOCK_NIL) { | 729 | if (first_block1 != BLOCK_NIL) { |
730 | /* XXX: what to do if same length ? */ | 730 | /* XXX: what to do if same length ? */ |
731 | chain_length1 = calc_chain_length(s, first_block1); | 731 | chain_length1 = calc_chain_length(s, first_block1); |
732 | printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", | 732 | printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", |
733 | first_block1, chain_length1, first_block, chain_length); | 733 | first_block1, chain_length1, first_block, chain_length); |
734 | 734 | ||
735 | if (chain_length >= chain_length1) { | 735 | if (chain_length >= chain_length1) { |
736 | chain_to_format = first_block1; | 736 | chain_to_format = first_block1; |
737 | s->EUNtable[first_logical_block] = first_block; | 737 | s->EUNtable[first_logical_block] = first_block; |
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig new file mode 100644 index 000000000000..126ff6bf63d5 --- /dev/null +++ b/drivers/mtd/onenand/Kconfig | |||
@@ -0,0 +1,38 @@ | |||
1 | # | ||
2 | # linux/drivers/mtd/onenand/Kconfig | ||
3 | # | ||
4 | |||
5 | menu "OneNAND Flash Device Drivers" | ||
6 | depends on MTD != n | ||
7 | |||
8 | config MTD_ONENAND | ||
9 | tristate "OneNAND Device Support" | ||
10 | depends on MTD | ||
11 | help | ||
12 | This enables support for accessing all type of OneNAND flash | ||
13 | devices. For further information see | ||
14 | <http://www.samsung.com/Products/Semiconductor/Flash/OneNAND_TM/index.htm>. | ||
15 | |||
16 | config MTD_ONENAND_VERIFY_WRITE | ||
17 | bool "Verify OneNAND page writes" | ||
18 | depends on MTD_ONENAND | ||
19 | help | ||
20 | This adds an extra check when data is written to the flash. The | ||
21 | OneNAND flash device internally checks only bits transitioning | ||
22 | from 1 to 0. There is a rare possibility that even though the | ||
23 | device thinks the write was successful, a bit could have been | ||
24 | flipped accidentaly due to device wear or something else. | ||
25 | |||
26 | config MTD_ONENAND_GENERIC | ||
27 | tristate "OneNAND Flash device via platform device driver" | ||
28 | depends on MTD_ONENAND && ARM | ||
29 | help | ||
30 | Support for OneNAND flash via platform device driver. | ||
31 | |||
32 | config MTD_ONENAND_SYNC_READ | ||
33 | bool "OneNAND Sync. Burst Read Support" | ||
34 | depends on ARCH_OMAP | ||
35 | help | ||
36 | This enables support for Sync. Burst Read. | ||
37 | |||
38 | endmenu | ||
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile new file mode 100644 index 000000000000..269cfe467345 --- /dev/null +++ b/drivers/mtd/onenand/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for the OneNAND MTD | ||
3 | # | ||
4 | |||
5 | # Core functionality. | ||
6 | obj-$(CONFIG_MTD_ONENAND) += onenand.o | ||
7 | |||
8 | # Board specific. | ||
9 | obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o | ||
10 | |||
11 | onenand-objs = onenand_base.o onenand_bbt.o | ||
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c new file mode 100644 index 000000000000..48cce431f89f --- /dev/null +++ b/drivers/mtd/onenand/generic.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * linux/drivers/mtd/onenand/generic.c | ||
3 | * | ||
4 | * Copyright (c) 2005 Samsung Electronics | ||
5 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
6 | * | ||
7 | * 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 | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Overview: | ||
12 | * This is a device driver for the OneNAND flash for generic boards. | ||
13 | */ | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include <linux/mtd/onenand.h> | ||
20 | #include <linux/mtd/partitions.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include <asm/mach/flash.h> | ||
24 | |||
25 | #define DRIVER_NAME "onenand" | ||
26 | |||
27 | |||
28 | #ifdef CONFIG_MTD_PARTITIONS | ||
29 | static const char *part_probes[] = { "cmdlinepart", NULL, }; | ||
30 | #endif | ||
31 | |||
32 | struct onenand_info { | ||
33 | struct mtd_info mtd; | ||
34 | struct mtd_partition *parts; | ||
35 | struct onenand_chip onenand; | ||
36 | }; | ||
37 | |||
38 | static int __devinit generic_onenand_probe(struct device *dev) | ||
39 | { | ||
40 | struct onenand_info *info; | ||
41 | struct platform_device *pdev = to_platform_device(dev); | ||
42 | struct onenand_platform_data *pdata = pdev->dev.platform_data; | ||
43 | struct resource *res = pdev->resource; | ||
44 | unsigned long size = res->end - res->start + 1; | ||
45 | int err; | ||
46 | |||
47 | info = kmalloc(sizeof(struct onenand_info), GFP_KERNEL); | ||
48 | if (!info) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | memset(info, 0, sizeof(struct onenand_info)); | ||
52 | |||
53 | if (!request_mem_region(res->start, size, dev->driver->name)) { | ||
54 | err = -EBUSY; | ||
55 | goto out_free_info; | ||
56 | } | ||
57 | |||
58 | info->onenand.base = ioremap(res->start, size); | ||
59 | if (!info->onenand.base) { | ||
60 | err = -ENOMEM; | ||
61 | goto out_release_mem_region; | ||
62 | } | ||
63 | |||
64 | info->onenand.mmcontrol = pdata->mmcontrol; | ||
65 | |||
66 | info->mtd.name = pdev->dev.bus_id; | ||
67 | info->mtd.priv = &info->onenand; | ||
68 | info->mtd.owner = THIS_MODULE; | ||
69 | |||
70 | if (onenand_scan(&info->mtd, 1)) { | ||
71 | err = -ENXIO; | ||
72 | goto out_iounmap; | ||
73 | } | ||
74 | |||
75 | #ifdef CONFIG_MTD_PARTITIONS | ||
76 | err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); | ||
77 | if (err > 0) | ||
78 | add_mtd_partitions(&info->mtd, info->parts, err); | ||
79 | else if (err < 0 && pdata->parts) | ||
80 | add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts); | ||
81 | else | ||
82 | #endif | ||
83 | err = add_mtd_device(&info->mtd); | ||
84 | |||
85 | dev_set_drvdata(&pdev->dev, info); | ||
86 | |||
87 | return 0; | ||
88 | |||
89 | out_iounmap: | ||
90 | iounmap(info->onenand.base); | ||
91 | out_release_mem_region: | ||
92 | release_mem_region(res->start, size); | ||
93 | out_free_info: | ||
94 | kfree(info); | ||
95 | |||
96 | return err; | ||
97 | } | ||
98 | |||
99 | static int __devexit generic_onenand_remove(struct device *dev) | ||
100 | { | ||
101 | struct platform_device *pdev = to_platform_device(dev); | ||
102 | struct onenand_info *info = dev_get_drvdata(&pdev->dev); | ||
103 | struct resource *res = pdev->resource; | ||
104 | unsigned long size = res->end - res->start + 1; | ||
105 | |||
106 | dev_set_drvdata(&pdev->dev, NULL); | ||
107 | |||
108 | if (info) { | ||
109 | if (info->parts) | ||
110 | del_mtd_partitions(&info->mtd); | ||
111 | else | ||
112 | del_mtd_device(&info->mtd); | ||
113 | |||
114 | onenand_release(&info->mtd); | ||
115 | release_mem_region(res->start, size); | ||
116 | iounmap(info->onenand.base); | ||
117 | kfree(info); | ||
118 | } | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static struct device_driver generic_onenand_driver = { | ||
124 | .name = DRIVER_NAME, | ||
125 | .bus = &platform_bus_type, | ||
126 | .probe = generic_onenand_probe, | ||
127 | .remove = __devexit_p(generic_onenand_remove), | ||
128 | }; | ||
129 | |||
130 | MODULE_ALIAS(DRIVER_NAME); | ||
131 | |||
132 | static int __init generic_onenand_init(void) | ||
133 | { | ||
134 | return driver_register(&generic_onenand_driver); | ||
135 | } | ||
136 | |||
137 | static void __exit generic_onenand_exit(void) | ||
138 | { | ||
139 | driver_unregister(&generic_onenand_driver); | ||
140 | } | ||
141 | |||
142 | module_init(generic_onenand_init); | ||
143 | module_exit(generic_onenand_exit); | ||
144 | |||
145 | MODULE_LICENSE("GPL"); | ||
146 | MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); | ||
147 | MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards"); | ||
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c new file mode 100644 index 000000000000..cc38fa0d45c6 --- /dev/null +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -0,0 +1,1588 @@ | |||
1 | /* | ||
2 | * linux/drivers/mtd/onenand/onenand_base.c | ||
3 | * | ||
4 | * Copyright (C) 2005 Samsung Electronics | ||
5 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
6 | * | ||
7 | * 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 | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/mtd/mtd.h> | ||
16 | #include <linux/mtd/onenand.h> | ||
17 | #include <linux/mtd/partitions.h> | ||
18 | |||
19 | #include <asm/io.h> | ||
20 | |||
21 | /** | ||
22 | * onenand_oob_64 - oob info for large (2KB) page | ||
23 | */ | ||
24 | static struct nand_oobinfo onenand_oob_64 = { | ||
25 | .useecc = MTD_NANDECC_AUTOPLACE, | ||
26 | .eccbytes = 20, | ||
27 | .eccpos = { | ||
28 | 8, 9, 10, 11, 12, | ||
29 | 24, 25, 26, 27, 28, | ||
30 | 40, 41, 42, 43, 44, | ||
31 | 56, 57, 58, 59, 60, | ||
32 | }, | ||
33 | .oobfree = { | ||
34 | {2, 3}, {14, 2}, {18, 3}, {30, 2}, | ||
35 | {24, 3}, {46, 2}, {40, 3}, {62, 2} } | ||
36 | }; | ||
37 | |||
38 | /** | ||
39 | * onenand_oob_32 - oob info for middle (1KB) page | ||
40 | */ | ||
41 | static struct nand_oobinfo onenand_oob_32 = { | ||
42 | .useecc = MTD_NANDECC_AUTOPLACE, | ||
43 | .eccbytes = 10, | ||
44 | .eccpos = { | ||
45 | 8, 9, 10, 11, 12, | ||
46 | 24, 25, 26, 27, 28, | ||
47 | }, | ||
48 | .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} } | ||
49 | }; | ||
50 | |||
51 | static const unsigned char ffchars[] = { | ||
52 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
53 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */ | ||
54 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
55 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 */ | ||
56 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
57 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */ | ||
58 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
59 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */ | ||
60 | }; | ||
61 | |||
62 | /** | ||
63 | * onenand_readw - [OneNAND Interface] Read OneNAND register | ||
64 | * @param addr address to read | ||
65 | * | ||
66 | * Read OneNAND register | ||
67 | */ | ||
68 | static unsigned short onenand_readw(void __iomem *addr) | ||
69 | { | ||
70 | return readw(addr); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * onenand_writew - [OneNAND Interface] Write OneNAND register with value | ||
75 | * @param value value to write | ||
76 | * @param addr address to write | ||
77 | * | ||
78 | * Write OneNAND register with value | ||
79 | */ | ||
80 | static void onenand_writew(unsigned short value, void __iomem *addr) | ||
81 | { | ||
82 | writew(value, addr); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * onenand_block_address - [DEFAULT] Get block address | ||
87 | * @param this onenand chip data structure | ||
88 | * @param block the block | ||
89 | * @return translated block address if DDP, otherwise same | ||
90 | * | ||
91 | * Setup Start Address 1 Register (F100h) | ||
92 | */ | ||
93 | static int onenand_block_address(struct onenand_chip *this, int block) | ||
94 | { | ||
95 | if (this->device_id & ONENAND_DEVICE_IS_DDP) { | ||
96 | /* Device Flash Core select, NAND Flash Block Address */ | ||
97 | int dfs = 0; | ||
98 | |||
99 | if (block & this->density_mask) | ||
100 | dfs = 1; | ||
101 | |||
102 | return (dfs << ONENAND_DDP_SHIFT) | | ||
103 | (block & (this->density_mask - 1)); | ||
104 | } | ||
105 | |||
106 | return block; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * onenand_bufferram_address - [DEFAULT] Get bufferram address | ||
111 | * @param this onenand chip data structure | ||
112 | * @param block the block | ||
113 | * @return set DBS value if DDP, otherwise 0 | ||
114 | * | ||
115 | * Setup Start Address 2 Register (F101h) for DDP | ||
116 | */ | ||
117 | static int onenand_bufferram_address(struct onenand_chip *this, int block) | ||
118 | { | ||
119 | if (this->device_id & ONENAND_DEVICE_IS_DDP) { | ||
120 | /* Device BufferRAM Select */ | ||
121 | int dbs = 0; | ||
122 | |||
123 | if (block & this->density_mask) | ||
124 | dbs = 1; | ||
125 | |||
126 | return (dbs << ONENAND_DDP_SHIFT); | ||
127 | } | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * onenand_page_address - [DEFAULT] Get page address | ||
134 | * @param page the page address | ||
135 | * @param sector the sector address | ||
136 | * @return combined page and sector address | ||
137 | * | ||
138 | * Setup Start Address 8 Register (F107h) | ||
139 | */ | ||
140 | static int onenand_page_address(int page, int sector) | ||
141 | { | ||
142 | /* Flash Page Address, Flash Sector Address */ | ||
143 | int fpa, fsa; | ||
144 | |||
145 | fpa = page & ONENAND_FPA_MASK; | ||
146 | fsa = sector & ONENAND_FSA_MASK; | ||
147 | |||
148 | return ((fpa << ONENAND_FPA_SHIFT) | fsa); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * onenand_buffer_address - [DEFAULT] Get buffer address | ||
153 | * @param dataram1 DataRAM index | ||
154 | * @param sectors the sector address | ||
155 | * @param count the number of sectors | ||
156 | * @return the start buffer value | ||
157 | * | ||
158 | * Setup Start Buffer Register (F200h) | ||
159 | */ | ||
160 | static int onenand_buffer_address(int dataram1, int sectors, int count) | ||
161 | { | ||
162 | int bsa, bsc; | ||
163 | |||
164 | /* BufferRAM Sector Address */ | ||
165 | bsa = sectors & ONENAND_BSA_MASK; | ||
166 | |||
167 | if (dataram1) | ||
168 | bsa |= ONENAND_BSA_DATARAM1; /* DataRAM1 */ | ||
169 | else | ||
170 | bsa |= ONENAND_BSA_DATARAM0; /* DataRAM0 */ | ||
171 | |||
172 | /* BufferRAM Sector Count */ | ||
173 | bsc = count & ONENAND_BSC_MASK; | ||
174 | |||
175 | return ((bsa << ONENAND_BSA_SHIFT) | bsc); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * onenand_command - [DEFAULT] Send command to OneNAND device | ||
180 | * @param mtd MTD device structure | ||
181 | * @param cmd the command to be sent | ||
182 | * @param addr offset to read from or write to | ||
183 | * @param len number of bytes to read or write | ||
184 | * | ||
185 | * Send command to OneNAND device. This function is used for middle/large page | ||
186 | * devices (1KB/2KB Bytes per page) | ||
187 | */ | ||
188 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) | ||
189 | { | ||
190 | struct onenand_chip *this = mtd->priv; | ||
191 | int value, readcmd = 0; | ||
192 | int block, page; | ||
193 | /* Now we use page size operation */ | ||
194 | int sectors = 4, count = 4; | ||
195 | |||
196 | /* Address translation */ | ||
197 | switch (cmd) { | ||
198 | case ONENAND_CMD_UNLOCK: | ||
199 | case ONENAND_CMD_LOCK: | ||
200 | case ONENAND_CMD_LOCK_TIGHT: | ||
201 | block = -1; | ||
202 | page = -1; | ||
203 | break; | ||
204 | |||
205 | case ONENAND_CMD_ERASE: | ||
206 | case ONENAND_CMD_BUFFERRAM: | ||
207 | block = (int) (addr >> this->erase_shift); | ||
208 | page = -1; | ||
209 | break; | ||
210 | |||
211 | default: | ||
212 | block = (int) (addr >> this->erase_shift); | ||
213 | page = (int) (addr >> this->page_shift); | ||
214 | page &= this->page_mask; | ||
215 | break; | ||
216 | } | ||
217 | |||
218 | /* NOTE: The setting order of the registers is very important! */ | ||
219 | if (cmd == ONENAND_CMD_BUFFERRAM) { | ||
220 | /* Select DataRAM for DDP */ | ||
221 | value = onenand_bufferram_address(this, block); | ||
222 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
223 | |||
224 | /* Switch to the next data buffer */ | ||
225 | ONENAND_SET_NEXT_BUFFERRAM(this); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | if (block != -1) { | ||
231 | /* Write 'DFS, FBA' of Flash */ | ||
232 | value = onenand_block_address(this, block); | ||
233 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | ||
234 | } | ||
235 | |||
236 | if (page != -1) { | ||
237 | int dataram; | ||
238 | |||
239 | switch (cmd) { | ||
240 | case ONENAND_CMD_READ: | ||
241 | case ONENAND_CMD_READOOB: | ||
242 | dataram = ONENAND_SET_NEXT_BUFFERRAM(this); | ||
243 | readcmd = 1; | ||
244 | break; | ||
245 | |||
246 | default: | ||
247 | dataram = ONENAND_CURRENT_BUFFERRAM(this); | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | /* Write 'FPA, FSA' of Flash */ | ||
252 | value = onenand_page_address(page, sectors); | ||
253 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS8); | ||
254 | |||
255 | /* Write 'BSA, BSC' of DataRAM */ | ||
256 | value = onenand_buffer_address(dataram, sectors, count); | ||
257 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); | ||
258 | |||
259 | if (readcmd) { | ||
260 | /* Select DataRAM for DDP */ | ||
261 | value = onenand_bufferram_address(this, block); | ||
262 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* Interrupt clear */ | ||
267 | this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT); | ||
268 | |||
269 | /* Write command */ | ||
270 | this->write_word(cmd, this->base + ONENAND_REG_COMMAND); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * onenand_wait - [DEFAULT] wait until the command is done | ||
277 | * @param mtd MTD device structure | ||
278 | * @param state state to select the max. timeout value | ||
279 | * | ||
280 | * Wait for command done. This applies to all OneNAND command | ||
281 | * Read can take up to 30us, erase up to 2ms and program up to 350us | ||
282 | * according to general OneNAND specs | ||
283 | */ | ||
284 | static int onenand_wait(struct mtd_info *mtd, int state) | ||
285 | { | ||
286 | struct onenand_chip * this = mtd->priv; | ||
287 | unsigned long timeout; | ||
288 | unsigned int flags = ONENAND_INT_MASTER; | ||
289 | unsigned int interrupt = 0; | ||
290 | unsigned int ctrl, ecc; | ||
291 | |||
292 | /* The 20 msec is enough */ | ||
293 | timeout = jiffies + msecs_to_jiffies(20); | ||
294 | while (time_before(jiffies, timeout)) { | ||
295 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | ||
296 | |||
297 | if (interrupt & flags) | ||
298 | break; | ||
299 | |||
300 | if (state != FL_READING) | ||
301 | cond_resched(); | ||
302 | } | ||
303 | /* To get correct interrupt status in timeout case */ | ||
304 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | ||
305 | |||
306 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | ||
307 | |||
308 | if (ctrl & ONENAND_CTRL_ERROR) { | ||
309 | /* It maybe occur at initial bad block */ | ||
310 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl); | ||
311 | /* Clear other interrupt bits for preventing ECC error */ | ||
312 | interrupt &= ONENAND_INT_MASTER; | ||
313 | } | ||
314 | |||
315 | if (ctrl & ONENAND_CTRL_LOCK) { | ||
316 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x\n", ctrl); | ||
317 | return -EACCES; | ||
318 | } | ||
319 | |||
320 | if (interrupt & ONENAND_INT_READ) { | ||
321 | ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); | ||
322 | if (ecc & ONENAND_ECC_2BIT_ALL) { | ||
323 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); | ||
324 | return -EBADMSG; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | /** | ||
332 | * onenand_bufferram_offset - [DEFAULT] BufferRAM offset | ||
333 | * @param mtd MTD data structure | ||
334 | * @param area BufferRAM area | ||
335 | * @return offset given area | ||
336 | * | ||
337 | * Return BufferRAM offset given area | ||
338 | */ | ||
339 | static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) | ||
340 | { | ||
341 | struct onenand_chip *this = mtd->priv; | ||
342 | |||
343 | if (ONENAND_CURRENT_BUFFERRAM(this)) { | ||
344 | if (area == ONENAND_DATARAM) | ||
345 | return mtd->oobblock; | ||
346 | if (area == ONENAND_SPARERAM) | ||
347 | return mtd->oobsize; | ||
348 | } | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area | ||
355 | * @param mtd MTD data structure | ||
356 | * @param area BufferRAM area | ||
357 | * @param buffer the databuffer to put/get data | ||
358 | * @param offset offset to read from or write to | ||
359 | * @param count number of bytes to read/write | ||
360 | * | ||
361 | * Read the BufferRAM area | ||
362 | */ | ||
363 | static int onenand_read_bufferram(struct mtd_info *mtd, int area, | ||
364 | unsigned char *buffer, int offset, size_t count) | ||
365 | { | ||
366 | struct onenand_chip *this = mtd->priv; | ||
367 | void __iomem *bufferram; | ||
368 | |||
369 | bufferram = this->base + area; | ||
370 | |||
371 | bufferram += onenand_bufferram_offset(mtd, area); | ||
372 | |||
373 | memcpy(buffer, bufferram + offset, count); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode | ||
380 | * @param mtd MTD data structure | ||
381 | * @param area BufferRAM area | ||
382 | * @param buffer the databuffer to put/get data | ||
383 | * @param offset offset to read from or write to | ||
384 | * @param count number of bytes to read/write | ||
385 | * | ||
386 | * Read the BufferRAM area with Sync. Burst Mode | ||
387 | */ | ||
388 | static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, | ||
389 | unsigned char *buffer, int offset, size_t count) | ||
390 | { | ||
391 | struct onenand_chip *this = mtd->priv; | ||
392 | void __iomem *bufferram; | ||
393 | |||
394 | bufferram = this->base + area; | ||
395 | |||
396 | bufferram += onenand_bufferram_offset(mtd, area); | ||
397 | |||
398 | this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ); | ||
399 | |||
400 | memcpy(buffer, bufferram + offset, count); | ||
401 | |||
402 | this->mmcontrol(mtd, 0); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area | ||
409 | * @param mtd MTD data structure | ||
410 | * @param area BufferRAM area | ||
411 | * @param buffer the databuffer to put/get data | ||
412 | * @param offset offset to read from or write to | ||
413 | * @param count number of bytes to read/write | ||
414 | * | ||
415 | * Write the BufferRAM area | ||
416 | */ | ||
417 | static int onenand_write_bufferram(struct mtd_info *mtd, int area, | ||
418 | const unsigned char *buffer, int offset, size_t count) | ||
419 | { | ||
420 | struct onenand_chip *this = mtd->priv; | ||
421 | void __iomem *bufferram; | ||
422 | |||
423 | bufferram = this->base + area; | ||
424 | |||
425 | bufferram += onenand_bufferram_offset(mtd, area); | ||
426 | |||
427 | memcpy(bufferram + offset, buffer, count); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * onenand_check_bufferram - [GENERIC] Check BufferRAM information | ||
434 | * @param mtd MTD data structure | ||
435 | * @param addr address to check | ||
436 | * @return 1 if there are valid data, otherwise 0 | ||
437 | * | ||
438 | * Check bufferram if there is data we required | ||
439 | */ | ||
440 | static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) | ||
441 | { | ||
442 | struct onenand_chip *this = mtd->priv; | ||
443 | int block, page; | ||
444 | int i; | ||
445 | |||
446 | block = (int) (addr >> this->erase_shift); | ||
447 | page = (int) (addr >> this->page_shift); | ||
448 | page &= this->page_mask; | ||
449 | |||
450 | i = ONENAND_CURRENT_BUFFERRAM(this); | ||
451 | |||
452 | /* Is there valid data? */ | ||
453 | if (this->bufferram[i].block == block && | ||
454 | this->bufferram[i].page == page && | ||
455 | this->bufferram[i].valid) | ||
456 | return 1; | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | /** | ||
462 | * onenand_update_bufferram - [GENERIC] Update BufferRAM information | ||
463 | * @param mtd MTD data structure | ||
464 | * @param addr address to update | ||
465 | * @param valid valid flag | ||
466 | * | ||
467 | * Update BufferRAM information | ||
468 | */ | ||
469 | static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, | ||
470 | int valid) | ||
471 | { | ||
472 | struct onenand_chip *this = mtd->priv; | ||
473 | int block, page; | ||
474 | int i; | ||
475 | |||
476 | block = (int) (addr >> this->erase_shift); | ||
477 | page = (int) (addr >> this->page_shift); | ||
478 | page &= this->page_mask; | ||
479 | |||
480 | /* Invalidate BufferRAM */ | ||
481 | for (i = 0; i < MAX_BUFFERRAM; i++) { | ||
482 | if (this->bufferram[i].block == block && | ||
483 | this->bufferram[i].page == page) | ||
484 | this->bufferram[i].valid = 0; | ||
485 | } | ||
486 | |||
487 | /* Update BufferRAM */ | ||
488 | i = ONENAND_CURRENT_BUFFERRAM(this); | ||
489 | this->bufferram[i].block = block; | ||
490 | this->bufferram[i].page = page; | ||
491 | this->bufferram[i].valid = valid; | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * onenand_get_device - [GENERIC] Get chip for selected access | ||
498 | * @param mtd MTD device structure | ||
499 | * @param new_state the state which is requested | ||
500 | * | ||
501 | * Get the device and lock it for exclusive access | ||
502 | */ | ||
503 | static int onenand_get_device(struct mtd_info *mtd, int new_state) | ||
504 | { | ||
505 | struct onenand_chip *this = mtd->priv; | ||
506 | DECLARE_WAITQUEUE(wait, current); | ||
507 | |||
508 | /* | ||
509 | * Grab the lock and see if the device is available | ||
510 | */ | ||
511 | while (1) { | ||
512 | spin_lock(&this->chip_lock); | ||
513 | if (this->state == FL_READY) { | ||
514 | this->state = new_state; | ||
515 | spin_unlock(&this->chip_lock); | ||
516 | break; | ||
517 | } | ||
518 | if (new_state == FL_PM_SUSPENDED) { | ||
519 | spin_unlock(&this->chip_lock); | ||
520 | return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; | ||
521 | } | ||
522 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
523 | add_wait_queue(&this->wq, &wait); | ||
524 | spin_unlock(&this->chip_lock); | ||
525 | schedule(); | ||
526 | remove_wait_queue(&this->wq, &wait); | ||
527 | } | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | /** | ||
533 | * onenand_release_device - [GENERIC] release chip | ||
534 | * @param mtd MTD device structure | ||
535 | * | ||
536 | * Deselect, release chip lock and wake up anyone waiting on the device | ||
537 | */ | ||
538 | static void onenand_release_device(struct mtd_info *mtd) | ||
539 | { | ||
540 | struct onenand_chip *this = mtd->priv; | ||
541 | |||
542 | /* Release the chip */ | ||
543 | spin_lock(&this->chip_lock); | ||
544 | this->state = FL_READY; | ||
545 | wake_up(&this->wq); | ||
546 | spin_unlock(&this->chip_lock); | ||
547 | } | ||
548 | |||
549 | /** | ||
550 | * onenand_read_ecc - [MTD Interface] Read data with ECC | ||
551 | * @param mtd MTD device structure | ||
552 | * @param from offset to read from | ||
553 | * @param len number of bytes to read | ||
554 | * @param retlen pointer to variable to store the number of read bytes | ||
555 | * @param buf the databuffer to put data | ||
556 | * @param oob_buf filesystem supplied oob data buffer | ||
557 | * @param oobsel oob selection structure | ||
558 | * | ||
559 | * OneNAND read with ECC | ||
560 | */ | ||
561 | static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | ||
562 | size_t *retlen, u_char *buf, | ||
563 | u_char *oob_buf, struct nand_oobinfo *oobsel) | ||
564 | { | ||
565 | struct onenand_chip *this = mtd->priv; | ||
566 | int read = 0, column; | ||
567 | int thislen; | ||
568 | int ret = 0; | ||
569 | |||
570 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | ||
571 | |||
572 | /* Do not allow reads past end of device */ | ||
573 | if ((from + len) > mtd->size) { | ||
574 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); | ||
575 | *retlen = 0; | ||
576 | return -EINVAL; | ||
577 | } | ||
578 | |||
579 | /* Grab the lock and see if the device is available */ | ||
580 | onenand_get_device(mtd, FL_READING); | ||
581 | |||
582 | /* TODO handling oob */ | ||
583 | |||
584 | while (read < len) { | ||
585 | thislen = min_t(int, mtd->oobblock, len - read); | ||
586 | |||
587 | column = from & (mtd->oobblock - 1); | ||
588 | if (column + thislen > mtd->oobblock) | ||
589 | thislen = mtd->oobblock - column; | ||
590 | |||
591 | if (!onenand_check_bufferram(mtd, from)) { | ||
592 | this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock); | ||
593 | |||
594 | ret = this->wait(mtd, FL_READING); | ||
595 | /* First copy data and check return value for ECC handling */ | ||
596 | onenand_update_bufferram(mtd, from, 1); | ||
597 | } | ||
598 | |||
599 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | ||
600 | |||
601 | read += thislen; | ||
602 | |||
603 | if (read == len) | ||
604 | break; | ||
605 | |||
606 | if (ret) { | ||
607 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); | ||
608 | goto out; | ||
609 | } | ||
610 | |||
611 | from += thislen; | ||
612 | buf += thislen; | ||
613 | } | ||
614 | |||
615 | out: | ||
616 | /* Deselect and wake up anyone waiting on the device */ | ||
617 | onenand_release_device(mtd); | ||
618 | |||
619 | /* | ||
620 | * Return success, if no ECC failures, else -EBADMSG | ||
621 | * fs driver will take care of that, because | ||
622 | * retlen == desired len and result == -EBADMSG | ||
623 | */ | ||
624 | *retlen = read; | ||
625 | return ret; | ||
626 | } | ||
627 | |||
628 | /** | ||
629 | * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc | ||
630 | * @param mtd MTD device structure | ||
631 | * @param from offset to read from | ||
632 | * @param len number of bytes to read | ||
633 | * @param retlen pointer to variable to store the number of read bytes | ||
634 | * @param buf the databuffer to put data | ||
635 | * | ||
636 | * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL | ||
637 | */ | ||
638 | static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
639 | size_t *retlen, u_char *buf) | ||
640 | { | ||
641 | return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); | ||
642 | } | ||
643 | |||
644 | /** | ||
645 | * onenand_read_oob - [MTD Interface] OneNAND read out-of-band | ||
646 | * @param mtd MTD device structure | ||
647 | * @param from offset to read from | ||
648 | * @param len number of bytes to read | ||
649 | * @param retlen pointer to variable to store the number of read bytes | ||
650 | * @param buf the databuffer to put data | ||
651 | * | ||
652 | * OneNAND read out-of-band data from the spare area | ||
653 | */ | ||
654 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | ||
655 | size_t *retlen, u_char *buf) | ||
656 | { | ||
657 | struct onenand_chip *this = mtd->priv; | ||
658 | int read = 0, thislen, column; | ||
659 | int ret = 0; | ||
660 | |||
661 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | ||
662 | |||
663 | /* Initialize return length value */ | ||
664 | *retlen = 0; | ||
665 | |||
666 | /* Do not allow reads past end of device */ | ||
667 | if (unlikely((from + len) > mtd->size)) { | ||
668 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n"); | ||
669 | return -EINVAL; | ||
670 | } | ||
671 | |||
672 | /* Grab the lock and see if the device is available */ | ||
673 | onenand_get_device(mtd, FL_READING); | ||
674 | |||
675 | column = from & (mtd->oobsize - 1); | ||
676 | |||
677 | while (read < len) { | ||
678 | thislen = mtd->oobsize - column; | ||
679 | thislen = min_t(int, thislen, len); | ||
680 | |||
681 | this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); | ||
682 | |||
683 | onenand_update_bufferram(mtd, from, 0); | ||
684 | |||
685 | ret = this->wait(mtd, FL_READING); | ||
686 | /* First copy data and check return value for ECC handling */ | ||
687 | |||
688 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | ||
689 | |||
690 | read += thislen; | ||
691 | |||
692 | if (read == len) | ||
693 | break; | ||
694 | |||
695 | if (ret) { | ||
696 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret); | ||
697 | goto out; | ||
698 | } | ||
699 | |||
700 | buf += thislen; | ||
701 | |||
702 | /* Read more? */ | ||
703 | if (read < len) { | ||
704 | /* Page size */ | ||
705 | from += mtd->oobblock; | ||
706 | column = 0; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | out: | ||
711 | /* Deselect and wake up anyone waiting on the device */ | ||
712 | onenand_release_device(mtd); | ||
713 | |||
714 | *retlen = read; | ||
715 | return ret; | ||
716 | } | ||
717 | |||
718 | #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE | ||
719 | /** | ||
720 | * onenand_verify_page - [GENERIC] verify the chip contents after a write | ||
721 | * @param mtd MTD device structure | ||
722 | * @param buf the databuffer to verify | ||
723 | * | ||
724 | * Check DataRAM area directly | ||
725 | */ | ||
726 | static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) | ||
727 | { | ||
728 | struct onenand_chip *this = mtd->priv; | ||
729 | void __iomem *dataram0, *dataram1; | ||
730 | int ret = 0; | ||
731 | |||
732 | this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); | ||
733 | |||
734 | ret = this->wait(mtd, FL_READING); | ||
735 | if (ret) | ||
736 | return ret; | ||
737 | |||
738 | onenand_update_bufferram(mtd, addr, 1); | ||
739 | |||
740 | /* Check, if the two dataram areas are same */ | ||
741 | dataram0 = this->base + ONENAND_DATARAM; | ||
742 | dataram1 = dataram0 + mtd->oobblock; | ||
743 | |||
744 | if (memcmp(dataram0, dataram1, mtd->oobblock)) | ||
745 | return -EBADMSG; | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | #else | ||
750 | #define onenand_verify_page(...) (0) | ||
751 | #endif | ||
752 | |||
753 | #define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0) | ||
754 | |||
755 | /** | ||
756 | * onenand_write_ecc - [MTD Interface] OneNAND write with ECC | ||
757 | * @param mtd MTD device structure | ||
758 | * @param to offset to write to | ||
759 | * @param len number of bytes to write | ||
760 | * @param retlen pointer to variable to store the number of written bytes | ||
761 | * @param buf the data to write | ||
762 | * @param eccbuf filesystem supplied oob data buffer | ||
763 | * @param oobsel oob selection structure | ||
764 | * | ||
765 | * OneNAND write with ECC | ||
766 | */ | ||
767 | static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | ||
768 | size_t *retlen, const u_char *buf, | ||
769 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
770 | { | ||
771 | struct onenand_chip *this = mtd->priv; | ||
772 | int written = 0; | ||
773 | int ret = 0; | ||
774 | |||
775 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | ||
776 | |||
777 | /* Initialize retlen, in case of early exit */ | ||
778 | *retlen = 0; | ||
779 | |||
780 | /* Do not allow writes past end of device */ | ||
781 | if (unlikely((to + len) > mtd->size)) { | ||
782 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); | ||
783 | return -EINVAL; | ||
784 | } | ||
785 | |||
786 | /* Reject writes, which are not page aligned */ | ||
787 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | ||
788 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); | ||
789 | return -EINVAL; | ||
790 | } | ||
791 | |||
792 | /* Grab the lock and see if the device is available */ | ||
793 | onenand_get_device(mtd, FL_WRITING); | ||
794 | |||
795 | /* Loop until all data write */ | ||
796 | while (written < len) { | ||
797 | int thislen = min_t(int, mtd->oobblock, len - written); | ||
798 | |||
799 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); | ||
800 | |||
801 | this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); | ||
802 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
803 | |||
804 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); | ||
805 | |||
806 | onenand_update_bufferram(mtd, to, 1); | ||
807 | |||
808 | ret = this->wait(mtd, FL_WRITING); | ||
809 | if (ret) { | ||
810 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); | ||
811 | goto out; | ||
812 | } | ||
813 | |||
814 | written += thislen; | ||
815 | |||
816 | /* Only check verify write turn on */ | ||
817 | ret = onenand_verify_page(mtd, (u_char *) buf, to); | ||
818 | if (ret) { | ||
819 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); | ||
820 | goto out; | ||
821 | } | ||
822 | |||
823 | if (written == len) | ||
824 | break; | ||
825 | |||
826 | to += thislen; | ||
827 | buf += thislen; | ||
828 | } | ||
829 | |||
830 | out: | ||
831 | /* Deselect and wake up anyone waiting on the device */ | ||
832 | onenand_release_device(mtd); | ||
833 | |||
834 | *retlen = written; | ||
835 | |||
836 | return ret; | ||
837 | } | ||
838 | |||
839 | /** | ||
840 | * onenand_write - [MTD Interface] compability function for onenand_write_ecc | ||
841 | * @param mtd MTD device structure | ||
842 | * @param to offset to write to | ||
843 | * @param len number of bytes to write | ||
844 | * @param retlen pointer to variable to store the number of written bytes | ||
845 | * @param buf the data to write | ||
846 | * | ||
847 | * This function simply calls onenand_write_ecc | ||
848 | * with oob buffer and oobsel = NULL | ||
849 | */ | ||
850 | static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
851 | size_t *retlen, const u_char *buf) | ||
852 | { | ||
853 | return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL); | ||
854 | } | ||
855 | |||
856 | /** | ||
857 | * onenand_write_oob - [MTD Interface] OneNAND write out-of-band | ||
858 | * @param mtd MTD device structure | ||
859 | * @param to offset to write to | ||
860 | * @param len number of bytes to write | ||
861 | * @param retlen pointer to variable to store the number of written bytes | ||
862 | * @param buf the data to write | ||
863 | * | ||
864 | * OneNAND write out-of-band | ||
865 | */ | ||
866 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | ||
867 | size_t *retlen, const u_char *buf) | ||
868 | { | ||
869 | struct onenand_chip *this = mtd->priv; | ||
870 | int column, status; | ||
871 | int written = 0; | ||
872 | |||
873 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | ||
874 | |||
875 | /* Initialize retlen, in case of early exit */ | ||
876 | *retlen = 0; | ||
877 | |||
878 | /* Do not allow writes past end of device */ | ||
879 | if (unlikely((to + len) > mtd->size)) { | ||
880 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n"); | ||
881 | return -EINVAL; | ||
882 | } | ||
883 | |||
884 | /* Grab the lock and see if the device is available */ | ||
885 | onenand_get_device(mtd, FL_WRITING); | ||
886 | |||
887 | /* Loop until all data write */ | ||
888 | while (written < len) { | ||
889 | int thislen = min_t(int, mtd->oobsize, len - written); | ||
890 | |||
891 | column = to & (mtd->oobsize - 1); | ||
892 | |||
893 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); | ||
894 | |||
895 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
896 | this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | ||
897 | |||
898 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); | ||
899 | |||
900 | onenand_update_bufferram(mtd, to, 0); | ||
901 | |||
902 | status = this->wait(mtd, FL_WRITING); | ||
903 | if (status) | ||
904 | goto out; | ||
905 | |||
906 | written += thislen; | ||
907 | |||
908 | if (written == len) | ||
909 | break; | ||
910 | |||
911 | to += thislen; | ||
912 | buf += thislen; | ||
913 | } | ||
914 | |||
915 | out: | ||
916 | /* Deselect and wake up anyone waiting on the device */ | ||
917 | onenand_release_device(mtd); | ||
918 | |||
919 | *retlen = written; | ||
920 | |||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | /** | ||
925 | * onenand_writev_ecc - [MTD Interface] write with iovec with ecc | ||
926 | * @param mtd MTD device structure | ||
927 | * @param vecs the iovectors to write | ||
928 | * @param count number of vectors | ||
929 | * @param to offset to write to | ||
930 | * @param retlen pointer to variable to store the number of written bytes | ||
931 | * @param eccbuf filesystem supplied oob data buffer | ||
932 | * @param oobsel oob selection structure | ||
933 | * | ||
934 | * OneNAND write with iovec with ecc | ||
935 | */ | ||
936 | static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | ||
937 | unsigned long count, loff_t to, size_t *retlen, | ||
938 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
939 | { | ||
940 | struct onenand_chip *this = mtd->priv; | ||
941 | unsigned char buffer[MAX_ONENAND_PAGESIZE], *pbuf; | ||
942 | size_t total_len, len; | ||
943 | int i, written = 0; | ||
944 | int ret = 0; | ||
945 | |||
946 | /* Preset written len for early exit */ | ||
947 | *retlen = 0; | ||
948 | |||
949 | /* Calculate total length of data */ | ||
950 | total_len = 0; | ||
951 | for (i = 0; i < count; i++) | ||
952 | total_len += vecs[i].iov_len; | ||
953 | |||
954 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); | ||
955 | |||
956 | /* Do not allow write past end of the device */ | ||
957 | if (unlikely((to + total_len) > mtd->size)) { | ||
958 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n"); | ||
959 | return -EINVAL; | ||
960 | } | ||
961 | |||
962 | /* Reject writes, which are not page aligned */ | ||
963 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) { | ||
964 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n"); | ||
965 | return -EINVAL; | ||
966 | } | ||
967 | |||
968 | /* Grab the lock and see if the device is available */ | ||
969 | onenand_get_device(mtd, FL_WRITING); | ||
970 | |||
971 | /* TODO handling oob */ | ||
972 | |||
973 | /* Loop until all keve's data has been written */ | ||
974 | len = 0; | ||
975 | while (count) { | ||
976 | pbuf = buffer; | ||
977 | /* | ||
978 | * If the given tuple is >= pagesize then | ||
979 | * write it out from the iov | ||
980 | */ | ||
981 | if ((vecs->iov_len - len) >= mtd->oobblock) { | ||
982 | pbuf = vecs->iov_base + len; | ||
983 | |||
984 | len += mtd->oobblock; | ||
985 | |||
986 | /* Check, if we have to switch to the next tuple */ | ||
987 | if (len >= (int) vecs->iov_len) { | ||
988 | vecs++; | ||
989 | len = 0; | ||
990 | count--; | ||
991 | } | ||
992 | } else { | ||
993 | int cnt = 0, thislen; | ||
994 | while (cnt < mtd->oobblock) { | ||
995 | thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len); | ||
996 | memcpy(buffer + cnt, vecs->iov_base + len, thislen); | ||
997 | cnt += thislen; | ||
998 | len += thislen; | ||
999 | |||
1000 | /* Check, if we have to switch to the next tuple */ | ||
1001 | if (len >= (int) vecs->iov_len) { | ||
1002 | vecs++; | ||
1003 | len = 0; | ||
1004 | count--; | ||
1005 | } | ||
1006 | } | ||
1007 | } | ||
1008 | |||
1009 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); | ||
1010 | |||
1011 | this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->oobblock); | ||
1012 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
1013 | |||
1014 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); | ||
1015 | |||
1016 | onenand_update_bufferram(mtd, to, 1); | ||
1017 | |||
1018 | ret = this->wait(mtd, FL_WRITING); | ||
1019 | if (ret) { | ||
1020 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret); | ||
1021 | goto out; | ||
1022 | } | ||
1023 | |||
1024 | |||
1025 | /* Only check verify write turn on */ | ||
1026 | ret = onenand_verify_page(mtd, (u_char *) pbuf, to); | ||
1027 | if (ret) { | ||
1028 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret); | ||
1029 | goto out; | ||
1030 | } | ||
1031 | |||
1032 | written += mtd->oobblock; | ||
1033 | |||
1034 | to += mtd->oobblock; | ||
1035 | } | ||
1036 | |||
1037 | out: | ||
1038 | /* Deselect and wakt up anyone waiting on the device */ | ||
1039 | onenand_release_device(mtd); | ||
1040 | |||
1041 | *retlen = written; | ||
1042 | |||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | /** | ||
1047 | * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc | ||
1048 | * @param mtd MTD device structure | ||
1049 | * @param vecs the iovectors to write | ||
1050 | * @param count number of vectors | ||
1051 | * @param to offset to write to | ||
1052 | * @param retlen pointer to variable to store the number of written bytes | ||
1053 | * | ||
1054 | * OneNAND write with kvec. This just calls the ecc function | ||
1055 | */ | ||
1056 | static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs, | ||
1057 | unsigned long count, loff_t to, size_t *retlen) | ||
1058 | { | ||
1059 | return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL); | ||
1060 | } | ||
1061 | |||
1062 | /** | ||
1063 | * onenand_block_checkbad - [GENERIC] Check if a block is marked bad | ||
1064 | * @param mtd MTD device structure | ||
1065 | * @param ofs offset from device start | ||
1066 | * @param getchip 0, if the chip is already selected | ||
1067 | * @param allowbbt 1, if its allowed to access the bbt area | ||
1068 | * | ||
1069 | * Check, if the block is bad. Either by reading the bad block table or | ||
1070 | * calling of the scan function. | ||
1071 | */ | ||
1072 | static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) | ||
1073 | { | ||
1074 | struct onenand_chip *this = mtd->priv; | ||
1075 | struct bbm_info *bbm = this->bbm; | ||
1076 | |||
1077 | /* Return info from the table */ | ||
1078 | return bbm->isbad_bbt(mtd, ofs, allowbbt); | ||
1079 | } | ||
1080 | |||
1081 | /** | ||
1082 | * onenand_erase - [MTD Interface] erase block(s) | ||
1083 | * @param mtd MTD device structure | ||
1084 | * @param instr erase instruction | ||
1085 | * | ||
1086 | * Erase one ore more blocks | ||
1087 | */ | ||
1088 | static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | ||
1089 | { | ||
1090 | struct onenand_chip *this = mtd->priv; | ||
1091 | unsigned int block_size; | ||
1092 | loff_t addr; | ||
1093 | int len; | ||
1094 | int ret = 0; | ||
1095 | |||
1096 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); | ||
1097 | |||
1098 | block_size = (1 << this->erase_shift); | ||
1099 | |||
1100 | /* Start address must align on block boundary */ | ||
1101 | if (unlikely(instr->addr & (block_size - 1))) { | ||
1102 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n"); | ||
1103 | return -EINVAL; | ||
1104 | } | ||
1105 | |||
1106 | /* Length must align on block boundary */ | ||
1107 | if (unlikely(instr->len & (block_size - 1))) { | ||
1108 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block aligned\n"); | ||
1109 | return -EINVAL; | ||
1110 | } | ||
1111 | |||
1112 | /* Do not allow erase past end of device */ | ||
1113 | if (unlikely((instr->len + instr->addr) > mtd->size)) { | ||
1114 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n"); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | |||
1118 | instr->fail_addr = 0xffffffff; | ||
1119 | |||
1120 | /* Grab the lock and see if the device is available */ | ||
1121 | onenand_get_device(mtd, FL_ERASING); | ||
1122 | |||
1123 | /* Loop throught the pages */ | ||
1124 | len = instr->len; | ||
1125 | addr = instr->addr; | ||
1126 | |||
1127 | instr->state = MTD_ERASING; | ||
1128 | |||
1129 | while (len) { | ||
1130 | |||
1131 | /* Check if we have a bad block, we do not erase bad blocks */ | ||
1132 | if (onenand_block_checkbad(mtd, addr, 0, 0)) { | ||
1133 | printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); | ||
1134 | instr->state = MTD_ERASE_FAILED; | ||
1135 | goto erase_exit; | ||
1136 | } | ||
1137 | |||
1138 | this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); | ||
1139 | |||
1140 | ret = this->wait(mtd, FL_ERASING); | ||
1141 | /* Check, if it is write protected */ | ||
1142 | if (ret) { | ||
1143 | if (ret == -EPERM) | ||
1144 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n"); | ||
1145 | else | ||
1146 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); | ||
1147 | instr->state = MTD_ERASE_FAILED; | ||
1148 | instr->fail_addr = addr; | ||
1149 | goto erase_exit; | ||
1150 | } | ||
1151 | |||
1152 | len -= block_size; | ||
1153 | addr += block_size; | ||
1154 | } | ||
1155 | |||
1156 | instr->state = MTD_ERASE_DONE; | ||
1157 | |||
1158 | erase_exit: | ||
1159 | |||
1160 | ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; | ||
1161 | /* Do call back function */ | ||
1162 | if (!ret) | ||
1163 | mtd_erase_callback(instr); | ||
1164 | |||
1165 | /* Deselect and wake up anyone waiting on the device */ | ||
1166 | onenand_release_device(mtd); | ||
1167 | |||
1168 | return ret; | ||
1169 | } | ||
1170 | |||
1171 | /** | ||
1172 | * onenand_sync - [MTD Interface] sync | ||
1173 | * @param mtd MTD device structure | ||
1174 | * | ||
1175 | * Sync is actually a wait for chip ready function | ||
1176 | */ | ||
1177 | static void onenand_sync(struct mtd_info *mtd) | ||
1178 | { | ||
1179 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_sync: called\n"); | ||
1180 | |||
1181 | /* Grab the lock and see if the device is available */ | ||
1182 | onenand_get_device(mtd, FL_SYNCING); | ||
1183 | |||
1184 | /* Release it and go back */ | ||
1185 | onenand_release_device(mtd); | ||
1186 | } | ||
1187 | |||
1188 | |||
1189 | /** | ||
1190 | * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad | ||
1191 | * @param mtd MTD device structure | ||
1192 | * @param ofs offset relative to mtd start | ||
1193 | * | ||
1194 | * Check whether the block is bad | ||
1195 | */ | ||
1196 | static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) | ||
1197 | { | ||
1198 | /* Check for invalid offset */ | ||
1199 | if (ofs > mtd->size) | ||
1200 | return -EINVAL; | ||
1201 | |||
1202 | return onenand_block_checkbad(mtd, ofs, 1, 0); | ||
1203 | } | ||
1204 | |||
1205 | /** | ||
1206 | * onenand_default_block_markbad - [DEFAULT] mark a block bad | ||
1207 | * @param mtd MTD device structure | ||
1208 | * @param ofs offset from device start | ||
1209 | * | ||
1210 | * This is the default implementation, which can be overridden by | ||
1211 | * a hardware specific driver. | ||
1212 | */ | ||
1213 | static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||
1214 | { | ||
1215 | struct onenand_chip *this = mtd->priv; | ||
1216 | struct bbm_info *bbm = this->bbm; | ||
1217 | u_char buf[2] = {0, 0}; | ||
1218 | size_t retlen; | ||
1219 | int block; | ||
1220 | |||
1221 | /* Get block number */ | ||
1222 | block = ((int) ofs) >> bbm->bbt_erase_shift; | ||
1223 | if (bbm->bbt) | ||
1224 | bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); | ||
1225 | |||
1226 | /* We write two bytes, so we dont have to mess with 16 bit access */ | ||
1227 | ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); | ||
1228 | return mtd->write_oob(mtd, ofs , 2, &retlen, buf); | ||
1229 | } | ||
1230 | |||
1231 | /** | ||
1232 | * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad | ||
1233 | * @param mtd MTD device structure | ||
1234 | * @param ofs offset relative to mtd start | ||
1235 | * | ||
1236 | * Mark the block as bad | ||
1237 | */ | ||
1238 | static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||
1239 | { | ||
1240 | struct onenand_chip *this = mtd->priv; | ||
1241 | int ret; | ||
1242 | |||
1243 | ret = onenand_block_isbad(mtd, ofs); | ||
1244 | if (ret) { | ||
1245 | /* If it was bad already, return success and do nothing */ | ||
1246 | if (ret > 0) | ||
1247 | return 0; | ||
1248 | return ret; | ||
1249 | } | ||
1250 | |||
1251 | return this->block_markbad(mtd, ofs); | ||
1252 | } | ||
1253 | |||
1254 | /** | ||
1255 | * onenand_unlock - [MTD Interface] Unlock block(s) | ||
1256 | * @param mtd MTD device structure | ||
1257 | * @param ofs offset relative to mtd start | ||
1258 | * @param len number of bytes to unlock | ||
1259 | * | ||
1260 | * Unlock one or more blocks | ||
1261 | */ | ||
1262 | static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | ||
1263 | { | ||
1264 | struct onenand_chip *this = mtd->priv; | ||
1265 | int start, end, block, value, status; | ||
1266 | |||
1267 | start = ofs >> this->erase_shift; | ||
1268 | end = len >> this->erase_shift; | ||
1269 | |||
1270 | /* Continuous lock scheme */ | ||
1271 | if (this->options & ONENAND_CONT_LOCK) { | ||
1272 | /* Set start block address */ | ||
1273 | this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); | ||
1274 | /* Set end block address */ | ||
1275 | this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); | ||
1276 | /* Write unlock command */ | ||
1277 | this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); | ||
1278 | |||
1279 | /* There's no return value */ | ||
1280 | this->wait(mtd, FL_UNLOCKING); | ||
1281 | |||
1282 | /* Sanity check */ | ||
1283 | while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) | ||
1284 | & ONENAND_CTRL_ONGO) | ||
1285 | continue; | ||
1286 | |||
1287 | /* Check lock status */ | ||
1288 | status = this->read_word(this->base + ONENAND_REG_WP_STATUS); | ||
1289 | if (!(status & ONENAND_WP_US)) | ||
1290 | printk(KERN_ERR "wp status = 0x%x\n", status); | ||
1291 | |||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | /* Block lock scheme */ | ||
1296 | for (block = start; block < end; block++) { | ||
1297 | /* Set start block address */ | ||
1298 | this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); | ||
1299 | /* Write unlock command */ | ||
1300 | this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); | ||
1301 | |||
1302 | /* There's no return value */ | ||
1303 | this->wait(mtd, FL_UNLOCKING); | ||
1304 | |||
1305 | /* Sanity check */ | ||
1306 | while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) | ||
1307 | & ONENAND_CTRL_ONGO) | ||
1308 | continue; | ||
1309 | |||
1310 | /* Set block address for read block status */ | ||
1311 | value = onenand_block_address(this, block); | ||
1312 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | ||
1313 | |||
1314 | /* Check lock status */ | ||
1315 | status = this->read_word(this->base + ONENAND_REG_WP_STATUS); | ||
1316 | if (!(status & ONENAND_WP_US)) | ||
1317 | printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); | ||
1318 | } | ||
1319 | |||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | /** | ||
1324 | * onenand_print_device_info - Print device ID | ||
1325 | * @param device device ID | ||
1326 | * | ||
1327 | * Print device ID | ||
1328 | */ | ||
1329 | static void onenand_print_device_info(int device) | ||
1330 | { | ||
1331 | int vcc, demuxed, ddp, density; | ||
1332 | |||
1333 | vcc = device & ONENAND_DEVICE_VCC_MASK; | ||
1334 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; | ||
1335 | ddp = device & ONENAND_DEVICE_IS_DDP; | ||
1336 | density = device >> ONENAND_DEVICE_DENSITY_SHIFT; | ||
1337 | printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", | ||
1338 | demuxed ? "" : "Muxed ", | ||
1339 | ddp ? "(DDP)" : "", | ||
1340 | (16 << density), | ||
1341 | vcc ? "2.65/3.3" : "1.8", | ||
1342 | device); | ||
1343 | } | ||
1344 | |||
1345 | static const struct onenand_manufacturers onenand_manuf_ids[] = { | ||
1346 | {ONENAND_MFR_SAMSUNG, "Samsung"}, | ||
1347 | {ONENAND_MFR_UNKNOWN, "Unknown"} | ||
1348 | }; | ||
1349 | |||
1350 | /** | ||
1351 | * onenand_check_maf - Check manufacturer ID | ||
1352 | * @param manuf manufacturer ID | ||
1353 | * | ||
1354 | * Check manufacturer ID | ||
1355 | */ | ||
1356 | static int onenand_check_maf(int manuf) | ||
1357 | { | ||
1358 | int i; | ||
1359 | |||
1360 | for (i = 0; onenand_manuf_ids[i].id; i++) { | ||
1361 | if (manuf == onenand_manuf_ids[i].id) | ||
1362 | break; | ||
1363 | } | ||
1364 | |||
1365 | printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", | ||
1366 | onenand_manuf_ids[i].name, manuf); | ||
1367 | |||
1368 | return (i != ONENAND_MFR_UNKNOWN); | ||
1369 | } | ||
1370 | |||
1371 | /** | ||
1372 | * onenand_probe - [OneNAND Interface] Probe the OneNAND device | ||
1373 | * @param mtd MTD device structure | ||
1374 | * | ||
1375 | * OneNAND detection method: | ||
1376 | * Compare the the values from command with ones from register | ||
1377 | */ | ||
1378 | static int onenand_probe(struct mtd_info *mtd) | ||
1379 | { | ||
1380 | struct onenand_chip *this = mtd->priv; | ||
1381 | int bram_maf_id, bram_dev_id, maf_id, dev_id; | ||
1382 | int version_id; | ||
1383 | int density; | ||
1384 | |||
1385 | /* Send the command for reading device ID from BootRAM */ | ||
1386 | this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM); | ||
1387 | |||
1388 | /* Read manufacturer and device IDs from BootRAM */ | ||
1389 | bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0); | ||
1390 | bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2); | ||
1391 | |||
1392 | /* Check manufacturer ID */ | ||
1393 | if (onenand_check_maf(bram_maf_id)) | ||
1394 | return -ENXIO; | ||
1395 | |||
1396 | /* Reset OneNAND to read default register values */ | ||
1397 | this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); | ||
1398 | |||
1399 | /* Read manufacturer and device IDs from Register */ | ||
1400 | maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); | ||
1401 | dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); | ||
1402 | |||
1403 | /* Check OneNAND device */ | ||
1404 | if (maf_id != bram_maf_id || dev_id != bram_dev_id) | ||
1405 | return -ENXIO; | ||
1406 | |||
1407 | /* Flash device information */ | ||
1408 | onenand_print_device_info(dev_id); | ||
1409 | this->device_id = dev_id; | ||
1410 | |||
1411 | density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | ||
1412 | this->chipsize = (16 << density) << 20; | ||
1413 | /* Set density mask. it is used for DDP */ | ||
1414 | this->density_mask = (1 << (density + 6)); | ||
1415 | |||
1416 | /* OneNAND page size & block size */ | ||
1417 | /* The data buffer size is equal to page size */ | ||
1418 | mtd->oobblock = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); | ||
1419 | mtd->oobsize = mtd->oobblock >> 5; | ||
1420 | /* Pagers per block is always 64 in OneNAND */ | ||
1421 | mtd->erasesize = mtd->oobblock << 6; | ||
1422 | |||
1423 | this->erase_shift = ffs(mtd->erasesize) - 1; | ||
1424 | this->page_shift = ffs(mtd->oobblock) - 1; | ||
1425 | this->ppb_shift = (this->erase_shift - this->page_shift); | ||
1426 | this->page_mask = (mtd->erasesize / mtd->oobblock) - 1; | ||
1427 | |||
1428 | /* REVIST: Multichip handling */ | ||
1429 | |||
1430 | mtd->size = this->chipsize; | ||
1431 | |||
1432 | /* Version ID */ | ||
1433 | version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); | ||
1434 | printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id); | ||
1435 | |||
1436 | /* Lock scheme */ | ||
1437 | if (density <= ONENAND_DEVICE_DENSITY_512Mb && | ||
1438 | !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) { | ||
1439 | printk(KERN_INFO "Lock scheme is Continues Lock\n"); | ||
1440 | this->options |= ONENAND_CONT_LOCK; | ||
1441 | } | ||
1442 | |||
1443 | return 0; | ||
1444 | } | ||
1445 | |||
1446 | /** | ||
1447 | * onenand_suspend - [MTD Interface] Suspend the OneNAND flash | ||
1448 | * @param mtd MTD device structure | ||
1449 | */ | ||
1450 | static int onenand_suspend(struct mtd_info *mtd) | ||
1451 | { | ||
1452 | return onenand_get_device(mtd, FL_PM_SUSPENDED); | ||
1453 | } | ||
1454 | |||
1455 | /** | ||
1456 | * onenand_resume - [MTD Interface] Resume the OneNAND flash | ||
1457 | * @param mtd MTD device structure | ||
1458 | */ | ||
1459 | static void onenand_resume(struct mtd_info *mtd) | ||
1460 | { | ||
1461 | struct onenand_chip *this = mtd->priv; | ||
1462 | |||
1463 | if (this->state == FL_PM_SUSPENDED) | ||
1464 | onenand_release_device(mtd); | ||
1465 | else | ||
1466 | printk(KERN_ERR "resume() called for the chip which is not" | ||
1467 | "in suspended state\n"); | ||
1468 | } | ||
1469 | |||
1470 | |||
1471 | /** | ||
1472 | * onenand_scan - [OneNAND Interface] Scan for the OneNAND device | ||
1473 | * @param mtd MTD device structure | ||
1474 | * @param maxchips Number of chips to scan for | ||
1475 | * | ||
1476 | * This fills out all the not initialized function pointers | ||
1477 | * with the defaults. | ||
1478 | * The flash ID is read and the mtd/chip structures are | ||
1479 | * filled with the appropriate values. | ||
1480 | */ | ||
1481 | int onenand_scan(struct mtd_info *mtd, int maxchips) | ||
1482 | { | ||
1483 | struct onenand_chip *this = mtd->priv; | ||
1484 | |||
1485 | if (!this->read_word) | ||
1486 | this->read_word = onenand_readw; | ||
1487 | if (!this->write_word) | ||
1488 | this->write_word = onenand_writew; | ||
1489 | |||
1490 | if (!this->command) | ||
1491 | this->command = onenand_command; | ||
1492 | if (!this->wait) | ||
1493 | this->wait = onenand_wait; | ||
1494 | |||
1495 | if (!this->read_bufferram) | ||
1496 | this->read_bufferram = onenand_read_bufferram; | ||
1497 | if (!this->write_bufferram) | ||
1498 | this->write_bufferram = onenand_write_bufferram; | ||
1499 | |||
1500 | if (!this->block_markbad) | ||
1501 | this->block_markbad = onenand_default_block_markbad; | ||
1502 | if (!this->scan_bbt) | ||
1503 | this->scan_bbt = onenand_default_bbt; | ||
1504 | |||
1505 | if (onenand_probe(mtd)) | ||
1506 | return -ENXIO; | ||
1507 | |||
1508 | /* Set Sync. Burst Read after probing */ | ||
1509 | if (this->mmcontrol) { | ||
1510 | printk(KERN_INFO "OneNAND Sync. Burst Read support\n"); | ||
1511 | this->read_bufferram = onenand_sync_read_bufferram; | ||
1512 | } | ||
1513 | |||
1514 | this->state = FL_READY; | ||
1515 | init_waitqueue_head(&this->wq); | ||
1516 | spin_lock_init(&this->chip_lock); | ||
1517 | |||
1518 | switch (mtd->oobsize) { | ||
1519 | case 64: | ||
1520 | this->autooob = &onenand_oob_64; | ||
1521 | break; | ||
1522 | |||
1523 | case 32: | ||
1524 | this->autooob = &onenand_oob_32; | ||
1525 | break; | ||
1526 | |||
1527 | default: | ||
1528 | printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", | ||
1529 | mtd->oobsize); | ||
1530 | /* To prevent kernel oops */ | ||
1531 | this->autooob = &onenand_oob_32; | ||
1532 | break; | ||
1533 | } | ||
1534 | |||
1535 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); | ||
1536 | |||
1537 | /* Fill in remaining MTD driver data */ | ||
1538 | mtd->type = MTD_NANDFLASH; | ||
1539 | mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; | ||
1540 | mtd->ecctype = MTD_ECC_SW; | ||
1541 | mtd->erase = onenand_erase; | ||
1542 | mtd->point = NULL; | ||
1543 | mtd->unpoint = NULL; | ||
1544 | mtd->read = onenand_read; | ||
1545 | mtd->write = onenand_write; | ||
1546 | mtd->read_ecc = onenand_read_ecc; | ||
1547 | mtd->write_ecc = onenand_write_ecc; | ||
1548 | mtd->read_oob = onenand_read_oob; | ||
1549 | mtd->write_oob = onenand_write_oob; | ||
1550 | mtd->readv = NULL; | ||
1551 | mtd->readv_ecc = NULL; | ||
1552 | mtd->writev = onenand_writev; | ||
1553 | mtd->writev_ecc = onenand_writev_ecc; | ||
1554 | mtd->sync = onenand_sync; | ||
1555 | mtd->lock = NULL; | ||
1556 | mtd->unlock = onenand_unlock; | ||
1557 | mtd->suspend = onenand_suspend; | ||
1558 | mtd->resume = onenand_resume; | ||
1559 | mtd->block_isbad = onenand_block_isbad; | ||
1560 | mtd->block_markbad = onenand_block_markbad; | ||
1561 | mtd->owner = THIS_MODULE; | ||
1562 | |||
1563 | /* Unlock whole block */ | ||
1564 | mtd->unlock(mtd, 0x0, this->chipsize); | ||
1565 | |||
1566 | return this->scan_bbt(mtd); | ||
1567 | } | ||
1568 | |||
1569 | /** | ||
1570 | * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device | ||
1571 | * @param mtd MTD device structure | ||
1572 | */ | ||
1573 | void onenand_release(struct mtd_info *mtd) | ||
1574 | { | ||
1575 | #ifdef CONFIG_MTD_PARTITIONS | ||
1576 | /* Deregister partitions */ | ||
1577 | del_mtd_partitions (mtd); | ||
1578 | #endif | ||
1579 | /* Deregister the device */ | ||
1580 | del_mtd_device (mtd); | ||
1581 | } | ||
1582 | |||
1583 | EXPORT_SYMBOL_GPL(onenand_scan); | ||
1584 | EXPORT_SYMBOL_GPL(onenand_release); | ||
1585 | |||
1586 | MODULE_LICENSE("GPL"); | ||
1587 | MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); | ||
1588 | MODULE_DESCRIPTION("Generic OneNAND flash driver code"); | ||
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c new file mode 100644 index 000000000000..f40190f499e1 --- /dev/null +++ b/drivers/mtd/onenand/onenand_bbt.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * linux/drivers/mtd/onenand/onenand_bbt.c | ||
3 | * | ||
4 | * Bad Block Table support for the OneNAND driver | ||
5 | * | ||
6 | * Copyright(c) 2005 Samsung Electronics | ||
7 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
8 | * | ||
9 | * Derived from nand_bbt.c | ||
10 | * | ||
11 | * TODO: | ||
12 | * Split BBT core and chip specific BBT. | ||
13 | */ | ||
14 | |||
15 | #include <linux/slab.h> | ||
16 | #include <linux/mtd/mtd.h> | ||
17 | #include <linux/mtd/onenand.h> | ||
18 | #include <linux/mtd/compatmac.h> | ||
19 | |||
20 | /** | ||
21 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer | ||
22 | * @param buf the buffer to search | ||
23 | * @param len the length of buffer to search | ||
24 | * @param paglen the pagelength | ||
25 | * @param td search pattern descriptor | ||
26 | * | ||
27 | * Check for a pattern at the given place. Used to search bad block | ||
28 | * tables and good / bad block identifiers. Same as check_pattern, but | ||
29 | * no optional empty check and the pattern is expected to start | ||
30 | * at offset 0. | ||
31 | * | ||
32 | */ | ||
33 | static int check_short_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) | ||
34 | { | ||
35 | int i; | ||
36 | uint8_t *p = buf; | ||
37 | |||
38 | /* Compare the pattern */ | ||
39 | for (i = 0; i < td->len; i++) { | ||
40 | if (p[i] != td->pattern[i]) | ||
41 | return -1; | ||
42 | } | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * create_bbt - [GENERIC] Create a bad block table by scanning the device | ||
48 | * @param mtd MTD device structure | ||
49 | * @param buf temporary buffer | ||
50 | * @param bd descriptor for the good/bad block search pattern | ||
51 | * @param chip create the table for a specific chip, -1 read all chips. | ||
52 | * Applies only if NAND_BBT_PERCHIP option is set | ||
53 | * | ||
54 | * Create a bad block table by scanning the device | ||
55 | * for the given good/bad block identify pattern | ||
56 | */ | ||
57 | static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) | ||
58 | { | ||
59 | struct onenand_chip *this = mtd->priv; | ||
60 | struct bbm_info *bbm = this->bbm; | ||
61 | int i, j, numblocks, len, scanlen; | ||
62 | int startblock; | ||
63 | loff_t from; | ||
64 | size_t readlen, ooblen; | ||
65 | |||
66 | printk(KERN_INFO "Scanning device for bad blocks\n"); | ||
67 | |||
68 | len = 1; | ||
69 | |||
70 | /* We need only read few bytes from the OOB area */ | ||
71 | scanlen = ooblen = 0; | ||
72 | readlen = bd->len; | ||
73 | |||
74 | /* chip == -1 case only */ | ||
75 | /* Note that numblocks is 2 * (real numblocks) here; | ||
76 | * see i += 2 below as it makses shifting and masking less painful | ||
77 | */ | ||
78 | numblocks = mtd->size >> (bbm->bbt_erase_shift - 1); | ||
79 | startblock = 0; | ||
80 | from = 0; | ||
81 | |||
82 | for (i = startblock; i < numblocks; ) { | ||
83 | int ret; | ||
84 | |||
85 | for (j = 0; j < len; j++) { | ||
86 | size_t retlen; | ||
87 | |||
88 | /* No need to read pages fully, | ||
89 | * just read required OOB bytes */ | ||
90 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs, | ||
91 | readlen, &retlen, &buf[0]); | ||
92 | |||
93 | if (ret) | ||
94 | return ret; | ||
95 | |||
96 | if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | ||
97 | bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); | ||
98 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | ||
99 | i >> 1, (unsigned int) from); | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | i += 2; | ||
104 | from += (1 << bbm->bbt_erase_shift); | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | |||
111 | /** | ||
112 | * onenand_memory_bbt - [GENERIC] create a memory based bad block table | ||
113 | * @param mtd MTD device structure | ||
114 | * @param bd descriptor for the good/bad block search pattern | ||
115 | * | ||
116 | * The function creates a memory based bbt by scanning the device | ||
117 | * for manufacturer / software marked good / bad blocks | ||
118 | */ | ||
119 | static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | ||
120 | { | ||
121 | unsigned char data_buf[MAX_ONENAND_PAGESIZE]; | ||
122 | |||
123 | bd->options &= ~NAND_BBT_SCANEMPTY; | ||
124 | return create_bbt(mtd, data_buf, bd, -1); | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad | ||
129 | * @param mtd MTD device structure | ||
130 | * @param offs offset in the device | ||
131 | * @param allowbbt allow access to bad block table region | ||
132 | */ | ||
133 | static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) | ||
134 | { | ||
135 | struct onenand_chip *this = mtd->priv; | ||
136 | struct bbm_info *bbm = this->bbm; | ||
137 | int block; | ||
138 | uint8_t res; | ||
139 | |||
140 | /* Get block number * 2 */ | ||
141 | block = (int) (offs >> (bbm->bbt_erase_shift - 1)); | ||
142 | res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; | ||
143 | |||
144 | DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", | ||
145 | (unsigned int) offs, block >> 1, res); | ||
146 | |||
147 | switch ((int) res) { | ||
148 | case 0x00: return 0; | ||
149 | case 0x01: return 1; | ||
150 | case 0x02: return allowbbt ? 0 : 1; | ||
151 | } | ||
152 | |||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s) | ||
158 | * @param mtd MTD device structure | ||
159 | * @param bd descriptor for the good/bad block search pattern | ||
160 | * | ||
161 | * The function checks, if a bad block table(s) is/are already | ||
162 | * available. If not it scans the device for manufacturer | ||
163 | * marked good / bad blocks and writes the bad block table(s) to | ||
164 | * the selected place. | ||
165 | * | ||
166 | * The bad block table memory is allocated here. It must be freed | ||
167 | * by calling the onenand_free_bbt function. | ||
168 | * | ||
169 | */ | ||
170 | int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) | ||
171 | { | ||
172 | struct onenand_chip *this = mtd->priv; | ||
173 | struct bbm_info *bbm = this->bbm; | ||
174 | int len, ret = 0; | ||
175 | |||
176 | len = mtd->size >> (this->erase_shift + 2); | ||
177 | /* Allocate memory (2bit per block) */ | ||
178 | bbm->bbt = kmalloc(len, GFP_KERNEL); | ||
179 | if (!bbm->bbt) { | ||
180 | printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); | ||
181 | return -ENOMEM; | ||
182 | } | ||
183 | /* Clear the memory bad block table */ | ||
184 | memset(bbm->bbt, 0x00, len); | ||
185 | |||
186 | /* Set the bad block position */ | ||
187 | bbm->badblockpos = ONENAND_BADBLOCK_POS; | ||
188 | |||
189 | /* Set erase shift */ | ||
190 | bbm->bbt_erase_shift = this->erase_shift; | ||
191 | |||
192 | if (!bbm->isbad_bbt) | ||
193 | bbm->isbad_bbt = onenand_isbad_bbt; | ||
194 | |||
195 | /* Scan the device to build a memory based bad block table */ | ||
196 | if ((ret = onenand_memory_bbt(mtd, bd))) { | ||
197 | printk(KERN_ERR "onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n"); | ||
198 | kfree(bbm->bbt); | ||
199 | bbm->bbt = NULL; | ||
200 | } | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Define some generic bad / good block scan pattern which are used | ||
207 | * while scanning a device for factory marked good / bad blocks. | ||
208 | */ | ||
209 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | ||
210 | |||
211 | static struct nand_bbt_descr largepage_memorybased = { | ||
212 | .options = 0, | ||
213 | .offs = 0, | ||
214 | .len = 2, | ||
215 | .pattern = scan_ff_pattern, | ||
216 | }; | ||
217 | |||
218 | /** | ||
219 | * onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device | ||
220 | * @param mtd MTD device structure | ||
221 | * | ||
222 | * This function selects the default bad block table | ||
223 | * support for the device and calls the onenand_scan_bbt function | ||
224 | */ | ||
225 | int onenand_default_bbt(struct mtd_info *mtd) | ||
226 | { | ||
227 | struct onenand_chip *this = mtd->priv; | ||
228 | struct bbm_info *bbm; | ||
229 | |||
230 | this->bbm = kmalloc(sizeof(struct bbm_info), GFP_KERNEL); | ||
231 | if (!this->bbm) | ||
232 | return -ENOMEM; | ||
233 | |||
234 | bbm = this->bbm; | ||
235 | |||
236 | memset(bbm, 0, sizeof(struct bbm_info)); | ||
237 | |||
238 | /* 1KB page has same configuration as 2KB page */ | ||
239 | if (!bbm->badblock_pattern) | ||
240 | bbm->badblock_pattern = &largepage_memorybased; | ||
241 | |||
242 | return onenand_scan_bbt(mtd, bbm->badblock_pattern); | ||
243 | } | ||
244 | |||
245 | EXPORT_SYMBOL(onenand_scan_bbt); | ||
246 | EXPORT_SYMBOL(onenand_default_bbt); | ||
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 13f9e992bef8..7b7ca5ab5ae4 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $ | 2 | * $Id: redboot.c,v 1.18 2005/11/07 11:14:21 gleixner Exp $ |
3 | * | 3 | * |
4 | * Parse RedBoot-style Flash Image System (FIS) tables and | 4 | * Parse RedBoot-style Flash Image System (FIS) tables and |
5 | * produce a Linux partition array to match. | 5 | * produce a Linux partition array to match. |
@@ -39,7 +39,7 @@ static inline int redboot_checksum(struct fis_image_desc *img) | |||
39 | return 1; | 39 | return 1; |
40 | } | 40 | } |
41 | 41 | ||
42 | static int parse_redboot_partitions(struct mtd_info *master, | 42 | static int parse_redboot_partitions(struct mtd_info *master, |
43 | struct mtd_partition **pparts, | 43 | struct mtd_partition **pparts, |
44 | unsigned long fis_origin) | 44 | unsigned long fis_origin) |
45 | { | 45 | { |
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c new file mode 100644 index 000000000000..041ee59ea77d --- /dev/null +++ b/drivers/mtd/rfd_ftl.c | |||
@@ -0,0 +1,855 @@ | |||
1 | /* | ||
2 | * rfd_ftl.c -- resident flash disk (flash translation layer) | ||
3 | * | ||
4 | * Copyright (C) 2005 Sean Young <sean@mess.org> | ||
5 | * | ||
6 | * $Id: rfd_ftl.c,v 1.5 2005/11/07 11:14:21 gleixner Exp $ | ||
7 | * | ||
8 | * This type of flash translation layer (FTL) is used by the Embedded BIOS | ||
9 | * by General Software. It is known as the Resident Flash Disk (RFD), see: | ||
10 | * | ||
11 | * http://www.gensw.com/pages/prod/bios/rfd.htm | ||
12 | * | ||
13 | * based on ftl.c | ||
14 | */ | ||
15 | |||
16 | #include <linux/hdreg.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mtd/blktrans.h> | ||
19 | #include <linux/mtd/mtd.h> | ||
20 | #include <linux/vmalloc.h> | ||
21 | |||
22 | #include <asm/types.h> | ||
23 | |||
24 | #define const_cpu_to_le16 __constant_cpu_to_le16 | ||
25 | |||
26 | static int block_size = 0; | ||
27 | module_param(block_size, int, 0); | ||
28 | MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size"); | ||
29 | |||
30 | #define PREFIX "rfd_ftl: " | ||
31 | |||
32 | /* Major device # for FTL device */ | ||
33 | |||
34 | /* A request for this major has been sent to device@lanana.org */ | ||
35 | #ifndef RFD_FTL_MAJOR | ||
36 | #define RFD_FTL_MAJOR 95 | ||
37 | #endif | ||
38 | |||
39 | /* Maximum number of partitions in an FTL region */ | ||
40 | #define PART_BITS 4 | ||
41 | |||
42 | /* An erase unit should start with this value */ | ||
43 | #define RFD_MAGIC 0x9193 | ||
44 | |||
45 | /* the second value is 0xffff or 0xffc8; function unknown */ | ||
46 | |||
47 | /* the third value is always 0xffff, ignored */ | ||
48 | |||
49 | /* next is an array of mapping for each corresponding sector */ | ||
50 | #define HEADER_MAP_OFFSET 3 | ||
51 | #define SECTOR_DELETED 0x0000 | ||
52 | #define SECTOR_ZERO 0xfffe | ||
53 | #define SECTOR_FREE 0xffff | ||
54 | |||
55 | #define SECTOR_SIZE 512 | ||
56 | |||
57 | #define SECTORS_PER_TRACK 63 | ||
58 | |||
59 | struct block { | ||
60 | enum { | ||
61 | BLOCK_OK, | ||
62 | BLOCK_ERASING, | ||
63 | BLOCK_ERASED, | ||
64 | BLOCK_FAILED | ||
65 | } state; | ||
66 | int free_sectors; | ||
67 | int used_sectors; | ||
68 | int erases; | ||
69 | u_long offset; | ||
70 | }; | ||
71 | |||
72 | struct partition { | ||
73 | struct mtd_blktrans_dev mbd; | ||
74 | |||
75 | u_int block_size; /* size of erase unit */ | ||
76 | u_int total_blocks; /* number of erase units */ | ||
77 | u_int header_sectors_per_block; /* header sectors in erase unit */ | ||
78 | u_int data_sectors_per_block; /* data sectors in erase unit */ | ||
79 | u_int sector_count; /* sectors in translated disk */ | ||
80 | u_int header_size; /* bytes in header sector */ | ||
81 | int reserved_block; /* block next up for reclaim */ | ||
82 | int current_block; /* block to write to */ | ||
83 | u16 *header_cache; /* cached header */ | ||
84 | |||
85 | int is_reclaiming; | ||
86 | int cylinders; | ||
87 | int errors; | ||
88 | u_long *sector_map; | ||
89 | struct block *blocks; | ||
90 | }; | ||
91 | |||
92 | static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf); | ||
93 | |||
94 | static int build_block_map(struct partition *part, int block_no) | ||
95 | { | ||
96 | struct block *block = &part->blocks[block_no]; | ||
97 | int i; | ||
98 | |||
99 | block->offset = part->block_size * block_no; | ||
100 | |||
101 | if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) { | ||
102 | block->state = BLOCK_ERASED; /* assumption */ | ||
103 | block->free_sectors = part->data_sectors_per_block; | ||
104 | part->reserved_block = block_no; | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | block->state = BLOCK_OK; | ||
109 | |||
110 | for (i=0; i<part->data_sectors_per_block; i++) { | ||
111 | u16 entry; | ||
112 | |||
113 | entry = le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]); | ||
114 | |||
115 | if (entry == SECTOR_DELETED) | ||
116 | continue; | ||
117 | |||
118 | if (entry == SECTOR_FREE) { | ||
119 | block->free_sectors++; | ||
120 | continue; | ||
121 | } | ||
122 | |||
123 | if (entry == SECTOR_ZERO) | ||
124 | entry = 0; | ||
125 | |||
126 | if (entry >= part->sector_count) { | ||
127 | printk(KERN_NOTICE PREFIX | ||
128 | "'%s': unit #%d: entry %d corrupt, " | ||
129 | "sector %d out of range\n", | ||
130 | part->mbd.mtd->name, block_no, i, entry); | ||
131 | continue; | ||
132 | } | ||
133 | |||
134 | if (part->sector_map[entry] != -1) { | ||
135 | printk(KERN_NOTICE PREFIX | ||
136 | "'%s': more than one entry for sector %d\n", | ||
137 | part->mbd.mtd->name, entry); | ||
138 | part->errors = 1; | ||
139 | continue; | ||
140 | } | ||
141 | |||
142 | part->sector_map[entry] = block->offset + | ||
143 | (i + part->header_sectors_per_block) * SECTOR_SIZE; | ||
144 | |||
145 | block->used_sectors++; | ||
146 | } | ||
147 | |||
148 | if (block->free_sectors == part->data_sectors_per_block) | ||
149 | part->reserved_block = block_no; | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int scan_header(struct partition *part) | ||
155 | { | ||
156 | int sectors_per_block; | ||
157 | int i, rc = -ENOMEM; | ||
158 | int blocks_found; | ||
159 | size_t retlen; | ||
160 | |||
161 | sectors_per_block = part->block_size / SECTOR_SIZE; | ||
162 | part->total_blocks = part->mbd.mtd->size / part->block_size; | ||
163 | |||
164 | if (part->total_blocks < 2) | ||
165 | return -ENOENT; | ||
166 | |||
167 | /* each erase block has three bytes header, followed by the map */ | ||
168 | part->header_sectors_per_block = | ||
169 | ((HEADER_MAP_OFFSET + sectors_per_block) * | ||
170 | sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE; | ||
171 | |||
172 | part->data_sectors_per_block = sectors_per_block - | ||
173 | part->header_sectors_per_block; | ||
174 | |||
175 | part->header_size = (HEADER_MAP_OFFSET + | ||
176 | part->data_sectors_per_block) * sizeof(u16); | ||
177 | |||
178 | part->cylinders = (part->data_sectors_per_block * | ||
179 | (part->total_blocks - 1) - 1) / SECTORS_PER_TRACK; | ||
180 | |||
181 | part->sector_count = part->cylinders * SECTORS_PER_TRACK; | ||
182 | |||
183 | part->current_block = -1; | ||
184 | part->reserved_block = -1; | ||
185 | part->is_reclaiming = 0; | ||
186 | |||
187 | part->header_cache = kmalloc(part->header_size, GFP_KERNEL); | ||
188 | if (!part->header_cache) | ||
189 | goto err; | ||
190 | |||
191 | part->blocks = kcalloc(part->total_blocks, sizeof(struct block), | ||
192 | GFP_KERNEL); | ||
193 | if (!part->blocks) | ||
194 | goto err; | ||
195 | |||
196 | part->sector_map = vmalloc(part->sector_count * sizeof(u_long)); | ||
197 | if (!part->sector_map) { | ||
198 | printk(KERN_ERR PREFIX "'%s': unable to allocate memory for " | ||
199 | "sector map", part->mbd.mtd->name); | ||
200 | goto err; | ||
201 | } | ||
202 | |||
203 | for (i=0; i<part->sector_count; i++) | ||
204 | part->sector_map[i] = -1; | ||
205 | |||
206 | for (i=0, blocks_found=0; i<part->total_blocks; i++) { | ||
207 | rc = part->mbd.mtd->read(part->mbd.mtd, | ||
208 | i * part->block_size, part->header_size, | ||
209 | &retlen, (u_char*)part->header_cache); | ||
210 | |||
211 | if (!rc && retlen != part->header_size) | ||
212 | rc = -EIO; | ||
213 | |||
214 | if (rc) | ||
215 | goto err; | ||
216 | |||
217 | if (!build_block_map(part, i)) | ||
218 | blocks_found++; | ||
219 | } | ||
220 | |||
221 | if (blocks_found == 0) { | ||
222 | printk(KERN_NOTICE PREFIX "no RFD magic found in '%s'\n", | ||
223 | part->mbd.mtd->name); | ||
224 | rc = -ENOENT; | ||
225 | goto err; | ||
226 | } | ||
227 | |||
228 | if (part->reserved_block == -1) { | ||
229 | printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n", | ||
230 | part->mbd.mtd->name); | ||
231 | |||
232 | part->errors = 1; | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | |||
237 | err: | ||
238 | vfree(part->sector_map); | ||
239 | kfree(part->header_cache); | ||
240 | kfree(part->blocks); | ||
241 | |||
242 | return rc; | ||
243 | } | ||
244 | |||
245 | static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) | ||
246 | { | ||
247 | struct partition *part = (struct partition*)dev; | ||
248 | u_long addr; | ||
249 | size_t retlen; | ||
250 | int rc; | ||
251 | |||
252 | if (sector >= part->sector_count) | ||
253 | return -EIO; | ||
254 | |||
255 | addr = part->sector_map[sector]; | ||
256 | if (addr != -1) { | ||
257 | rc = part->mbd.mtd->read(part->mbd.mtd, addr, SECTOR_SIZE, | ||
258 | &retlen, (u_char*)buf); | ||
259 | if (!rc && retlen != SECTOR_SIZE) | ||
260 | rc = -EIO; | ||
261 | |||
262 | if (rc) { | ||
263 | printk(KERN_WARNING PREFIX "error reading '%s' at " | ||
264 | "0x%lx\n", part->mbd.mtd->name, addr); | ||
265 | return rc; | ||
266 | } | ||
267 | } else | ||
268 | memset(buf, 0, SECTOR_SIZE); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static void erase_callback(struct erase_info *erase) | ||
274 | { | ||
275 | struct partition *part; | ||
276 | u16 magic; | ||
277 | int i, rc; | ||
278 | size_t retlen; | ||
279 | |||
280 | part = (struct partition*)erase->priv; | ||
281 | |||
282 | i = erase->addr / part->block_size; | ||
283 | if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) { | ||
284 | printk(KERN_ERR PREFIX "erase callback for unknown offset %x " | ||
285 | "on '%s'\n", erase->addr, part->mbd.mtd->name); | ||
286 | return; | ||
287 | } | ||
288 | |||
289 | if (erase->state != MTD_ERASE_DONE) { | ||
290 | printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', " | ||
291 | "state %d\n", erase->addr, | ||
292 | part->mbd.mtd->name, erase->state); | ||
293 | |||
294 | part->blocks[i].state = BLOCK_FAILED; | ||
295 | part->blocks[i].free_sectors = 0; | ||
296 | part->blocks[i].used_sectors = 0; | ||
297 | |||
298 | kfree(erase); | ||
299 | |||
300 | return; | ||
301 | } | ||
302 | |||
303 | magic = const_cpu_to_le16(RFD_MAGIC); | ||
304 | |||
305 | part->blocks[i].state = BLOCK_ERASED; | ||
306 | part->blocks[i].free_sectors = part->data_sectors_per_block; | ||
307 | part->blocks[i].used_sectors = 0; | ||
308 | part->blocks[i].erases++; | ||
309 | |||
310 | rc = part->mbd.mtd->write(part->mbd.mtd, | ||
311 | part->blocks[i].offset, sizeof(magic), &retlen, | ||
312 | (u_char*)&magic); | ||
313 | |||
314 | if (!rc && retlen != sizeof(magic)) | ||
315 | rc = -EIO; | ||
316 | |||
317 | if (rc) { | ||
318 | printk(KERN_NOTICE PREFIX "'%s': unable to write RFD " | ||
319 | "header at 0x%lx\n", | ||
320 | part->mbd.mtd->name, | ||
321 | part->blocks[i].offset); | ||
322 | part->blocks[i].state = BLOCK_FAILED; | ||
323 | } | ||
324 | else | ||
325 | part->blocks[i].state = BLOCK_OK; | ||
326 | |||
327 | kfree(erase); | ||
328 | } | ||
329 | |||
330 | static int erase_block(struct partition *part, int block) | ||
331 | { | ||
332 | struct erase_info *erase; | ||
333 | int rc = -ENOMEM; | ||
334 | |||
335 | erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); | ||
336 | if (!erase) | ||
337 | goto err; | ||
338 | |||
339 | erase->mtd = part->mbd.mtd; | ||
340 | erase->callback = erase_callback; | ||
341 | erase->addr = part->blocks[block].offset; | ||
342 | erase->len = part->block_size; | ||
343 | erase->priv = (u_long)part; | ||
344 | |||
345 | part->blocks[block].state = BLOCK_ERASING; | ||
346 | part->blocks[block].free_sectors = 0; | ||
347 | |||
348 | rc = part->mbd.mtd->erase(part->mbd.mtd, erase); | ||
349 | |||
350 | if (rc) { | ||
351 | printk(KERN_WARNING PREFIX "erase of region %x,%x on '%s' " | ||
352 | "failed\n", erase->addr, erase->len, | ||
353 | part->mbd.mtd->name); | ||
354 | kfree(erase); | ||
355 | } | ||
356 | |||
357 | err: | ||
358 | return rc; | ||
359 | } | ||
360 | |||
361 | static int move_block_contents(struct partition *part, int block_no, u_long *old_sector) | ||
362 | { | ||
363 | void *sector_data; | ||
364 | u16 *map; | ||
365 | size_t retlen; | ||
366 | int i, rc = -ENOMEM; | ||
367 | |||
368 | part->is_reclaiming = 1; | ||
369 | |||
370 | sector_data = kmalloc(SECTOR_SIZE, GFP_KERNEL); | ||
371 | if (!sector_data) | ||
372 | goto err3; | ||
373 | |||
374 | map = kmalloc(part->header_size, GFP_KERNEL); | ||
375 | if (!map) | ||
376 | goto err2; | ||
377 | |||
378 | rc = part->mbd.mtd->read(part->mbd.mtd, | ||
379 | part->blocks[block_no].offset, part->header_size, | ||
380 | &retlen, (u_char*)map); | ||
381 | |||
382 | if (!rc && retlen != part->header_size) | ||
383 | rc = -EIO; | ||
384 | |||
385 | if (rc) { | ||
386 | printk(KERN_NOTICE PREFIX "error reading '%s' at " | ||
387 | "0x%lx\n", part->mbd.mtd->name, | ||
388 | part->blocks[block_no].offset); | ||
389 | |||
390 | goto err; | ||
391 | } | ||
392 | |||
393 | for (i=0; i<part->data_sectors_per_block; i++) { | ||
394 | u16 entry = le16_to_cpu(map[HEADER_MAP_OFFSET + i]); | ||
395 | u_long addr; | ||
396 | |||
397 | |||
398 | if (entry == SECTOR_FREE || entry == SECTOR_DELETED) | ||
399 | continue; | ||
400 | |||
401 | if (entry == SECTOR_ZERO) | ||
402 | entry = 0; | ||
403 | |||
404 | /* already warned about and ignored in build_block_map() */ | ||
405 | if (entry >= part->sector_count) | ||
406 | continue; | ||
407 | |||
408 | addr = part->blocks[block_no].offset + | ||
409 | (i + part->header_sectors_per_block) * SECTOR_SIZE; | ||
410 | |||
411 | if (*old_sector == addr) { | ||
412 | *old_sector = -1; | ||
413 | if (!part->blocks[block_no].used_sectors--) { | ||
414 | rc = erase_block(part, block_no); | ||
415 | break; | ||
416 | } | ||
417 | continue; | ||
418 | } | ||
419 | rc = part->mbd.mtd->read(part->mbd.mtd, addr, | ||
420 | SECTOR_SIZE, &retlen, sector_data); | ||
421 | |||
422 | if (!rc && retlen != SECTOR_SIZE) | ||
423 | rc = -EIO; | ||
424 | |||
425 | if (rc) { | ||
426 | printk(KERN_NOTICE PREFIX "'%s': Unable to " | ||
427 | "read sector for relocation\n", | ||
428 | part->mbd.mtd->name); | ||
429 | |||
430 | goto err; | ||
431 | } | ||
432 | |||
433 | rc = rfd_ftl_writesect((struct mtd_blktrans_dev*)part, | ||
434 | entry, sector_data); | ||
435 | |||
436 | if (rc) | ||
437 | goto err; | ||
438 | } | ||
439 | |||
440 | err: | ||
441 | kfree(map); | ||
442 | err2: | ||
443 | kfree(sector_data); | ||
444 | err3: | ||
445 | part->is_reclaiming = 0; | ||
446 | |||
447 | return rc; | ||
448 | } | ||
449 | |||
450 | static int reclaim_block(struct partition *part, u_long *old_sector) | ||
451 | { | ||
452 | int block, best_block, score, old_sector_block; | ||
453 | int rc; | ||
454 | |||
455 | /* we have a race if sync doesn't exist */ | ||
456 | if (part->mbd.mtd->sync) | ||
457 | part->mbd.mtd->sync(part->mbd.mtd); | ||
458 | |||
459 | score = 0x7fffffff; /* MAX_INT */ | ||
460 | best_block = -1; | ||
461 | if (*old_sector != -1) | ||
462 | old_sector_block = *old_sector / part->block_size; | ||
463 | else | ||
464 | old_sector_block = -1; | ||
465 | |||
466 | for (block=0; block<part->total_blocks; block++) { | ||
467 | int this_score; | ||
468 | |||
469 | if (block == part->reserved_block) | ||
470 | continue; | ||
471 | |||
472 | /* | ||
473 | * Postpone reclaiming if there is a free sector as | ||
474 | * more removed sectors is more efficient (have to move | ||
475 | * less). | ||
476 | */ | ||
477 | if (part->blocks[block].free_sectors) | ||
478 | return 0; | ||
479 | |||
480 | this_score = part->blocks[block].used_sectors; | ||
481 | |||
482 | if (block == old_sector_block) | ||
483 | this_score--; | ||
484 | else { | ||
485 | /* no point in moving a full block */ | ||
486 | if (part->blocks[block].used_sectors == | ||
487 | part->data_sectors_per_block) | ||
488 | continue; | ||
489 | } | ||
490 | |||
491 | this_score += part->blocks[block].erases; | ||
492 | |||
493 | if (this_score < score) { | ||
494 | best_block = block; | ||
495 | score = this_score; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | if (best_block == -1) | ||
500 | return -ENOSPC; | ||
501 | |||
502 | part->current_block = -1; | ||
503 | part->reserved_block = best_block; | ||
504 | |||
505 | pr_debug("reclaim_block: reclaiming block #%d with %d used " | ||
506 | "%d free sectors\n", best_block, | ||
507 | part->blocks[best_block].used_sectors, | ||
508 | part->blocks[best_block].free_sectors); | ||
509 | |||
510 | if (part->blocks[best_block].used_sectors) | ||
511 | rc = move_block_contents(part, best_block, old_sector); | ||
512 | else | ||
513 | rc = erase_block(part, best_block); | ||
514 | |||
515 | return rc; | ||
516 | } | ||
517 | |||
518 | /* | ||
519 | * IMPROVE: It would be best to choose the block with the most deleted sectors, | ||
520 | * because if we fill that one up first it'll have the most chance of having | ||
521 | * the least live sectors at reclaim. | ||
522 | */ | ||
523 | static int find_free_block(const struct partition *part) | ||
524 | { | ||
525 | int block, stop; | ||
526 | |||
527 | block = part->current_block == -1 ? | ||
528 | jiffies % part->total_blocks : part->current_block; | ||
529 | stop = block; | ||
530 | |||
531 | do { | ||
532 | if (part->blocks[block].free_sectors && | ||
533 | block != part->reserved_block) | ||
534 | return block; | ||
535 | |||
536 | if (++block >= part->total_blocks) | ||
537 | block = 0; | ||
538 | |||
539 | } while (block != stop); | ||
540 | |||
541 | return -1; | ||
542 | } | ||
543 | |||
544 | static int find_writeable_block(struct partition *part, u_long *old_sector) | ||
545 | { | ||
546 | int rc, block; | ||
547 | size_t retlen; | ||
548 | |||
549 | block = find_free_block(part); | ||
550 | |||
551 | if (block == -1) { | ||
552 | if (!part->is_reclaiming) { | ||
553 | rc = reclaim_block(part, old_sector); | ||
554 | if (rc) | ||
555 | goto err; | ||
556 | |||
557 | block = find_free_block(part); | ||
558 | } | ||
559 | |||
560 | if (block == -1) { | ||
561 | rc = -ENOSPC; | ||
562 | goto err; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset, | ||
567 | part->header_size, &retlen, (u_char*)part->header_cache); | ||
568 | |||
569 | if (!rc && retlen != part->header_size) | ||
570 | rc = -EIO; | ||
571 | |||
572 | if (rc) { | ||
573 | printk(KERN_NOTICE PREFIX "'%s': unable to read header at " | ||
574 | "0x%lx\n", part->mbd.mtd->name, | ||
575 | part->blocks[block].offset); | ||
576 | goto err; | ||
577 | } | ||
578 | |||
579 | part->current_block = block; | ||
580 | |||
581 | err: | ||
582 | return rc; | ||
583 | } | ||
584 | |||
585 | static int mark_sector_deleted(struct partition *part, u_long old_addr) | ||
586 | { | ||
587 | int block, offset, rc; | ||
588 | u_long addr; | ||
589 | size_t retlen; | ||
590 | u16 del = const_cpu_to_le16(SECTOR_DELETED); | ||
591 | |||
592 | block = old_addr / part->block_size; | ||
593 | offset = (old_addr % part->block_size) / SECTOR_SIZE - | ||
594 | part->header_sectors_per_block; | ||
595 | |||
596 | addr = part->blocks[block].offset + | ||
597 | (HEADER_MAP_OFFSET + offset) * sizeof(u16); | ||
598 | rc = part->mbd.mtd->write(part->mbd.mtd, addr, | ||
599 | sizeof(del), &retlen, (u_char*)&del); | ||
600 | |||
601 | if (!rc && retlen != sizeof(del)) | ||
602 | rc = -EIO; | ||
603 | |||
604 | if (rc) { | ||
605 | printk(KERN_WARNING PREFIX "error writing '%s' at " | ||
606 | "0x%lx\n", part->mbd.mtd->name, addr); | ||
607 | if (rc) | ||
608 | goto err; | ||
609 | } | ||
610 | if (block == part->current_block) | ||
611 | part->header_cache[offset + HEADER_MAP_OFFSET] = del; | ||
612 | |||
613 | part->blocks[block].used_sectors--; | ||
614 | |||
615 | if (!part->blocks[block].used_sectors && | ||
616 | !part->blocks[block].free_sectors) | ||
617 | rc = erase_block(part, block); | ||
618 | |||
619 | err: | ||
620 | return rc; | ||
621 | } | ||
622 | |||
623 | static int find_free_sector(const struct partition *part, const struct block *block) | ||
624 | { | ||
625 | int i, stop; | ||
626 | |||
627 | i = stop = part->data_sectors_per_block - block->free_sectors; | ||
628 | |||
629 | do { | ||
630 | if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]) | ||
631 | == SECTOR_FREE) | ||
632 | return i; | ||
633 | |||
634 | if (++i == part->data_sectors_per_block) | ||
635 | i = 0; | ||
636 | } | ||
637 | while(i != stop); | ||
638 | |||
639 | return -1; | ||
640 | } | ||
641 | |||
642 | static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ulong *old_addr) | ||
643 | { | ||
644 | struct partition *part = (struct partition*)dev; | ||
645 | struct block *block; | ||
646 | u_long addr; | ||
647 | int i; | ||
648 | int rc; | ||
649 | size_t retlen; | ||
650 | u16 entry; | ||
651 | |||
652 | if (part->current_block == -1 || | ||
653 | !part->blocks[part->current_block].free_sectors) { | ||
654 | |||
655 | rc = find_writeable_block(part, old_addr); | ||
656 | if (rc) | ||
657 | goto err; | ||
658 | } | ||
659 | |||
660 | block = &part->blocks[part->current_block]; | ||
661 | |||
662 | i = find_free_sector(part, block); | ||
663 | |||
664 | if (i < 0) { | ||
665 | rc = -ENOSPC; | ||
666 | goto err; | ||
667 | } | ||
668 | |||
669 | addr = (i + part->header_sectors_per_block) * SECTOR_SIZE + | ||
670 | block->offset; | ||
671 | rc = part->mbd.mtd->write(part->mbd.mtd, | ||
672 | addr, SECTOR_SIZE, &retlen, (u_char*)buf); | ||
673 | |||
674 | if (!rc && retlen != SECTOR_SIZE) | ||
675 | rc = -EIO; | ||
676 | |||
677 | if (rc) { | ||
678 | printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n", | ||
679 | part->mbd.mtd->name, addr); | ||
680 | if (rc) | ||
681 | goto err; | ||
682 | } | ||
683 | |||
684 | part->sector_map[sector] = addr; | ||
685 | |||
686 | entry = cpu_to_le16(sector == 0 ? SECTOR_ZERO : sector); | ||
687 | |||
688 | part->header_cache[i + HEADER_MAP_OFFSET] = entry; | ||
689 | |||
690 | addr = block->offset + (HEADER_MAP_OFFSET + i) * sizeof(u16); | ||
691 | rc = part->mbd.mtd->write(part->mbd.mtd, addr, | ||
692 | sizeof(entry), &retlen, (u_char*)&entry); | ||
693 | |||
694 | if (!rc && retlen != sizeof(entry)) | ||
695 | rc = -EIO; | ||
696 | |||
697 | if (rc) { | ||
698 | printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n", | ||
699 | part->mbd.mtd->name, addr); | ||
700 | if (rc) | ||
701 | goto err; | ||
702 | } | ||
703 | block->used_sectors++; | ||
704 | block->free_sectors--; | ||
705 | |||
706 | err: | ||
707 | return rc; | ||
708 | } | ||
709 | |||
710 | static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) | ||
711 | { | ||
712 | struct partition *part = (struct partition*)dev; | ||
713 | u_long old_addr; | ||
714 | int i; | ||
715 | int rc = 0; | ||
716 | |||
717 | pr_debug("rfd_ftl_writesect(sector=0x%lx)\n", sector); | ||
718 | |||
719 | if (part->reserved_block == -1) { | ||
720 | rc = -EACCES; | ||
721 | goto err; | ||
722 | } | ||
723 | |||
724 | if (sector >= part->sector_count) { | ||
725 | rc = -EIO; | ||
726 | goto err; | ||
727 | } | ||
728 | |||
729 | old_addr = part->sector_map[sector]; | ||
730 | |||
731 | for (i=0; i<SECTOR_SIZE; i++) { | ||
732 | if (!buf[i]) | ||
733 | continue; | ||
734 | |||
735 | rc = do_writesect(dev, sector, buf, &old_addr); | ||
736 | if (rc) | ||
737 | goto err; | ||
738 | break; | ||
739 | } | ||
740 | |||
741 | if (i == SECTOR_SIZE) | ||
742 | part->sector_map[sector] = -1; | ||
743 | |||
744 | if (old_addr != -1) | ||
745 | rc = mark_sector_deleted(part, old_addr); | ||
746 | |||
747 | err: | ||
748 | return rc; | ||
749 | } | ||
750 | |||
751 | static int rfd_ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) | ||
752 | { | ||
753 | struct partition *part = (struct partition*)dev; | ||
754 | |||
755 | geo->heads = 1; | ||
756 | geo->sectors = SECTORS_PER_TRACK; | ||
757 | geo->cylinders = part->cylinders; | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | ||
763 | { | ||
764 | struct partition *part; | ||
765 | |||
766 | if (mtd->type != MTD_NORFLASH) | ||
767 | return; | ||
768 | |||
769 | part = kcalloc(1, sizeof(struct partition), GFP_KERNEL); | ||
770 | if (!part) | ||
771 | return; | ||
772 | |||
773 | part->mbd.mtd = mtd; | ||
774 | |||
775 | if (block_size) | ||
776 | part->block_size = block_size; | ||
777 | else { | ||
778 | if (!mtd->erasesize) { | ||
779 | printk(KERN_NOTICE PREFIX "please provide block_size"); | ||
780 | return; | ||
781 | } | ||
782 | else | ||
783 | part->block_size = mtd->erasesize; | ||
784 | } | ||
785 | |||
786 | if (scan_header(part) == 0) { | ||
787 | part->mbd.size = part->sector_count; | ||
788 | part->mbd.blksize = SECTOR_SIZE; | ||
789 | part->mbd.tr = tr; | ||
790 | part->mbd.devnum = -1; | ||
791 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
792 | part->mbd.readonly = 1; | ||
793 | else if (part->errors) { | ||
794 | printk(KERN_NOTICE PREFIX "'%s': errors found, " | ||
795 | "setting read-only", mtd->name); | ||
796 | part->mbd.readonly = 1; | ||
797 | } | ||
798 | |||
799 | printk(KERN_INFO PREFIX "name: '%s' type: %d flags %x\n", | ||
800 | mtd->name, mtd->type, mtd->flags); | ||
801 | |||
802 | if (!add_mtd_blktrans_dev((void*)part)) | ||
803 | return; | ||
804 | } | ||
805 | |||
806 | kfree(part); | ||
807 | } | ||
808 | |||
809 | static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev) | ||
810 | { | ||
811 | struct partition *part = (struct partition*)dev; | ||
812 | int i; | ||
813 | |||
814 | for (i=0; i<part->total_blocks; i++) { | ||
815 | pr_debug("rfd_ftl_remove_dev:'%s': erase unit #%02d: %d erases\n", | ||
816 | part->mbd.mtd->name, i, part->blocks[i].erases); | ||
817 | } | ||
818 | |||
819 | del_mtd_blktrans_dev(dev); | ||
820 | vfree(part->sector_map); | ||
821 | kfree(part->header_cache); | ||
822 | kfree(part->blocks); | ||
823 | kfree(part); | ||
824 | } | ||
825 | |||
826 | struct mtd_blktrans_ops rfd_ftl_tr = { | ||
827 | .name = "rfd", | ||
828 | .major = RFD_FTL_MAJOR, | ||
829 | .part_bits = PART_BITS, | ||
830 | .readsect = rfd_ftl_readsect, | ||
831 | .writesect = rfd_ftl_writesect, | ||
832 | .getgeo = rfd_ftl_getgeo, | ||
833 | .add_mtd = rfd_ftl_add_mtd, | ||
834 | .remove_dev = rfd_ftl_remove_dev, | ||
835 | .owner = THIS_MODULE, | ||
836 | }; | ||
837 | |||
838 | static int __init init_rfd_ftl(void) | ||
839 | { | ||
840 | return register_mtd_blktrans(&rfd_ftl_tr); | ||
841 | } | ||
842 | |||
843 | static void __exit cleanup_rfd_ftl(void) | ||
844 | { | ||
845 | deregister_mtd_blktrans(&rfd_ftl_tr); | ||
846 | } | ||
847 | |||
848 | module_init(init_rfd_ftl); | ||
849 | module_exit(cleanup_rfd_ftl); | ||
850 | |||
851 | MODULE_LICENSE("GPL"); | ||
852 | MODULE_AUTHOR("Sean Young <sean@mess.org>"); | ||
853 | MODULE_DESCRIPTION("Support code for RFD Flash Translation Layer, " | ||
854 | "used by General Software's Embedded BIOS"); | ||
855 | |||
diff --git a/fs/Kconfig b/fs/Kconfig index 7cf36ca157ff..7d6ae369ce44 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1051,6 +1051,19 @@ config JFFS2_FS_WRITEBUFFER | |||
1051 | - NOR flash with transparent ECC | 1051 | - NOR flash with transparent ECC |
1052 | - DataFlash | 1052 | - DataFlash |
1053 | 1053 | ||
1054 | config JFFS2_SUMMARY | ||
1055 | bool "JFFS2 summary support (EXPERIMENTAL)" | ||
1056 | depends on JFFS2_FS && EXPERIMENTAL | ||
1057 | default n | ||
1058 | help | ||
1059 | This feature makes it possible to use summary information | ||
1060 | for faster filesystem mount. | ||
1061 | |||
1062 | The summary information can be inserted into a filesystem image | ||
1063 | by the utility 'sumtool'. | ||
1064 | |||
1065 | If unsure, say 'N'. | ||
1066 | |||
1054 | config JFFS2_COMPRESSION_OPTIONS | 1067 | config JFFS2_COMPRESSION_OPTIONS |
1055 | bool "Advanced compression options for JFFS2" | 1068 | bool "Advanced compression options for JFFS2" |
1056 | depends on JFFS2_FS | 1069 | depends on JFFS2_FS |
@@ -1072,10 +1085,10 @@ config JFFS2_ZLIB | |||
1072 | default y | 1085 | default y |
1073 | help | 1086 | help |
1074 | Zlib is designed to be a free, general-purpose, legally unencumbered, | 1087 | Zlib is designed to be a free, general-purpose, legally unencumbered, |
1075 | lossless data-compression library for use on virtually any computer | 1088 | lossless data-compression library for use on virtually any computer |
1076 | hardware and operating system. See <http://www.gzip.org/zlib/> for | 1089 | hardware and operating system. See <http://www.gzip.org/zlib/> for |
1077 | further information. | 1090 | further information. |
1078 | 1091 | ||
1079 | Say 'Y' if unsure. | 1092 | Say 'Y' if unsure. |
1080 | 1093 | ||
1081 | config JFFS2_RTIME | 1094 | config JFFS2_RTIME |
@@ -1097,7 +1110,7 @@ choice | |||
1097 | default JFFS2_CMODE_PRIORITY | 1110 | default JFFS2_CMODE_PRIORITY |
1098 | depends on JFFS2_FS | 1111 | depends on JFFS2_FS |
1099 | help | 1112 | help |
1100 | You can set here the default compression mode of JFFS2 from | 1113 | You can set here the default compression mode of JFFS2 from |
1101 | the available compression modes. Don't touch if unsure. | 1114 | the available compression modes. Don't touch if unsure. |
1102 | 1115 | ||
1103 | config JFFS2_CMODE_NONE | 1116 | config JFFS2_CMODE_NONE |
@@ -1108,13 +1121,13 @@ config JFFS2_CMODE_NONE | |||
1108 | config JFFS2_CMODE_PRIORITY | 1121 | config JFFS2_CMODE_PRIORITY |
1109 | bool "priority" | 1122 | bool "priority" |
1110 | help | 1123 | help |
1111 | Tries the compressors in a predefinied order and chooses the first | 1124 | Tries the compressors in a predefinied order and chooses the first |
1112 | successful one. | 1125 | successful one. |
1113 | 1126 | ||
1114 | config JFFS2_CMODE_SIZE | 1127 | config JFFS2_CMODE_SIZE |
1115 | bool "size (EXPERIMENTAL)" | 1128 | bool "size (EXPERIMENTAL)" |
1116 | help | 1129 | help |
1117 | Tries all compressors and chooses the one which has the smallest | 1130 | Tries all compressors and chooses the one which has the smallest |
1118 | result. | 1131 | result. |
1119 | 1132 | ||
1120 | endchoice | 1133 | endchoice |
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index f1afe681ecd6..77dc5561a04e 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the Linux Journalling Flash File System v2 (JFFS2) | 2 | # Makefile for the Linux Journalling Flash File System v2 (JFFS2) |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $ | 4 | # $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $ |
5 | # | 5 | # |
6 | 6 | ||
7 | obj-$(CONFIG_JFFS2_FS) += jffs2.o | 7 | obj-$(CONFIG_JFFS2_FS) += jffs2.o |
@@ -9,9 +9,10 @@ obj-$(CONFIG_JFFS2_FS) += jffs2.o | |||
9 | jffs2-y := compr.o dir.o file.o ioctl.o nodelist.o malloc.o | 9 | jffs2-y := compr.o dir.o file.o ioctl.o nodelist.o malloc.o |
10 | jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o | 10 | jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o |
11 | jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o | 11 | jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o |
12 | jffs2-y += super.o | 12 | jffs2-y += super.o debug.o |
13 | 13 | ||
14 | jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o | 14 | jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o |
15 | jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o | 15 | jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o |
16 | jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o | 16 | jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o |
17 | jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o | 17 | jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o |
18 | jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o | ||
diff --git a/fs/jffs2/TODO b/fs/jffs2/TODO index 2bff82fd221f..d0e23b26fa50 100644 --- a/fs/jffs2/TODO +++ b/fs/jffs2/TODO | |||
@@ -1,5 +1,11 @@ | |||
1 | $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $ | 1 | $Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $ |
2 | 2 | ||
3 | - support asynchronous operation -- add a per-fs 'reserved_space' count, | ||
4 | let each outstanding write reserve the _maximum_ amount of physical | ||
5 | space it could take. Let GC flush the outstanding writes because the | ||
6 | reservations will necessarily be pessimistic. With this we could even | ||
7 | do shared writable mmap, if we can have a fs hook for do_wp_page() to | ||
8 | make the reservation. | ||
3 | - disable compression in commit_write()? | 9 | - disable compression in commit_write()? |
4 | - fine-tune the allocation / GC thresholds | 10 | - fine-tune the allocation / GC thresholds |
5 | - chattr support - turning on/off and tuning compression per-inode | 11 | - chattr support - turning on/off and tuning compression per-inode |
@@ -11,26 +17,15 @@ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $ | |||
11 | - test, test, test | 17 | - test, test, test |
12 | 18 | ||
13 | - NAND flash support: | 19 | - NAND flash support: |
14 | - flush_wbuf using GC to fill it, don't just pad. | 20 | - almost done :) |
15 | - Deal with write errors. Data don't get lost - we just have to write | 21 | - use bad block check instead of the hardwired byte check |
16 | the affected node(s) out again somewhere else. | ||
17 | - make fsync flush only if actually required | ||
18 | - make sys_sync() work. | ||
19 | - reboot notifier | ||
20 | - timed flush of old wbuf | ||
21 | - fix magical second arg of jffs2_flush_wbuf(). Split into two or more functions instead. | ||
22 | |||
23 | 22 | ||
24 | - Optimisations: | 23 | - Optimisations: |
25 | - Stop GC from decompressing and immediately recompressing nodes which could | 24 | - Split writes so they go to two separate blocks rather than just c->nextblock. |
26 | just be copied intact. (We now keep track of REF_PRISTINE flag. Easy now.) | 25 | By writing _new_ nodes to one block, and garbage-collected REF_PRISTINE |
27 | - Furthermore, in the case where it could be copied intact we don't even need | 26 | nodes to a different one, we can separate clean nodes from those which |
28 | to call iget() for it -- if we use (raw_node_raw->flash_offset & 2) as a flag | 27 | are likely to become dirty, and end up with blocks which are each far |
29 | to show a node can be copied intact and it's _not_ in icache, we could just do | 28 | closer to 100% or 0% clean, hence speeding up later GC progress dramatically. |
30 | it, fix up the next_in_ino list and move on. We would need a way to find out | ||
31 | _whether_ it's in icache though -- if it's in icache we also need to do the | ||
32 | fragment lists, etc. P'raps a flag or pointer in the jffs2_inode_cache could | ||
33 | help. (We have half of this now.) | ||
34 | - Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in | 29 | - Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in |
35 | the full dirent, we only need to go to the flash in lookup() when we think we've | 30 | the full dirent, we only need to go to the flash in lookup() when we think we've |
36 | got a match, and in readdir(). | 31 | got a match, and in readdir(). |
@@ -38,3 +33,8 @@ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $ | |||
38 | - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into | 33 | - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into |
39 | jffs2_mark_node_obsolete(). Can all callers work it out? | 34 | jffs2_mark_node_obsolete(). Can all callers work it out? |
40 | - Remove size from jffs2_raw_node_frag. | 35 | - Remove size from jffs2_raw_node_frag. |
36 | |||
37 | dedekind: | ||
38 | 1. __jffs2_flush_wbuf() has a strange 'pad' parameter. Eliminate. | ||
39 | 2. get_sb()->build_fs()->scan() path... Why get_sb() removes scan()'s crap in | ||
40 | case of failure? scan() does not clean everything. Fix. | ||
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 8210ac16a368..7b77a9541125 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
@@ -51,7 +51,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) | |||
51 | D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); | 51 | D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); |
52 | wait_for_completion(&c->gc_thread_start); | 52 | wait_for_completion(&c->gc_thread_start); |
53 | } | 53 | } |
54 | 54 | ||
55 | return ret; | 55 | return ret; |
56 | } | 56 | } |
57 | 57 | ||
@@ -101,7 +101,7 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
101 | 101 | ||
102 | cond_resched(); | 102 | cond_resched(); |
103 | 103 | ||
104 | /* Put_super will send a SIGKILL and then wait on the sem. | 104 | /* Put_super will send a SIGKILL and then wait on the sem. |
105 | */ | 105 | */ |
106 | while (signal_pending(current)) { | 106 | while (signal_pending(current)) { |
107 | siginfo_t info; | 107 | siginfo_t info; |
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 97dc39796e2c..fff108bb118b 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: build.c,v 1.71 2005/07/12 16:37:08 dedekind Exp $ | 10 | * $Id: build.c,v 1.85 2005/11/07 11:14:38 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -18,7 +18,8 @@ | |||
18 | #include <linux/mtd/mtd.h> | 18 | #include <linux/mtd/mtd.h> |
19 | #include "nodelist.h" | 19 | #include "nodelist.h" |
20 | 20 | ||
21 | static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **); | 21 | static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, |
22 | struct jffs2_inode_cache *, struct jffs2_full_dirent **); | ||
22 | 23 | ||
23 | static inline struct jffs2_inode_cache * | 24 | static inline struct jffs2_inode_cache * |
24 | first_inode_chain(int *i, struct jffs2_sb_info *c) | 25 | first_inode_chain(int *i, struct jffs2_sb_info *c) |
@@ -46,11 +47,12 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) | |||
46 | ic = next_inode(&i, ic, (c))) | 47 | ic = next_inode(&i, ic, (c))) |
47 | 48 | ||
48 | 49 | ||
49 | static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) | 50 | static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, |
51 | struct jffs2_inode_cache *ic) | ||
50 | { | 52 | { |
51 | struct jffs2_full_dirent *fd; | 53 | struct jffs2_full_dirent *fd; |
52 | 54 | ||
53 | D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino)); | 55 | dbg_fsbuild("building directory inode #%u\n", ic->ino); |
54 | 56 | ||
55 | /* For each child, increase nlink */ | 57 | /* For each child, increase nlink */ |
56 | for(fd = ic->scan_dents; fd; fd = fd->next) { | 58 | for(fd = ic->scan_dents; fd; fd = fd->next) { |
@@ -58,26 +60,23 @@ static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2 | |||
58 | if (!fd->ino) | 60 | if (!fd->ino) |
59 | continue; | 61 | continue; |
60 | 62 | ||
61 | /* XXX: Can get high latency here with huge directories */ | 63 | /* we can get high latency here with huge directories */ |
62 | 64 | ||
63 | child_ic = jffs2_get_ino_cache(c, fd->ino); | 65 | child_ic = jffs2_get_ino_cache(c, fd->ino); |
64 | if (!child_ic) { | 66 | if (!child_ic) { |
65 | printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", | 67 | dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", |
66 | fd->name, fd->ino, ic->ino); | 68 | fd->name, fd->ino, ic->ino); |
67 | jffs2_mark_node_obsolete(c, fd->raw); | 69 | jffs2_mark_node_obsolete(c, fd->raw); |
68 | continue; | 70 | continue; |
69 | } | 71 | } |
70 | 72 | ||
71 | if (child_ic->nlink++ && fd->type == DT_DIR) { | 73 | if (child_ic->nlink++ && fd->type == DT_DIR) { |
72 | printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino); | 74 | JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", |
73 | if (fd->ino == 1 && ic->ino == 1) { | 75 | fd->name, fd->ino, ic->ino); |
74 | printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n"); | 76 | /* TODO: What do we do about it? */ |
75 | printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n"); | ||
76 | } | ||
77 | /* What do we do about it? */ | ||
78 | } | 77 | } |
79 | D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino)); | 78 | dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); |
80 | /* Can't free them. We might need them in pass 2 */ | 79 | /* Can't free scan_dents so far. We might need them in pass 2 */ |
81 | } | 80 | } |
82 | } | 81 | } |
83 | 82 | ||
@@ -94,6 +93,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
94 | struct jffs2_full_dirent *fd; | 93 | struct jffs2_full_dirent *fd; |
95 | struct jffs2_full_dirent *dead_fds = NULL; | 94 | struct jffs2_full_dirent *dead_fds = NULL; |
96 | 95 | ||
96 | dbg_fsbuild("build FS data structures\n"); | ||
97 | |||
97 | /* First, scan the medium and build all the inode caches with | 98 | /* First, scan the medium and build all the inode caches with |
98 | lists of physical nodes */ | 99 | lists of physical nodes */ |
99 | 100 | ||
@@ -103,60 +104,54 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
103 | if (ret) | 104 | if (ret) |
104 | goto exit; | 105 | goto exit; |
105 | 106 | ||
106 | D1(printk(KERN_DEBUG "Scanned flash completely\n")); | 107 | dbg_fsbuild("scanned flash completely\n"); |
107 | D2(jffs2_dump_block_lists(c)); | 108 | jffs2_dbg_dump_block_lists_nolock(c); |
108 | 109 | ||
110 | dbg_fsbuild("pass 1 starting\n"); | ||
109 | c->flags |= JFFS2_SB_FLAG_BUILDING; | 111 | c->flags |= JFFS2_SB_FLAG_BUILDING; |
110 | /* Now scan the directory tree, increasing nlink according to every dirent found. */ | 112 | /* Now scan the directory tree, increasing nlink according to every dirent found. */ |
111 | for_each_inode(i, c, ic) { | 113 | for_each_inode(i, c, ic) { |
112 | D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); | ||
113 | |||
114 | D1(BUG_ON(ic->ino > c->highest_ino)); | ||
115 | |||
116 | if (ic->scan_dents) { | 114 | if (ic->scan_dents) { |
117 | jffs2_build_inode_pass1(c, ic); | 115 | jffs2_build_inode_pass1(c, ic); |
118 | cond_resched(); | 116 | cond_resched(); |
119 | } | 117 | } |
120 | } | 118 | } |
121 | 119 | ||
122 | D1(printk(KERN_DEBUG "Pass 1 complete\n")); | 120 | dbg_fsbuild("pass 1 complete\n"); |
123 | 121 | ||
124 | /* Next, scan for inodes with nlink == 0 and remove them. If | 122 | /* Next, scan for inodes with nlink == 0 and remove them. If |
125 | they were directories, then decrement the nlink of their | 123 | they were directories, then decrement the nlink of their |
126 | children too, and repeat the scan. As that's going to be | 124 | children too, and repeat the scan. As that's going to be |
127 | a fairly uncommon occurrence, it's not so evil to do it this | 125 | a fairly uncommon occurrence, it's not so evil to do it this |
128 | way. Recursion bad. */ | 126 | way. Recursion bad. */ |
129 | D1(printk(KERN_DEBUG "Pass 2 starting\n")); | 127 | dbg_fsbuild("pass 2 starting\n"); |
130 | 128 | ||
131 | for_each_inode(i, c, ic) { | 129 | for_each_inode(i, c, ic) { |
132 | D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes)); | ||
133 | if (ic->nlink) | 130 | if (ic->nlink) |
134 | continue; | 131 | continue; |
135 | 132 | ||
136 | jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); | 133 | jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); |
137 | cond_resched(); | 134 | cond_resched(); |
138 | } | 135 | } |
139 | 136 | ||
140 | D1(printk(KERN_DEBUG "Pass 2a starting\n")); | 137 | dbg_fsbuild("pass 2a starting\n"); |
141 | 138 | ||
142 | while (dead_fds) { | 139 | while (dead_fds) { |
143 | fd = dead_fds; | 140 | fd = dead_fds; |
144 | dead_fds = fd->next; | 141 | dead_fds = fd->next; |
145 | 142 | ||
146 | ic = jffs2_get_ino_cache(c, fd->ino); | 143 | ic = jffs2_get_ino_cache(c, fd->ino); |
147 | D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic)); | ||
148 | 144 | ||
149 | if (ic) | 145 | if (ic) |
150 | jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); | 146 | jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); |
151 | jffs2_free_full_dirent(fd); | 147 | jffs2_free_full_dirent(fd); |
152 | } | 148 | } |
153 | 149 | ||
154 | D1(printk(KERN_DEBUG "Pass 2 complete\n")); | 150 | dbg_fsbuild("pass 2a complete\n"); |
155 | 151 | dbg_fsbuild("freeing temporary data structures\n"); | |
152 | |||
156 | /* Finally, we can scan again and free the dirent structs */ | 153 | /* Finally, we can scan again and free the dirent structs */ |
157 | for_each_inode(i, c, ic) { | 154 | for_each_inode(i, c, ic) { |
158 | D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes)); | ||
159 | |||
160 | while(ic->scan_dents) { | 155 | while(ic->scan_dents) { |
161 | fd = ic->scan_dents; | 156 | fd = ic->scan_dents; |
162 | ic->scan_dents = fd->next; | 157 | ic->scan_dents = fd->next; |
@@ -166,9 +161,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
166 | cond_resched(); | 161 | cond_resched(); |
167 | } | 162 | } |
168 | c->flags &= ~JFFS2_SB_FLAG_BUILDING; | 163 | c->flags &= ~JFFS2_SB_FLAG_BUILDING; |
169 | 164 | ||
170 | D1(printk(KERN_DEBUG "Pass 3 complete\n")); | 165 | dbg_fsbuild("FS build complete\n"); |
171 | D2(jffs2_dump_block_lists(c)); | ||
172 | 166 | ||
173 | /* Rotate the lists by some number to ensure wear levelling */ | 167 | /* Rotate the lists by some number to ensure wear levelling */ |
174 | jffs2_rotate_lists(c); | 168 | jffs2_rotate_lists(c); |
@@ -189,24 +183,26 @@ exit: | |||
189 | return ret; | 183 | return ret; |
190 | } | 184 | } |
191 | 185 | ||
192 | static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds) | 186 | static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, |
187 | struct jffs2_inode_cache *ic, | ||
188 | struct jffs2_full_dirent **dead_fds) | ||
193 | { | 189 | { |
194 | struct jffs2_raw_node_ref *raw; | 190 | struct jffs2_raw_node_ref *raw; |
195 | struct jffs2_full_dirent *fd; | 191 | struct jffs2_full_dirent *fd; |
196 | 192 | ||
197 | D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino)); | 193 | dbg_fsbuild("removing ino #%u with nlink == zero.\n", ic->ino); |
198 | 194 | ||
199 | raw = ic->nodes; | 195 | raw = ic->nodes; |
200 | while (raw != (void *)ic) { | 196 | while (raw != (void *)ic) { |
201 | struct jffs2_raw_node_ref *next = raw->next_in_ino; | 197 | struct jffs2_raw_node_ref *next = raw->next_in_ino; |
202 | D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw))); | 198 | dbg_fsbuild("obsoleting node at 0x%08x\n", ref_offset(raw)); |
203 | jffs2_mark_node_obsolete(c, raw); | 199 | jffs2_mark_node_obsolete(c, raw); |
204 | raw = next; | 200 | raw = next; |
205 | } | 201 | } |
206 | 202 | ||
207 | if (ic->scan_dents) { | 203 | if (ic->scan_dents) { |
208 | int whinged = 0; | 204 | int whinged = 0; |
209 | D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino)); | 205 | dbg_fsbuild("inode #%u was a directory which may have children...\n", ic->ino); |
210 | 206 | ||
211 | while(ic->scan_dents) { | 207 | while(ic->scan_dents) { |
212 | struct jffs2_inode_cache *child_ic; | 208 | struct jffs2_inode_cache *child_ic; |
@@ -216,45 +212,43 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jf | |||
216 | 212 | ||
217 | if (!fd->ino) { | 213 | if (!fd->ino) { |
218 | /* It's a deletion dirent. Ignore it */ | 214 | /* It's a deletion dirent. Ignore it */ |
219 | D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name)); | 215 | dbg_fsbuild("child \"%s\" is a deletion dirent, skipping...\n", fd->name); |
220 | jffs2_free_full_dirent(fd); | 216 | jffs2_free_full_dirent(fd); |
221 | continue; | 217 | continue; |
222 | } | 218 | } |
223 | if (!whinged) { | 219 | if (!whinged) |
224 | whinged = 1; | 220 | whinged = 1; |
225 | printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino); | ||
226 | } | ||
227 | 221 | ||
228 | D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n", | 222 | dbg_fsbuild("removing child \"%s\", ino #%u\n", fd->name, fd->ino); |
229 | fd->name, fd->ino)); | 223 | |
230 | |||
231 | child_ic = jffs2_get_ino_cache(c, fd->ino); | 224 | child_ic = jffs2_get_ino_cache(c, fd->ino); |
232 | if (!child_ic) { | 225 | if (!child_ic) { |
233 | printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino); | 226 | dbg_fsbuild("cannot remove child \"%s\", ino #%u, because it doesn't exist\n", |
227 | fd->name, fd->ino); | ||
234 | jffs2_free_full_dirent(fd); | 228 | jffs2_free_full_dirent(fd); |
235 | continue; | 229 | continue; |
236 | } | 230 | } |
237 | 231 | ||
238 | /* Reduce nlink of the child. If it's now zero, stick it on the | 232 | /* Reduce nlink of the child. If it's now zero, stick it on the |
239 | dead_fds list to be cleaned up later. Else just free the fd */ | 233 | dead_fds list to be cleaned up later. Else just free the fd */ |
240 | 234 | ||
241 | child_ic->nlink--; | 235 | child_ic->nlink--; |
242 | 236 | ||
243 | if (!child_ic->nlink) { | 237 | if (!child_ic->nlink) { |
244 | D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n", | 238 | dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n", |
245 | fd->ino, fd->name)); | 239 | fd->ino, fd->name); |
246 | fd->next = *dead_fds; | 240 | fd->next = *dead_fds; |
247 | *dead_fds = fd; | 241 | *dead_fds = fd; |
248 | } else { | 242 | } else { |
249 | D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", | 243 | dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", |
250 | fd->ino, fd->name, child_ic->nlink)); | 244 | fd->ino, fd->name, child_ic->nlink); |
251 | jffs2_free_full_dirent(fd); | 245 | jffs2_free_full_dirent(fd); |
252 | } | 246 | } |
253 | } | 247 | } |
254 | } | 248 | } |
255 | 249 | ||
256 | /* | 250 | /* |
257 | We don't delete the inocache from the hash list and free it yet. | 251 | We don't delete the inocache from the hash list and free it yet. |
258 | The erase code will do that, when all the nodes are completely gone. | 252 | The erase code will do that, when all the nodes are completely gone. |
259 | */ | 253 | */ |
260 | } | 254 | } |
@@ -268,7 +262,7 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) | |||
268 | because there's not enough free space... */ | 262 | because there's not enough free space... */ |
269 | c->resv_blocks_deletion = 2; | 263 | c->resv_blocks_deletion = 2; |
270 | 264 | ||
271 | /* Be conservative about how much space we need before we allow writes. | 265 | /* Be conservative about how much space we need before we allow writes. |
272 | On top of that which is required for deletia, require an extra 2% | 266 | On top of that which is required for deletia, require an extra 2% |
273 | of the medium to be available, for overhead caused by nodes being | 267 | of the medium to be available, for overhead caused by nodes being |
274 | split across blocks, etc. */ | 268 | split across blocks, etc. */ |
@@ -283,7 +277,7 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) | |||
283 | 277 | ||
284 | c->resv_blocks_gctrigger = c->resv_blocks_write + 1; | 278 | c->resv_blocks_gctrigger = c->resv_blocks_write + 1; |
285 | 279 | ||
286 | /* When do we allow garbage collection to merge nodes to make | 280 | /* When do we allow garbage collection to merge nodes to make |
287 | long-term progress at the expense of short-term space exhaustion? */ | 281 | long-term progress at the expense of short-term space exhaustion? */ |
288 | c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1; | 282 | c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1; |
289 | 283 | ||
@@ -295,45 +289,45 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) | |||
295 | trying to GC to make more space. It'll be a fruitless task */ | 289 | trying to GC to make more space. It'll be a fruitless task */ |
296 | c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); | 290 | c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); |
297 | 291 | ||
298 | D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n", | 292 | dbg_fsbuild("JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n", |
299 | c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks)); | 293 | c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks); |
300 | D1(printk(KERN_DEBUG "Blocks required to allow deletion: %d (%d KiB)\n", | 294 | dbg_fsbuild("Blocks required to allow deletion: %d (%d KiB)\n", |
301 | c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024)); | 295 | c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024); |
302 | D1(printk(KERN_DEBUG "Blocks required to allow writes: %d (%d KiB)\n", | 296 | dbg_fsbuild("Blocks required to allow writes: %d (%d KiB)\n", |
303 | c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024)); | 297 | c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024); |
304 | D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n", | 298 | dbg_fsbuild("Blocks required to quiesce GC thread: %d (%d KiB)\n", |
305 | c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024)); | 299 | c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024); |
306 | D1(printk(KERN_DEBUG "Blocks required to allow GC merges: %d (%d KiB)\n", | 300 | dbg_fsbuild("Blocks required to allow GC merges: %d (%d KiB)\n", |
307 | c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024)); | 301 | c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024); |
308 | D1(printk(KERN_DEBUG "Blocks required to GC bad blocks: %d (%d KiB)\n", | 302 | dbg_fsbuild("Blocks required to GC bad blocks: %d (%d KiB)\n", |
309 | c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024)); | 303 | c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024); |
310 | D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n", | 304 | dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n", |
311 | c->nospc_dirty_size)); | 305 | c->nospc_dirty_size); |
312 | } | 306 | } |
313 | 307 | ||
314 | int jffs2_do_mount_fs(struct jffs2_sb_info *c) | 308 | int jffs2_do_mount_fs(struct jffs2_sb_info *c) |
315 | { | 309 | { |
310 | int ret; | ||
316 | int i; | 311 | int i; |
312 | int size; | ||
317 | 313 | ||
318 | c->free_size = c->flash_size; | 314 | c->free_size = c->flash_size; |
319 | c->nr_blocks = c->flash_size / c->sector_size; | 315 | c->nr_blocks = c->flash_size / c->sector_size; |
320 | if (c->mtd->flags & MTD_NO_VIRTBLOCKS) | 316 | size = sizeof(struct jffs2_eraseblock) * c->nr_blocks; |
321 | c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks); | 317 | #ifndef __ECOS |
318 | if (jffs2_blocks_use_vmalloc(c)) | ||
319 | c->blocks = vmalloc(size); | ||
322 | else | 320 | else |
323 | c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL); | 321 | #endif |
322 | c->blocks = kmalloc(size, GFP_KERNEL); | ||
324 | if (!c->blocks) | 323 | if (!c->blocks) |
325 | return -ENOMEM; | 324 | return -ENOMEM; |
325 | |||
326 | memset(c->blocks, 0, size); | ||
326 | for (i=0; i<c->nr_blocks; i++) { | 327 | for (i=0; i<c->nr_blocks; i++) { |
327 | INIT_LIST_HEAD(&c->blocks[i].list); | 328 | INIT_LIST_HEAD(&c->blocks[i].list); |
328 | c->blocks[i].offset = i * c->sector_size; | 329 | c->blocks[i].offset = i * c->sector_size; |
329 | c->blocks[i].free_size = c->sector_size; | 330 | c->blocks[i].free_size = c->sector_size; |
330 | c->blocks[i].dirty_size = 0; | ||
331 | c->blocks[i].wasted_size = 0; | ||
332 | c->blocks[i].unchecked_size = 0; | ||
333 | c->blocks[i].used_size = 0; | ||
334 | c->blocks[i].first_node = NULL; | ||
335 | c->blocks[i].last_node = NULL; | ||
336 | c->blocks[i].bad_count = 0; | ||
337 | } | 331 | } |
338 | 332 | ||
339 | INIT_LIST_HEAD(&c->clean_list); | 333 | INIT_LIST_HEAD(&c->clean_list); |
@@ -348,16 +342,23 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) | |||
348 | INIT_LIST_HEAD(&c->bad_list); | 342 | INIT_LIST_HEAD(&c->bad_list); |
349 | INIT_LIST_HEAD(&c->bad_used_list); | 343 | INIT_LIST_HEAD(&c->bad_used_list); |
350 | c->highest_ino = 1; | 344 | c->highest_ino = 1; |
345 | c->summary = NULL; | ||
346 | |||
347 | ret = jffs2_sum_init(c); | ||
348 | if (ret) | ||
349 | return ret; | ||
351 | 350 | ||
352 | if (jffs2_build_filesystem(c)) { | 351 | if (jffs2_build_filesystem(c)) { |
353 | D1(printk(KERN_DEBUG "build_fs failed\n")); | 352 | dbg_fsbuild("build_fs failed\n"); |
354 | jffs2_free_ino_caches(c); | 353 | jffs2_free_ino_caches(c); |
355 | jffs2_free_raw_node_refs(c); | 354 | jffs2_free_raw_node_refs(c); |
356 | if (c->mtd->flags & MTD_NO_VIRTBLOCKS) { | 355 | #ifndef __ECOS |
356 | if (jffs2_blocks_use_vmalloc(c)) | ||
357 | vfree(c->blocks); | 357 | vfree(c->blocks); |
358 | } else { | 358 | else |
359 | #endif | ||
359 | kfree(c->blocks); | 360 | kfree(c->blocks); |
360 | } | 361 | |
361 | return -EIO; | 362 | return -EIO; |
362 | } | 363 | } |
363 | 364 | ||
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index af922a9618ac..e7944e665b9f 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * | 9 | * |
10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
11 | * | 11 | * |
12 | * $Id: compr.c,v 1.42 2004/08/07 21:56:08 dwmw2 Exp $ | 12 | * $Id: compr.c,v 1.46 2005/11/07 11:14:38 gleixner Exp $ |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
@@ -36,16 +36,16 @@ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_co | |||
36 | * data. | 36 | * data. |
37 | * | 37 | * |
38 | * Returns: Lower byte to be stored with data indicating compression type used. | 38 | * Returns: Lower byte to be stored with data indicating compression type used. |
39 | * Zero is used to show that the data could not be compressed - the | 39 | * Zero is used to show that the data could not be compressed - the |
40 | * compressed version was actually larger than the original. | 40 | * compressed version was actually larger than the original. |
41 | * Upper byte will be used later. (soon) | 41 | * Upper byte will be used later. (soon) |
42 | * | 42 | * |
43 | * If the cdata buffer isn't large enough to hold all the uncompressed data, | 43 | * If the cdata buffer isn't large enough to hold all the uncompressed data, |
44 | * jffs2_compress should compress as much as will fit, and should set | 44 | * jffs2_compress should compress as much as will fit, and should set |
45 | * *datalen accordingly to show the amount of data which were compressed. | 45 | * *datalen accordingly to show the amount of data which were compressed. |
46 | */ | 46 | */ |
47 | uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 47 | uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
48 | unsigned char *data_in, unsigned char **cpage_out, | 48 | unsigned char *data_in, unsigned char **cpage_out, |
49 | uint32_t *datalen, uint32_t *cdatalen) | 49 | uint32_t *datalen, uint32_t *cdatalen) |
50 | { | 50 | { |
51 | int ret = JFFS2_COMPR_NONE; | 51 | int ret = JFFS2_COMPR_NONE; |
@@ -164,7 +164,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
164 | } | 164 | } |
165 | 165 | ||
166 | int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 166 | int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
167 | uint16_t comprtype, unsigned char *cdata_in, | 167 | uint16_t comprtype, unsigned char *cdata_in, |
168 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) | 168 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) |
169 | { | 169 | { |
170 | struct jffs2_compressor *this; | 170 | struct jffs2_compressor *this; |
@@ -298,7 +298,7 @@ char *jffs2_stats(void) | |||
298 | 298 | ||
299 | act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n"); | 299 | act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n"); |
300 | act_buf += sprintf(act_buf,"%10s ","none"); | 300 | act_buf += sprintf(act_buf,"%10s ","none"); |
301 | act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, | 301 | act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, |
302 | none_stat_compr_size, none_stat_decompr_blocks); | 302 | none_stat_compr_size, none_stat_decompr_blocks); |
303 | spin_lock(&jffs2_compressor_list_lock); | 303 | spin_lock(&jffs2_compressor_list_lock); |
304 | list_for_each_entry(this, &jffs2_compressor_list, list) { | 304 | list_for_each_entry(this, &jffs2_compressor_list, list) { |
@@ -307,8 +307,8 @@ char *jffs2_stats(void) | |||
307 | act_buf += sprintf(act_buf,"- "); | 307 | act_buf += sprintf(act_buf,"- "); |
308 | else | 308 | else |
309 | act_buf += sprintf(act_buf,"+ "); | 309 | act_buf += sprintf(act_buf,"+ "); |
310 | act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks, | 310 | act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks, |
311 | this->stat_compr_new_size, this->stat_compr_orig_size, | 311 | this->stat_compr_new_size, this->stat_compr_orig_size, |
312 | this->stat_decompr_blocks); | 312 | this->stat_decompr_blocks); |
313 | act_buf += sprintf(act_buf,"\n"); | 313 | act_buf += sprintf(act_buf,"\n"); |
314 | } | 314 | } |
@@ -317,7 +317,7 @@ char *jffs2_stats(void) | |||
317 | return buf; | 317 | return buf; |
318 | } | 318 | } |
319 | 319 | ||
320 | char *jffs2_get_compression_mode_name(void) | 320 | char *jffs2_get_compression_mode_name(void) |
321 | { | 321 | { |
322 | switch (jffs2_compression_mode) { | 322 | switch (jffs2_compression_mode) { |
323 | case JFFS2_COMPR_MODE_NONE: | 323 | case JFFS2_COMPR_MODE_NONE: |
@@ -330,7 +330,7 @@ char *jffs2_get_compression_mode_name(void) | |||
330 | return "unkown"; | 330 | return "unkown"; |
331 | } | 331 | } |
332 | 332 | ||
333 | int jffs2_set_compression_mode_name(const char *name) | 333 | int jffs2_set_compression_mode_name(const char *name) |
334 | { | 334 | { |
335 | if (!strcmp("none",name)) { | 335 | if (!strcmp("none",name)) { |
336 | jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; | 336 | jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; |
@@ -355,7 +355,7 @@ static int jffs2_compressor_Xable(const char *name, int disabled) | |||
355 | if (!strcmp(this->name, name)) { | 355 | if (!strcmp(this->name, name)) { |
356 | this->disabled = disabled; | 356 | this->disabled = disabled; |
357 | spin_unlock(&jffs2_compressor_list_lock); | 357 | spin_unlock(&jffs2_compressor_list_lock); |
358 | return 0; | 358 | return 0; |
359 | } | 359 | } |
360 | } | 360 | } |
361 | spin_unlock(&jffs2_compressor_list_lock); | 361 | spin_unlock(&jffs2_compressor_list_lock); |
@@ -385,7 +385,7 @@ int jffs2_set_compressor_priority(const char *name, int priority) | |||
385 | } | 385 | } |
386 | } | 386 | } |
387 | spin_unlock(&jffs2_compressor_list_lock); | 387 | spin_unlock(&jffs2_compressor_list_lock); |
388 | printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name); | 388 | printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name); |
389 | return 1; | 389 | return 1; |
390 | reinsert: | 390 | reinsert: |
391 | /* list is sorted in the order of priority, so if | 391 | /* list is sorted in the order of priority, so if |
@@ -412,7 +412,7 @@ void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) | |||
412 | kfree(comprbuf); | 412 | kfree(comprbuf); |
413 | } | 413 | } |
414 | 414 | ||
415 | int jffs2_compressors_init(void) | 415 | int jffs2_compressors_init(void) |
416 | { | 416 | { |
417 | /* Registering compressors */ | 417 | /* Registering compressors */ |
418 | #ifdef CONFIG_JFFS2_ZLIB | 418 | #ifdef CONFIG_JFFS2_ZLIB |
@@ -425,12 +425,6 @@ int jffs2_compressors_init(void) | |||
425 | jffs2_rubinmips_init(); | 425 | jffs2_rubinmips_init(); |
426 | jffs2_dynrubin_init(); | 426 | jffs2_dynrubin_init(); |
427 | #endif | 427 | #endif |
428 | #ifdef CONFIG_JFFS2_LZARI | ||
429 | jffs2_lzari_init(); | ||
430 | #endif | ||
431 | #ifdef CONFIG_JFFS2_LZO | ||
432 | jffs2_lzo_init(); | ||
433 | #endif | ||
434 | /* Setting default compression mode */ | 428 | /* Setting default compression mode */ |
435 | #ifdef CONFIG_JFFS2_CMODE_NONE | 429 | #ifdef CONFIG_JFFS2_CMODE_NONE |
436 | jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; | 430 | jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; |
@@ -446,15 +440,9 @@ int jffs2_compressors_init(void) | |||
446 | return 0; | 440 | return 0; |
447 | } | 441 | } |
448 | 442 | ||
449 | int jffs2_compressors_exit(void) | 443 | int jffs2_compressors_exit(void) |
450 | { | 444 | { |
451 | /* Unregistering compressors */ | 445 | /* Unregistering compressors */ |
452 | #ifdef CONFIG_JFFS2_LZO | ||
453 | jffs2_lzo_exit(); | ||
454 | #endif | ||
455 | #ifdef CONFIG_JFFS2_LZARI | ||
456 | jffs2_lzari_exit(); | ||
457 | #endif | ||
458 | #ifdef CONFIG_JFFS2_RUBIN | 446 | #ifdef CONFIG_JFFS2_RUBIN |
459 | jffs2_dynrubin_exit(); | 447 | jffs2_dynrubin_exit(); |
460 | jffs2_rubinmips_exit(); | 448 | jffs2_rubinmips_exit(); |
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 89ceeed201eb..a77e830d85c5 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h | |||
@@ -4,10 +4,10 @@ | |||
4 | * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 4 | * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
5 | * University of Szeged, Hungary | 5 | * University of Szeged, Hungary |
6 | * | 6 | * |
7 | * For licensing information, see the file 'LICENCE' in the | 7 | * For licensing information, see the file 'LICENCE' in the |
8 | * jffs2 directory. | 8 | * jffs2 directory. |
9 | * | 9 | * |
10 | * $Id: compr.h,v 1.6 2004/07/16 15:17:57 dwmw2 Exp $ | 10 | * $Id: compr.h,v 1.9 2005/11/07 11:14:38 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -103,13 +103,5 @@ void jffs2_rtime_exit(void); | |||
103 | int jffs2_zlib_init(void); | 103 | int jffs2_zlib_init(void); |
104 | void jffs2_zlib_exit(void); | 104 | void jffs2_zlib_exit(void); |
105 | #endif | 105 | #endif |
106 | #ifdef CONFIG_JFFS2_LZARI | ||
107 | int jffs2_lzari_init(void); | ||
108 | void jffs2_lzari_exit(void); | ||
109 | #endif | ||
110 | #ifdef CONFIG_JFFS2_LZO | ||
111 | int jffs2_lzo_init(void); | ||
112 | void jffs2_lzo_exit(void); | ||
113 | #endif | ||
114 | 106 | ||
115 | #endif /* __JFFS2_COMPR_H__ */ | 107 | #endif /* __JFFS2_COMPR_H__ */ |
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 393129418666..2eb1b7428d16 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c | |||
@@ -24,8 +24,8 @@ | |||
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
27 | #include <linux/string.h> | 27 | #include <linux/string.h> |
28 | #include <linux/jffs2.h> | 28 | #include <linux/jffs2.h> |
29 | #include "compr.h" | 29 | #include "compr.h" |
30 | 30 | ||
31 | /* _compress returns the compressed size, -1 if bigger */ | 31 | /* _compress returns the compressed size, -1 if bigger */ |
@@ -38,19 +38,19 @@ static int jffs2_rtime_compress(unsigned char *data_in, | |||
38 | int outpos = 0; | 38 | int outpos = 0; |
39 | int pos=0; | 39 | int pos=0; |
40 | 40 | ||
41 | memset(positions,0,sizeof(positions)); | 41 | memset(positions,0,sizeof(positions)); |
42 | 42 | ||
43 | while (pos < (*sourcelen) && outpos <= (*dstlen)-2) { | 43 | while (pos < (*sourcelen) && outpos <= (*dstlen)-2) { |
44 | int backpos, runlen=0; | 44 | int backpos, runlen=0; |
45 | unsigned char value; | 45 | unsigned char value; |
46 | 46 | ||
47 | value = data_in[pos]; | 47 | value = data_in[pos]; |
48 | 48 | ||
49 | cpage_out[outpos++] = data_in[pos++]; | 49 | cpage_out[outpos++] = data_in[pos++]; |
50 | 50 | ||
51 | backpos = positions[value]; | 51 | backpos = positions[value]; |
52 | positions[value]=pos; | 52 | positions[value]=pos; |
53 | 53 | ||
54 | while ((backpos < pos) && (pos < (*sourcelen)) && | 54 | while ((backpos < pos) && (pos < (*sourcelen)) && |
55 | (data_in[pos]==data_in[backpos++]) && (runlen<255)) { | 55 | (data_in[pos]==data_in[backpos++]) && (runlen<255)) { |
56 | pos++; | 56 | pos++; |
@@ -63,12 +63,12 @@ static int jffs2_rtime_compress(unsigned char *data_in, | |||
63 | /* We failed */ | 63 | /* We failed */ |
64 | return -1; | 64 | return -1; |
65 | } | 65 | } |
66 | 66 | ||
67 | /* Tell the caller how much we managed to compress, and how much space it took */ | 67 | /* Tell the caller how much we managed to compress, and how much space it took */ |
68 | *sourcelen = pos; | 68 | *sourcelen = pos; |
69 | *dstlen = outpos; | 69 | *dstlen = outpos; |
70 | return 0; | 70 | return 0; |
71 | } | 71 | } |
72 | 72 | ||
73 | 73 | ||
74 | static int jffs2_rtime_decompress(unsigned char *data_in, | 74 | static int jffs2_rtime_decompress(unsigned char *data_in, |
@@ -79,19 +79,19 @@ static int jffs2_rtime_decompress(unsigned char *data_in, | |||
79 | short positions[256]; | 79 | short positions[256]; |
80 | int outpos = 0; | 80 | int outpos = 0; |
81 | int pos=0; | 81 | int pos=0; |
82 | 82 | ||
83 | memset(positions,0,sizeof(positions)); | 83 | memset(positions,0,sizeof(positions)); |
84 | 84 | ||
85 | while (outpos<destlen) { | 85 | while (outpos<destlen) { |
86 | unsigned char value; | 86 | unsigned char value; |
87 | int backoffs; | 87 | int backoffs; |
88 | int repeat; | 88 | int repeat; |
89 | 89 | ||
90 | value = data_in[pos++]; | 90 | value = data_in[pos++]; |
91 | cpage_out[outpos++] = value; /* first the verbatim copied byte */ | 91 | cpage_out[outpos++] = value; /* first the verbatim copied byte */ |
92 | repeat = data_in[pos++]; | 92 | repeat = data_in[pos++]; |
93 | backoffs = positions[value]; | 93 | backoffs = positions[value]; |
94 | 94 | ||
95 | positions[value]=outpos; | 95 | positions[value]=outpos; |
96 | if (repeat) { | 96 | if (repeat) { |
97 | if (backoffs + repeat >= outpos) { | 97 | if (backoffs + repeat >= outpos) { |
@@ -101,12 +101,12 @@ static int jffs2_rtime_decompress(unsigned char *data_in, | |||
101 | } | 101 | } |
102 | } else { | 102 | } else { |
103 | memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat); | 103 | memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat); |
104 | outpos+=repeat; | 104 | outpos+=repeat; |
105 | } | 105 | } |
106 | } | 106 | } |
107 | } | 107 | } |
108 | return 0; | 108 | return 0; |
109 | } | 109 | } |
110 | 110 | ||
111 | static struct jffs2_compressor jffs2_rtime_comp = { | 111 | static struct jffs2_compressor jffs2_rtime_comp = { |
112 | .priority = JFFS2_RTIME_PRIORITY, | 112 | .priority = JFFS2_RTIME_PRIORITY, |
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index 09422388fb96..e792e675d624 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c | |||
@@ -11,7 +11,6 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | |||
15 | #include <linux/string.h> | 14 | #include <linux/string.h> |
16 | #include <linux/types.h> | 15 | #include <linux/types.h> |
17 | #include <linux/jffs2.h> | 16 | #include <linux/jffs2.h> |
@@ -20,7 +19,7 @@ | |||
20 | #include "compr.h" | 19 | #include "compr.h" |
21 | 20 | ||
22 | static void init_rubin(struct rubin_state *rs, int div, int *bits) | 21 | static void init_rubin(struct rubin_state *rs, int div, int *bits) |
23 | { | 22 | { |
24 | int c; | 23 | int c; |
25 | 24 | ||
26 | rs->q = 0; | 25 | rs->q = 0; |
@@ -40,7 +39,7 @@ static int encode(struct rubin_state *rs, long A, long B, int symbol) | |||
40 | 39 | ||
41 | while ((rs->q >= UPPER_BIT_RUBIN) || ((rs->p + rs->q) <= UPPER_BIT_RUBIN)) { | 40 | while ((rs->q >= UPPER_BIT_RUBIN) || ((rs->p + rs->q) <= UPPER_BIT_RUBIN)) { |
42 | rs->bit_number++; | 41 | rs->bit_number++; |
43 | 42 | ||
44 | ret = pushbit(&rs->pp, (rs->q & UPPER_BIT_RUBIN) ? 1 : 0, 0); | 43 | ret = pushbit(&rs->pp, (rs->q & UPPER_BIT_RUBIN) ? 1 : 0, 0); |
45 | if (ret) | 44 | if (ret) |
46 | return ret; | 45 | return ret; |
@@ -68,7 +67,7 @@ static int encode(struct rubin_state *rs, long A, long B, int symbol) | |||
68 | 67 | ||
69 | 68 | ||
70 | static void end_rubin(struct rubin_state *rs) | 69 | static void end_rubin(struct rubin_state *rs) |
71 | { | 70 | { |
72 | 71 | ||
73 | int i; | 72 | int i; |
74 | 73 | ||
@@ -82,7 +81,7 @@ static void end_rubin(struct rubin_state *rs) | |||
82 | 81 | ||
83 | static void init_decode(struct rubin_state *rs, int div, int *bits) | 82 | static void init_decode(struct rubin_state *rs, int div, int *bits) |
84 | { | 83 | { |
85 | init_rubin(rs, div, bits); | 84 | init_rubin(rs, div, bits); |
86 | 85 | ||
87 | /* behalve lower */ | 86 | /* behalve lower */ |
88 | rs->rec_q = 0; | 87 | rs->rec_q = 0; |
@@ -188,7 +187,7 @@ static int in_byte(struct rubin_state *rs) | |||
188 | 187 | ||
189 | 188 | ||
190 | 189 | ||
191 | static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, | 190 | static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, |
192 | unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) | 191 | unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) |
193 | { | 192 | { |
194 | int outpos = 0; | 193 | int outpos = 0; |
@@ -198,31 +197,31 @@ static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, | |||
198 | init_pushpull(&rs.pp, cpage_out, *dstlen * 8, 0, 32); | 197 | init_pushpull(&rs.pp, cpage_out, *dstlen * 8, 0, 32); |
199 | 198 | ||
200 | init_rubin(&rs, bit_divider, bits); | 199 | init_rubin(&rs, bit_divider, bits); |
201 | 200 | ||
202 | while (pos < (*sourcelen) && !out_byte(&rs, data_in[pos])) | 201 | while (pos < (*sourcelen) && !out_byte(&rs, data_in[pos])) |
203 | pos++; | 202 | pos++; |
204 | 203 | ||
205 | end_rubin(&rs); | 204 | end_rubin(&rs); |
206 | 205 | ||
207 | if (outpos > pos) { | 206 | if (outpos > pos) { |
208 | /* We failed */ | 207 | /* We failed */ |
209 | return -1; | 208 | return -1; |
210 | } | 209 | } |
211 | 210 | ||
212 | /* Tell the caller how much we managed to compress, | 211 | /* Tell the caller how much we managed to compress, |
213 | * and how much space it took */ | 212 | * and how much space it took */ |
214 | 213 | ||
215 | outpos = (pushedbits(&rs.pp)+7)/8; | 214 | outpos = (pushedbits(&rs.pp)+7)/8; |
216 | 215 | ||
217 | if (outpos >= pos) | 216 | if (outpos >= pos) |
218 | return -1; /* We didn't actually compress */ | 217 | return -1; /* We didn't actually compress */ |
219 | *sourcelen = pos; | 218 | *sourcelen = pos; |
220 | *dstlen = outpos; | 219 | *dstlen = outpos; |
221 | return 0; | 220 | return 0; |
222 | } | 221 | } |
223 | #if 0 | 222 | #if 0 |
224 | /* _compress returns the compressed size, -1 if bigger */ | 223 | /* _compress returns the compressed size, -1 if bigger */ |
225 | int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, | 224 | int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, |
226 | uint32_t *sourcelen, uint32_t *dstlen, void *model) | 225 | uint32_t *sourcelen, uint32_t *dstlen, void *model) |
227 | { | 226 | { |
228 | return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); | 227 | return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); |
@@ -277,7 +276,7 @@ static int jffs2_dynrubin_compress(unsigned char *data_in, | |||
277 | } | 276 | } |
278 | 277 | ||
279 | ret = rubin_do_compress(256, bits, data_in, cpage_out+8, &mysrclen, &mydstlen); | 278 | ret = rubin_do_compress(256, bits, data_in, cpage_out+8, &mysrclen, &mydstlen); |
280 | if (ret) | 279 | if (ret) |
281 | return ret; | 280 | return ret; |
282 | 281 | ||
283 | /* Add back the 8 bytes we took for the probabilities */ | 282 | /* Add back the 8 bytes we took for the probabilities */ |
@@ -293,19 +292,19 @@ static int jffs2_dynrubin_compress(unsigned char *data_in, | |||
293 | return 0; | 292 | return 0; |
294 | } | 293 | } |
295 | 294 | ||
296 | static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, | 295 | static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, |
297 | unsigned char *page_out, uint32_t srclen, uint32_t destlen) | 296 | unsigned char *page_out, uint32_t srclen, uint32_t destlen) |
298 | { | 297 | { |
299 | int outpos = 0; | 298 | int outpos = 0; |
300 | struct rubin_state rs; | 299 | struct rubin_state rs; |
301 | 300 | ||
302 | init_pushpull(&rs.pp, cdata_in, srclen, 0, 0); | 301 | init_pushpull(&rs.pp, cdata_in, srclen, 0, 0); |
303 | init_decode(&rs, bit_divider, bits); | 302 | init_decode(&rs, bit_divider, bits); |
304 | 303 | ||
305 | while (outpos < destlen) { | 304 | while (outpos < destlen) { |
306 | page_out[outpos++] = in_byte(&rs); | 305 | page_out[outpos++] = in_byte(&rs); |
307 | } | 306 | } |
308 | } | 307 | } |
309 | 308 | ||
310 | 309 | ||
311 | static int jffs2_rubinmips_decompress(unsigned char *data_in, | 310 | static int jffs2_rubinmips_decompress(unsigned char *data_in, |
diff --git a/fs/jffs2/compr_rubin.h b/fs/jffs2/compr_rubin.h index cf51e34f6574..bf1a93451621 100644 --- a/fs/jffs2/compr_rubin.h +++ b/fs/jffs2/compr_rubin.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* Rubin encoder/decoder header */ | 1 | /* Rubin encoder/decoder header */ |
2 | /* work started at : aug 3, 1994 */ | 2 | /* work started at : aug 3, 1994 */ |
3 | /* last modification : aug 15, 1994 */ | 3 | /* last modification : aug 15, 1994 */ |
4 | /* $Id: compr_rubin.h,v 1.6 2002/01/25 01:49:26 dwmw2 Exp $ */ | 4 | /* $Id: compr_rubin.h,v 1.7 2005/11/07 11:14:38 gleixner Exp $ */ |
5 | 5 | ||
6 | #include "pushpull.h" | 6 | #include "pushpull.h" |
7 | 7 | ||
@@ -11,8 +11,8 @@ | |||
11 | 11 | ||
12 | 12 | ||
13 | struct rubin_state { | 13 | struct rubin_state { |
14 | unsigned long p; | 14 | unsigned long p; |
15 | unsigned long q; | 15 | unsigned long q; |
16 | unsigned long rec_q; | 16 | unsigned long rec_q; |
17 | long bit_number; | 17 | long bit_number; |
18 | struct pushpull pp; | 18 | struct pushpull pp; |
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 83f7e0788fd0..4db8be8e90cc 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $ | 10 | * $Id: compr_zlib.c,v 1.32 2005/11/07 11:14:38 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -24,11 +24,11 @@ | |||
24 | #include "nodelist.h" | 24 | #include "nodelist.h" |
25 | #include "compr.h" | 25 | #include "compr.h" |
26 | 26 | ||
27 | /* Plan: call deflate() with avail_in == *sourcelen, | 27 | /* Plan: call deflate() with avail_in == *sourcelen, |
28 | avail_out = *dstlen - 12 and flush == Z_FINISH. | 28 | avail_out = *dstlen - 12 and flush == Z_FINISH. |
29 | If it doesn't manage to finish, call it again with | 29 | If it doesn't manage to finish, call it again with |
30 | avail_in == 0 and avail_out set to the remaining 12 | 30 | avail_in == 0 and avail_out set to the remaining 12 |
31 | bytes for it to clean up. | 31 | bytes for it to clean up. |
32 | Q: Is 12 bytes sufficient? | 32 | Q: Is 12 bytes sufficient? |
33 | */ | 33 | */ |
34 | #define STREAM_END_SPACE 12 | 34 | #define STREAM_END_SPACE 12 |
@@ -89,7 +89,7 @@ static int jffs2_zlib_compress(unsigned char *data_in, | |||
89 | 89 | ||
90 | def_strm.next_in = data_in; | 90 | def_strm.next_in = data_in; |
91 | def_strm.total_in = 0; | 91 | def_strm.total_in = 0; |
92 | 92 | ||
93 | def_strm.next_out = cpage_out; | 93 | def_strm.next_out = cpage_out; |
94 | def_strm.total_out = 0; | 94 | def_strm.total_out = 0; |
95 | 95 | ||
@@ -99,7 +99,7 @@ static int jffs2_zlib_compress(unsigned char *data_in, | |||
99 | D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n", | 99 | D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n", |
100 | def_strm.avail_in, def_strm.avail_out)); | 100 | def_strm.avail_in, def_strm.avail_out)); |
101 | ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); | 101 | ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); |
102 | D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", | 102 | D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", |
103 | def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out)); | 103 | def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out)); |
104 | if (ret != Z_OK) { | 104 | if (ret != Z_OK) { |
105 | D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret)); | 105 | D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret)); |
@@ -150,7 +150,7 @@ static int jffs2_zlib_decompress(unsigned char *data_in, | |||
150 | inf_strm.next_in = data_in; | 150 | inf_strm.next_in = data_in; |
151 | inf_strm.avail_in = srclen; | 151 | inf_strm.avail_in = srclen; |
152 | inf_strm.total_in = 0; | 152 | inf_strm.total_in = 0; |
153 | 153 | ||
154 | inf_strm.next_out = cpage_out; | 154 | inf_strm.next_out = cpage_out; |
155 | inf_strm.avail_out = destlen; | 155 | inf_strm.avail_out = destlen; |
156 | inf_strm.total_out = 0; | 156 | inf_strm.total_out = 0; |
diff --git a/fs/jffs2/comprtest.c b/fs/jffs2/comprtest.c index cf51f091d0e7..f0fb8be7740c 100644 --- a/fs/jffs2/comprtest.c +++ b/fs/jffs2/comprtest.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: comprtest.c,v 1.5 2002/01/03 15:20:44 dwmw2 Exp $ */ | 1 | /* $Id: comprtest.c,v 1.6 2005/11/07 11:14:38 gleixner Exp $ */ |
2 | 2 | ||
3 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
4 | #include <linux/string.h> | 4 | #include <linux/string.h> |
@@ -265,9 +265,9 @@ static unsigned char testdata[TESTDATA_LEN] = { | |||
265 | static unsigned char comprbuf[TESTDATA_LEN]; | 265 | static unsigned char comprbuf[TESTDATA_LEN]; |
266 | static unsigned char decomprbuf[TESTDATA_LEN]; | 266 | static unsigned char decomprbuf[TESTDATA_LEN]; |
267 | 267 | ||
268 | int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, | 268 | int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, |
269 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); | 269 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); |
270 | unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, | 270 | unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, |
271 | uint32_t *datalen, uint32_t *cdatalen); | 271 | uint32_t *datalen, uint32_t *cdatalen); |
272 | 272 | ||
273 | int init_module(void ) { | 273 | int init_module(void ) { |
@@ -276,10 +276,10 @@ int init_module(void ) { | |||
276 | int ret; | 276 | int ret; |
277 | 277 | ||
278 | printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", | 278 | printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", |
279 | testdata[0],testdata[1],testdata[2],testdata[3], | 279 | testdata[0],testdata[1],testdata[2],testdata[3], |
280 | testdata[4],testdata[5],testdata[6],testdata[7], | 280 | testdata[4],testdata[5],testdata[6],testdata[7], |
281 | testdata[8],testdata[9],testdata[10],testdata[11], | 281 | testdata[8],testdata[9],testdata[10],testdata[11], |
282 | testdata[12],testdata[13],testdata[14],testdata[15]); | 282 | testdata[12],testdata[13],testdata[14],testdata[15]); |
283 | d = TESTDATA_LEN; | 283 | d = TESTDATA_LEN; |
284 | c = TESTDATA_LEN; | 284 | c = TESTDATA_LEN; |
285 | comprtype = jffs2_compress(testdata, comprbuf, &d, &c); | 285 | comprtype = jffs2_compress(testdata, comprbuf, &d, &c); |
@@ -287,18 +287,18 @@ int init_module(void ) { | |||
287 | printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n", | 287 | printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n", |
288 | comprtype, c, d); | 288 | comprtype, c, d); |
289 | printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", | 289 | printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", |
290 | comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3], | 290 | comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3], |
291 | comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7], | 291 | comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7], |
292 | comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11], | 292 | comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11], |
293 | comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]); | 293 | comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]); |
294 | 294 | ||
295 | ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d); | 295 | ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d); |
296 | printk("jffs2_decompress returned %d\n", ret); | 296 | printk("jffs2_decompress returned %d\n", ret); |
297 | printk("Decompressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", | 297 | printk("Decompressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", |
298 | decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3], | 298 | decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3], |
299 | decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7], | 299 | decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7], |
300 | decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11], | 300 | decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11], |
301 | decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]); | 301 | decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]); |
302 | if (memcmp(decomprbuf, testdata, d)) | 302 | if (memcmp(decomprbuf, testdata, d)) |
303 | printk("Compression and decompression corrupted data\n"); | 303 | printk("Compression and decompression corrupted data\n"); |
304 | else | 304 | else |
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c new file mode 100644 index 000000000000..1fe17de713e8 --- /dev/null +++ b/fs/jffs2/debug.c | |||
@@ -0,0 +1,705 @@ | |||
1 | /* | ||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
3 | * | ||
4 | * Copyright (C) 2001-2003 Red Hat, Inc. | ||
5 | * | ||
6 | * Created by David Woodhouse <dwmw2@infradead.org> | ||
7 | * | ||
8 | * For licensing information, see the file 'LICENCE' in this directory. | ||
9 | * | ||
10 | * $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $ | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/pagemap.h> | ||
16 | #include <linux/crc32.h> | ||
17 | #include <linux/jffs2.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include "nodelist.h" | ||
20 | #include "debug.h" | ||
21 | |||
22 | #ifdef JFFS2_DBG_SANITY_CHECKS | ||
23 | |||
24 | void | ||
25 | __jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c, | ||
26 | struct jffs2_eraseblock *jeb) | ||
27 | { | ||
28 | if (unlikely(jeb && jeb->used_size + jeb->dirty_size + | ||
29 | jeb->free_size + jeb->wasted_size + | ||
30 | jeb->unchecked_size != c->sector_size)) { | ||
31 | JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset); | ||
32 | JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n", | ||
33 | jeb->free_size, jeb->dirty_size, jeb->used_size, | ||
34 | jeb->wasted_size, jeb->unchecked_size, c->sector_size); | ||
35 | BUG(); | ||
36 | } | ||
37 | |||
38 | if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size | ||
39 | + c->wasted_size + c->unchecked_size != c->flash_size)) { | ||
40 | JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n"); | ||
41 | JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n", | ||
42 | c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, | ||
43 | c->wasted_size, c->unchecked_size, c->flash_size); | ||
44 | BUG(); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | void | ||
49 | __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c, | ||
50 | struct jffs2_eraseblock *jeb) | ||
51 | { | ||
52 | spin_lock(&c->erase_completion_lock); | ||
53 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); | ||
54 | spin_unlock(&c->erase_completion_lock); | ||
55 | } | ||
56 | |||
57 | #endif /* JFFS2_DBG_SANITY_CHECKS */ | ||
58 | |||
59 | #ifdef JFFS2_DBG_PARANOIA_CHECKS | ||
60 | /* | ||
61 | * Check the fragtree. | ||
62 | */ | ||
63 | void | ||
64 | __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) | ||
65 | { | ||
66 | down(&f->sem); | ||
67 | __jffs2_dbg_fragtree_paranoia_check_nolock(f); | ||
68 | up(&f->sem); | ||
69 | } | ||
70 | |||
71 | void | ||
72 | __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f) | ||
73 | { | ||
74 | struct jffs2_node_frag *frag; | ||
75 | int bitched = 0; | ||
76 | |||
77 | for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { | ||
78 | struct jffs2_full_dnode *fn = frag->node; | ||
79 | |||
80 | if (!fn || !fn->raw) | ||
81 | continue; | ||
82 | |||
83 | if (ref_flags(fn->raw) == REF_PRISTINE) { | ||
84 | if (fn->frags > 1) { | ||
85 | JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n", | ||
86 | ref_offset(fn->raw), fn->frags); | ||
87 | bitched = 1; | ||
88 | } | ||
89 | |||
90 | /* A hole node which isn't multi-page should be garbage-collected | ||
91 | and merged anyway, so we just check for the frag size here, | ||
92 | rather than mucking around with actually reading the node | ||
93 | and checking the compression type, which is the real way | ||
94 | to tell a hole node. */ | ||
95 | if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) | ||
96 | && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { | ||
97 | JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n", | ||
98 | ref_offset(fn->raw)); | ||
99 | bitched = 1; | ||
100 | } | ||
101 | |||
102 | if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) | ||
103 | && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { | ||
104 | JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n", | ||
105 | ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); | ||
106 | bitched = 1; | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | if (bitched) { | ||
112 | JFFS2_ERROR("fragtree is corrupted.\n"); | ||
113 | __jffs2_dbg_dump_fragtree_nolock(f); | ||
114 | BUG(); | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Check if the flash contains all 0xFF before we start writing. | ||
120 | */ | ||
121 | void | ||
122 | __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, | ||
123 | uint32_t ofs, int len) | ||
124 | { | ||
125 | size_t retlen; | ||
126 | int ret, i; | ||
127 | unsigned char *buf; | ||
128 | |||
129 | buf = kmalloc(len, GFP_KERNEL); | ||
130 | if (!buf) | ||
131 | return; | ||
132 | |||
133 | ret = jffs2_flash_read(c, ofs, len, &retlen, buf); | ||
134 | if (ret || (retlen != len)) { | ||
135 | JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n", | ||
136 | len, ret, retlen); | ||
137 | kfree(buf); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | ret = 0; | ||
142 | for (i = 0; i < len; i++) | ||
143 | if (buf[i] != 0xff) | ||
144 | ret = 1; | ||
145 | |||
146 | if (ret) { | ||
147 | JFFS2_ERROR("argh, about to write node to %#08x on flash, but there are data already there. The first corrupted byte is at %#08x offset.\n", | ||
148 | ofs, ofs + i); | ||
149 | __jffs2_dbg_dump_buffer(buf, len, ofs); | ||
150 | kfree(buf); | ||
151 | BUG(); | ||
152 | } | ||
153 | |||
154 | kfree(buf); | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. | ||
159 | */ | ||
160 | void | ||
161 | __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c, | ||
162 | struct jffs2_eraseblock *jeb) | ||
163 | { | ||
164 | spin_lock(&c->erase_completion_lock); | ||
165 | __jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | ||
166 | spin_unlock(&c->erase_completion_lock); | ||
167 | } | ||
168 | |||
169 | void | ||
170 | __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, | ||
171 | struct jffs2_eraseblock *jeb) | ||
172 | { | ||
173 | uint32_t my_used_size = 0; | ||
174 | uint32_t my_unchecked_size = 0; | ||
175 | uint32_t my_dirty_size = 0; | ||
176 | struct jffs2_raw_node_ref *ref2 = jeb->first_node; | ||
177 | |||
178 | while (ref2) { | ||
179 | uint32_t totlen = ref_totlen(c, jeb, ref2); | ||
180 | |||
181 | if (ref2->flash_offset < jeb->offset || | ||
182 | ref2->flash_offset > jeb->offset + c->sector_size) { | ||
183 | JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n", | ||
184 | ref_offset(ref2), jeb->offset); | ||
185 | goto error; | ||
186 | |||
187 | } | ||
188 | if (ref_flags(ref2) == REF_UNCHECKED) | ||
189 | my_unchecked_size += totlen; | ||
190 | else if (!ref_obsolete(ref2)) | ||
191 | my_used_size += totlen; | ||
192 | else | ||
193 | my_dirty_size += totlen; | ||
194 | |||
195 | if ((!ref2->next_phys) != (ref2 == jeb->last_node)) { | ||
196 | JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next_phys at %#08x (mem %p), last_node is at %#08x (mem %p).\n", | ||
197 | ref_offset(ref2), ref2, ref_offset(ref2->next_phys), ref2->next_phys, | ||
198 | ref_offset(jeb->last_node), jeb->last_node); | ||
199 | goto error; | ||
200 | } | ||
201 | ref2 = ref2->next_phys; | ||
202 | } | ||
203 | |||
204 | if (my_used_size != jeb->used_size) { | ||
205 | JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n", | ||
206 | my_used_size, jeb->used_size); | ||
207 | goto error; | ||
208 | } | ||
209 | |||
210 | if (my_unchecked_size != jeb->unchecked_size) { | ||
211 | JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n", | ||
212 | my_unchecked_size, jeb->unchecked_size); | ||
213 | goto error; | ||
214 | } | ||
215 | |||
216 | #if 0 | ||
217 | /* This should work when we implement ref->__totlen elemination */ | ||
218 | if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) { | ||
219 | JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n", | ||
220 | my_dirty_size, jeb->dirty_size + jeb->wasted_size); | ||
221 | goto error; | ||
222 | } | ||
223 | |||
224 | if (jeb->free_size == 0 | ||
225 | && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) { | ||
226 | JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n", | ||
227 | my_used_size + my_unchecked_size + my_dirty_size, | ||
228 | c->sector_size); | ||
229 | goto error; | ||
230 | } | ||
231 | #endif | ||
232 | |||
233 | return; | ||
234 | |||
235 | error: | ||
236 | __jffs2_dbg_dump_node_refs_nolock(c, jeb); | ||
237 | __jffs2_dbg_dump_jeb_nolock(jeb); | ||
238 | __jffs2_dbg_dump_block_lists_nolock(c); | ||
239 | BUG(); | ||
240 | |||
241 | } | ||
242 | #endif /* JFFS2_DBG_PARANOIA_CHECKS */ | ||
243 | |||
244 | #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) | ||
245 | /* | ||
246 | * Dump the node_refs of the 'jeb' JFFS2 eraseblock. | ||
247 | */ | ||
248 | void | ||
249 | __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, | ||
250 | struct jffs2_eraseblock *jeb) | ||
251 | { | ||
252 | spin_lock(&c->erase_completion_lock); | ||
253 | __jffs2_dbg_dump_node_refs_nolock(c, jeb); | ||
254 | spin_unlock(&c->erase_completion_lock); | ||
255 | } | ||
256 | |||
257 | void | ||
258 | __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, | ||
259 | struct jffs2_eraseblock *jeb) | ||
260 | { | ||
261 | struct jffs2_raw_node_ref *ref; | ||
262 | int i = 0; | ||
263 | |||
264 | printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset); | ||
265 | if (!jeb->first_node) { | ||
266 | printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | printk(JFFS2_DBG); | ||
271 | for (ref = jeb->first_node; ; ref = ref->next_phys) { | ||
272 | printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); | ||
273 | if (ref->next_phys) | ||
274 | printk("->"); | ||
275 | else | ||
276 | break; | ||
277 | if (++i == 4) { | ||
278 | i = 0; | ||
279 | printk("\n" JFFS2_DBG); | ||
280 | } | ||
281 | } | ||
282 | printk("\n"); | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * Dump an eraseblock's space accounting. | ||
287 | */ | ||
288 | void | ||
289 | __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | ||
290 | { | ||
291 | spin_lock(&c->erase_completion_lock); | ||
292 | __jffs2_dbg_dump_jeb_nolock(jeb); | ||
293 | spin_unlock(&c->erase_completion_lock); | ||
294 | } | ||
295 | |||
296 | void | ||
297 | __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb) | ||
298 | { | ||
299 | if (!jeb) | ||
300 | return; | ||
301 | |||
302 | printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n", | ||
303 | jeb->offset); | ||
304 | |||
305 | printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size); | ||
306 | printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size); | ||
307 | printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size); | ||
308 | printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size); | ||
309 | printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size); | ||
310 | } | ||
311 | |||
312 | void | ||
313 | __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c) | ||
314 | { | ||
315 | spin_lock(&c->erase_completion_lock); | ||
316 | __jffs2_dbg_dump_block_lists_nolock(c); | ||
317 | spin_unlock(&c->erase_completion_lock); | ||
318 | } | ||
319 | |||
320 | void | ||
321 | __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) | ||
322 | { | ||
323 | printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n"); | ||
324 | |||
325 | printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size); | ||
326 | printk(JFFS2_DBG "used_size: %#08x\n", c->used_size); | ||
327 | printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size); | ||
328 | printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size); | ||
329 | printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size); | ||
330 | printk(JFFS2_DBG "free_size: %#08x\n", c->free_size); | ||
331 | printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size); | ||
332 | printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size); | ||
333 | printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size); | ||
334 | printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n", | ||
335 | c->sector_size * c->resv_blocks_write); | ||
336 | |||
337 | if (c->nextblock) | ||
338 | printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
339 | c->nextblock->offset, c->nextblock->used_size, | ||
340 | c->nextblock->dirty_size, c->nextblock->wasted_size, | ||
341 | c->nextblock->unchecked_size, c->nextblock->free_size); | ||
342 | else | ||
343 | printk(JFFS2_DBG "nextblock: NULL\n"); | ||
344 | |||
345 | if (c->gcblock) | ||
346 | printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
347 | c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, | ||
348 | c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); | ||
349 | else | ||
350 | printk(JFFS2_DBG "gcblock: NULL\n"); | ||
351 | |||
352 | if (list_empty(&c->clean_list)) { | ||
353 | printk(JFFS2_DBG "clean_list: empty\n"); | ||
354 | } else { | ||
355 | struct list_head *this; | ||
356 | int numblocks = 0; | ||
357 | uint32_t dirty = 0; | ||
358 | |||
359 | list_for_each(this, &c->clean_list) { | ||
360 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
361 | numblocks ++; | ||
362 | dirty += jeb->wasted_size; | ||
363 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
364 | printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
365 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
366 | jeb->unchecked_size, jeb->free_size); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", | ||
371 | numblocks, dirty, dirty / numblocks); | ||
372 | } | ||
373 | |||
374 | if (list_empty(&c->very_dirty_list)) { | ||
375 | printk(JFFS2_DBG "very_dirty_list: empty\n"); | ||
376 | } else { | ||
377 | struct list_head *this; | ||
378 | int numblocks = 0; | ||
379 | uint32_t dirty = 0; | ||
380 | |||
381 | list_for_each(this, &c->very_dirty_list) { | ||
382 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
383 | |||
384 | numblocks ++; | ||
385 | dirty += jeb->dirty_size; | ||
386 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
387 | printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
388 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
389 | jeb->unchecked_size, jeb->free_size); | ||
390 | } | ||
391 | } | ||
392 | |||
393 | printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", | ||
394 | numblocks, dirty, dirty / numblocks); | ||
395 | } | ||
396 | |||
397 | if (list_empty(&c->dirty_list)) { | ||
398 | printk(JFFS2_DBG "dirty_list: empty\n"); | ||
399 | } else { | ||
400 | struct list_head *this; | ||
401 | int numblocks = 0; | ||
402 | uint32_t dirty = 0; | ||
403 | |||
404 | list_for_each(this, &c->dirty_list) { | ||
405 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
406 | |||
407 | numblocks ++; | ||
408 | dirty += jeb->dirty_size; | ||
409 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
410 | printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
411 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
412 | jeb->unchecked_size, jeb->free_size); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n", | ||
417 | numblocks, dirty, dirty / numblocks); | ||
418 | } | ||
419 | |||
420 | if (list_empty(&c->erasable_list)) { | ||
421 | printk(JFFS2_DBG "erasable_list: empty\n"); | ||
422 | } else { | ||
423 | struct list_head *this; | ||
424 | |||
425 | list_for_each(this, &c->erasable_list) { | ||
426 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
427 | |||
428 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
429 | printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
430 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
431 | jeb->unchecked_size, jeb->free_size); | ||
432 | } | ||
433 | } | ||
434 | } | ||
435 | |||
436 | if (list_empty(&c->erasing_list)) { | ||
437 | printk(JFFS2_DBG "erasing_list: empty\n"); | ||
438 | } else { | ||
439 | struct list_head *this; | ||
440 | |||
441 | list_for_each(this, &c->erasing_list) { | ||
442 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
443 | |||
444 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
445 | printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
446 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
447 | jeb->unchecked_size, jeb->free_size); | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | if (list_empty(&c->erase_pending_list)) { | ||
453 | printk(JFFS2_DBG "erase_pending_list: empty\n"); | ||
454 | } else { | ||
455 | struct list_head *this; | ||
456 | |||
457 | list_for_each(this, &c->erase_pending_list) { | ||
458 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
459 | |||
460 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
461 | printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
462 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
463 | jeb->unchecked_size, jeb->free_size); | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | |||
468 | if (list_empty(&c->erasable_pending_wbuf_list)) { | ||
469 | printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n"); | ||
470 | } else { | ||
471 | struct list_head *this; | ||
472 | |||
473 | list_for_each(this, &c->erasable_pending_wbuf_list) { | ||
474 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
475 | |||
476 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
477 | printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
478 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
479 | jeb->unchecked_size, jeb->free_size); | ||
480 | } | ||
481 | } | ||
482 | } | ||
483 | |||
484 | if (list_empty(&c->free_list)) { | ||
485 | printk(JFFS2_DBG "free_list: empty\n"); | ||
486 | } else { | ||
487 | struct list_head *this; | ||
488 | |||
489 | list_for_each(this, &c->free_list) { | ||
490 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
491 | |||
492 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
493 | printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
494 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
495 | jeb->unchecked_size, jeb->free_size); | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | |||
500 | if (list_empty(&c->bad_list)) { | ||
501 | printk(JFFS2_DBG "bad_list: empty\n"); | ||
502 | } else { | ||
503 | struct list_head *this; | ||
504 | |||
505 | list_for_each(this, &c->bad_list) { | ||
506 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
507 | |||
508 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
509 | printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
510 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
511 | jeb->unchecked_size, jeb->free_size); | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | |||
516 | if (list_empty(&c->bad_used_list)) { | ||
517 | printk(JFFS2_DBG "bad_used_list: empty\n"); | ||
518 | } else { | ||
519 | struct list_head *this; | ||
520 | |||
521 | list_for_each(this, &c->bad_used_list) { | ||
522 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
523 | |||
524 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
525 | printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
526 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
527 | jeb->unchecked_size, jeb->free_size); | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | } | ||
532 | |||
533 | void | ||
534 | __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) | ||
535 | { | ||
536 | down(&f->sem); | ||
537 | jffs2_dbg_dump_fragtree_nolock(f); | ||
538 | up(&f->sem); | ||
539 | } | ||
540 | |||
541 | void | ||
542 | __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f) | ||
543 | { | ||
544 | struct jffs2_node_frag *this = frag_first(&f->fragtree); | ||
545 | uint32_t lastofs = 0; | ||
546 | int buggy = 0; | ||
547 | |||
548 | printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino); | ||
549 | while(this) { | ||
550 | if (this->node) | ||
551 | printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n", | ||
552 | this->ofs, this->ofs+this->size, ref_offset(this->node->raw), | ||
553 | ref_flags(this->node->raw), this, frag_left(this), frag_right(this), | ||
554 | frag_parent(this)); | ||
555 | else | ||
556 | printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n", | ||
557 | this->ofs, this->ofs+this->size, this, frag_left(this), | ||
558 | frag_right(this), frag_parent(this)); | ||
559 | if (this->ofs != lastofs) | ||
560 | buggy = 1; | ||
561 | lastofs = this->ofs + this->size; | ||
562 | this = frag_next(this); | ||
563 | } | ||
564 | |||
565 | if (f->metadata) | ||
566 | printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); | ||
567 | |||
568 | if (buggy) { | ||
569 | JFFS2_ERROR("frag tree got a hole in it.\n"); | ||
570 | BUG(); | ||
571 | } | ||
572 | } | ||
573 | |||
574 | #define JFFS2_BUFDUMP_BYTES_PER_LINE 32 | ||
575 | void | ||
576 | __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs) | ||
577 | { | ||
578 | int skip; | ||
579 | int i; | ||
580 | |||
581 | printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n", | ||
582 | offs, offs + len, len); | ||
583 | i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE; | ||
584 | offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1); | ||
585 | |||
586 | if (skip != 0) | ||
587 | printk(JFFS2_DBG "%#08x: ", offs); | ||
588 | |||
589 | while (skip--) | ||
590 | printk(" "); | ||
591 | |||
592 | while (i < len) { | ||
593 | if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) { | ||
594 | if (i != 0) | ||
595 | printk("\n"); | ||
596 | offs += JFFS2_BUFDUMP_BYTES_PER_LINE; | ||
597 | printk(JFFS2_DBG "%0#8x: ", offs); | ||
598 | } | ||
599 | |||
600 | printk("%02x ", buf[i]); | ||
601 | |||
602 | i += 1; | ||
603 | } | ||
604 | |||
605 | printk("\n"); | ||
606 | } | ||
607 | |||
608 | /* | ||
609 | * Dump a JFFS2 node. | ||
610 | */ | ||
611 | void | ||
612 | __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs) | ||
613 | { | ||
614 | union jffs2_node_union node; | ||
615 | int len = sizeof(union jffs2_node_union); | ||
616 | size_t retlen; | ||
617 | uint32_t crc; | ||
618 | int ret; | ||
619 | |||
620 | printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs); | ||
621 | |||
622 | ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node); | ||
623 | if (ret || (retlen != len)) { | ||
624 | JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n", | ||
625 | len, ret, retlen); | ||
626 | return; | ||
627 | } | ||
628 | |||
629 | printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic)); | ||
630 | printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype)); | ||
631 | printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen)); | ||
632 | printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc)); | ||
633 | |||
634 | crc = crc32(0, &node.u, sizeof(node.u) - 4); | ||
635 | if (crc != je32_to_cpu(node.u.hdr_crc)) { | ||
636 | JFFS2_ERROR("wrong common header CRC.\n"); | ||
637 | return; | ||
638 | } | ||
639 | |||
640 | if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK && | ||
641 | je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK) | ||
642 | { | ||
643 | JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n", | ||
644 | je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK); | ||
645 | return; | ||
646 | } | ||
647 | |||
648 | switch(je16_to_cpu(node.u.nodetype)) { | ||
649 | |||
650 | case JFFS2_NODETYPE_INODE: | ||
651 | |||
652 | printk(JFFS2_DBG "the node is inode node\n"); | ||
653 | printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino)); | ||
654 | printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version)); | ||
655 | printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m); | ||
656 | printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid)); | ||
657 | printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid)); | ||
658 | printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize)); | ||
659 | printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime)); | ||
660 | printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime)); | ||
661 | printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime)); | ||
662 | printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset)); | ||
663 | printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize)); | ||
664 | printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize)); | ||
665 | printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr); | ||
666 | printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr); | ||
667 | printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags)); | ||
668 | printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc)); | ||
669 | printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc)); | ||
670 | |||
671 | crc = crc32(0, &node.i, sizeof(node.i) - 8); | ||
672 | if (crc != je32_to_cpu(node.i.node_crc)) { | ||
673 | JFFS2_ERROR("wrong node header CRC.\n"); | ||
674 | return; | ||
675 | } | ||
676 | break; | ||
677 | |||
678 | case JFFS2_NODETYPE_DIRENT: | ||
679 | |||
680 | printk(JFFS2_DBG "the node is dirent node\n"); | ||
681 | printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino)); | ||
682 | printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version)); | ||
683 | printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino)); | ||
684 | printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime)); | ||
685 | printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize); | ||
686 | printk(JFFS2_DBG "type:\t%#02x\n", node.d.type); | ||
687 | printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc)); | ||
688 | printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc)); | ||
689 | |||
690 | node.d.name[node.d.nsize] = '\0'; | ||
691 | printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name); | ||
692 | |||
693 | crc = crc32(0, &node.d, sizeof(node.d) - 8); | ||
694 | if (crc != je32_to_cpu(node.d.node_crc)) { | ||
695 | JFFS2_ERROR("wrong node header CRC.\n"); | ||
696 | return; | ||
697 | } | ||
698 | break; | ||
699 | |||
700 | default: | ||
701 | printk(JFFS2_DBG "node type is unknown\n"); | ||
702 | break; | ||
703 | } | ||
704 | } | ||
705 | #endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */ | ||
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h new file mode 100644 index 000000000000..f193d43a8a59 --- /dev/null +++ b/fs/jffs2/debug.h | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
3 | * | ||
4 | * Copyright (C) 2001-2003 Red Hat, Inc. | ||
5 | * | ||
6 | * Created by David Woodhouse <dwmw2@infradead.org> | ||
7 | * | ||
8 | * For licensing information, see the file 'LICENCE' in this directory. | ||
9 | * | ||
10 | * $Id: debug.h,v 1.21 2005/11/07 11:14:39 gleixner Exp $ | ||
11 | * | ||
12 | */ | ||
13 | #ifndef _JFFS2_DEBUG_H_ | ||
14 | #define _JFFS2_DEBUG_H_ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | |||
18 | #ifndef CONFIG_JFFS2_FS_DEBUG | ||
19 | #define CONFIG_JFFS2_FS_DEBUG 0 | ||
20 | #endif | ||
21 | |||
22 | #if CONFIG_JFFS2_FS_DEBUG > 0 | ||
23 | /* Enable "paranoia" checks and dumps */ | ||
24 | #define JFFS2_DBG_PARANOIA_CHECKS | ||
25 | #define JFFS2_DBG_DUMPS | ||
26 | |||
27 | /* | ||
28 | * By defining/undefining the below macros one may select debugging messages | ||
29 | * fro specific JFFS2 subsystems. | ||
30 | */ | ||
31 | #define JFFS2_DBG_READINODE_MESSAGES | ||
32 | #define JFFS2_DBG_FRAGTREE_MESSAGES | ||
33 | #define JFFS2_DBG_DENTLIST_MESSAGES | ||
34 | #define JFFS2_DBG_NODEREF_MESSAGES | ||
35 | #define JFFS2_DBG_INOCACHE_MESSAGES | ||
36 | #define JFFS2_DBG_SUMMARY_MESSAGES | ||
37 | #define JFFS2_DBG_FSBUILD_MESSAGES | ||
38 | #endif | ||
39 | |||
40 | #if CONFIG_JFFS2_FS_DEBUG > 1 | ||
41 | #define JFFS2_DBG_FRAGTREE2_MESSAGES | ||
42 | #define JFFS2_DBG_MEMALLOC_MESSAGES | ||
43 | #endif | ||
44 | |||
45 | /* Sanity checks are supposed to be light-weight and enabled by default */ | ||
46 | #define JFFS2_DBG_SANITY_CHECKS | ||
47 | |||
48 | /* | ||
49 | * Dx() are mainly used for debugging messages, they must go away and be | ||
50 | * superseded by nicer dbg_xxx() macros... | ||
51 | */ | ||
52 | #if CONFIG_JFFS2_FS_DEBUG > 0 | ||
53 | #define D1(x) x | ||
54 | #else | ||
55 | #define D1(x) | ||
56 | #endif | ||
57 | |||
58 | #if CONFIG_JFFS2_FS_DEBUG > 1 | ||
59 | #define D2(x) x | ||
60 | #else | ||
61 | #define D2(x) | ||
62 | #endif | ||
63 | |||
64 | /* The prefixes of JFFS2 messages */ | ||
65 | #define JFFS2_DBG_PREFIX "[JFFS2 DBG]" | ||
66 | #define JFFS2_ERR_PREFIX "JFFS2 error:" | ||
67 | #define JFFS2_WARN_PREFIX "JFFS2 warning:" | ||
68 | #define JFFS2_NOTICE_PREFIX "JFFS2 notice:" | ||
69 | |||
70 | #define JFFS2_ERR KERN_ERR | ||
71 | #define JFFS2_WARN KERN_WARNING | ||
72 | #define JFFS2_NOT KERN_NOTICE | ||
73 | #define JFFS2_DBG KERN_DEBUG | ||
74 | |||
75 | #define JFFS2_DBG_MSG_PREFIX JFFS2_DBG JFFS2_DBG_PREFIX | ||
76 | #define JFFS2_ERR_MSG_PREFIX JFFS2_ERR JFFS2_ERR_PREFIX | ||
77 | #define JFFS2_WARN_MSG_PREFIX JFFS2_WARN JFFS2_WARN_PREFIX | ||
78 | #define JFFS2_NOTICE_MSG_PREFIX JFFS2_NOT JFFS2_NOTICE_PREFIX | ||
79 | |||
80 | /* JFFS2 message macros */ | ||
81 | #define JFFS2_ERROR(fmt, ...) \ | ||
82 | do { \ | ||
83 | printk(JFFS2_ERR_MSG_PREFIX \ | ||
84 | " (%d) %s: " fmt, current->pid, \ | ||
85 | __FUNCTION__, ##__VA_ARGS__); \ | ||
86 | } while(0) | ||
87 | |||
88 | #define JFFS2_WARNING(fmt, ...) \ | ||
89 | do { \ | ||
90 | printk(JFFS2_WARN_MSG_PREFIX \ | ||
91 | " (%d) %s: " fmt, current->pid, \ | ||
92 | __FUNCTION__, ##__VA_ARGS__); \ | ||
93 | } while(0) | ||
94 | |||
95 | #define JFFS2_NOTICE(fmt, ...) \ | ||
96 | do { \ | ||
97 | printk(JFFS2_NOTICE_MSG_PREFIX \ | ||
98 | " (%d) %s: " fmt, current->pid, \ | ||
99 | __FUNCTION__, ##__VA_ARGS__); \ | ||
100 | } while(0) | ||
101 | |||
102 | #define JFFS2_DEBUG(fmt, ...) \ | ||
103 | do { \ | ||
104 | printk(JFFS2_DBG_MSG_PREFIX \ | ||
105 | " (%d) %s: " fmt, current->pid, \ | ||
106 | __FUNCTION__, ##__VA_ARGS__); \ | ||
107 | } while(0) | ||
108 | |||
109 | /* | ||
110 | * We split our debugging messages on several parts, depending on the JFFS2 | ||
111 | * subsystem the message belongs to. | ||
112 | */ | ||
113 | /* Read inode debugging messages */ | ||
114 | #ifdef JFFS2_DBG_READINODE_MESSAGES | ||
115 | #define dbg_readinode(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
116 | #else | ||
117 | #define dbg_readinode(fmt, ...) | ||
118 | #endif | ||
119 | |||
120 | /* Fragtree build debugging messages */ | ||
121 | #ifdef JFFS2_DBG_FRAGTREE_MESSAGES | ||
122 | #define dbg_fragtree(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
123 | #else | ||
124 | #define dbg_fragtree(fmt, ...) | ||
125 | #endif | ||
126 | #ifdef JFFS2_DBG_FRAGTREE2_MESSAGES | ||
127 | #define dbg_fragtree2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
128 | #else | ||
129 | #define dbg_fragtree2(fmt, ...) | ||
130 | #endif | ||
131 | |||
132 | /* Directory entry list manilulation debugging messages */ | ||
133 | #ifdef JFFS2_DBG_DENTLIST_MESSAGES | ||
134 | #define dbg_dentlist(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
135 | #else | ||
136 | #define dbg_dentlist(fmt, ...) | ||
137 | #endif | ||
138 | |||
139 | /* Print the messages about manipulating node_refs */ | ||
140 | #ifdef JFFS2_DBG_NODEREF_MESSAGES | ||
141 | #define dbg_noderef(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
142 | #else | ||
143 | #define dbg_noderef(fmt, ...) | ||
144 | #endif | ||
145 | |||
146 | /* Manipulations with the list of inodes (JFFS2 inocache) */ | ||
147 | #ifdef JFFS2_DBG_INOCACHE_MESSAGES | ||
148 | #define dbg_inocache(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
149 | #else | ||
150 | #define dbg_inocache(fmt, ...) | ||
151 | #endif | ||
152 | |||
153 | /* Summary debugging messages */ | ||
154 | #ifdef JFFS2_DBG_SUMMARY_MESSAGES | ||
155 | #define dbg_summary(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
156 | #else | ||
157 | #define dbg_summary(fmt, ...) | ||
158 | #endif | ||
159 | |||
160 | /* File system build messages */ | ||
161 | #ifdef JFFS2_DBG_FSBUILD_MESSAGES | ||
162 | #define dbg_fsbuild(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
163 | #else | ||
164 | #define dbg_fsbuild(fmt, ...) | ||
165 | #endif | ||
166 | |||
167 | /* Watch the object allocations */ | ||
168 | #ifdef JFFS2_DBG_MEMALLOC_MESSAGES | ||
169 | #define dbg_memalloc(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
170 | #else | ||
171 | #define dbg_memalloc(fmt, ...) | ||
172 | #endif | ||
173 | |||
174 | |||
175 | /* "Sanity" checks */ | ||
176 | void | ||
177 | __jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c, | ||
178 | struct jffs2_eraseblock *jeb); | ||
179 | void | ||
180 | __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c, | ||
181 | struct jffs2_eraseblock *jeb); | ||
182 | |||
183 | /* "Paranoia" checks */ | ||
184 | void | ||
185 | __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f); | ||
186 | void | ||
187 | __jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f); | ||
188 | void | ||
189 | __jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c, | ||
190 | struct jffs2_eraseblock *jeb); | ||
191 | void | ||
192 | __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, | ||
193 | struct jffs2_eraseblock *jeb); | ||
194 | void | ||
195 | __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, | ||
196 | uint32_t ofs, int len); | ||
197 | |||
198 | /* "Dump" functions */ | ||
199 | void | ||
200 | __jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); | ||
201 | void | ||
202 | __jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb); | ||
203 | void | ||
204 | __jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c); | ||
205 | void | ||
206 | __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c); | ||
207 | void | ||
208 | __jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, | ||
209 | struct jffs2_eraseblock *jeb); | ||
210 | void | ||
211 | __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, | ||
212 | struct jffs2_eraseblock *jeb); | ||
213 | void | ||
214 | __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f); | ||
215 | void | ||
216 | __jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f); | ||
217 | void | ||
218 | __jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs); | ||
219 | void | ||
220 | __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs); | ||
221 | |||
222 | #ifdef JFFS2_DBG_PARANOIA_CHECKS | ||
223 | #define jffs2_dbg_fragtree_paranoia_check(f) \ | ||
224 | __jffs2_dbg_fragtree_paranoia_check(f) | ||
225 | #define jffs2_dbg_fragtree_paranoia_check_nolock(f) \ | ||
226 | __jffs2_dbg_fragtree_paranoia_check_nolock(f) | ||
227 | #define jffs2_dbg_acct_paranoia_check(c, jeb) \ | ||
228 | __jffs2_dbg_acct_paranoia_check(c,jeb) | ||
229 | #define jffs2_dbg_acct_paranoia_check_nolock(c, jeb) \ | ||
230 | __jffs2_dbg_acct_paranoia_check_nolock(c,jeb) | ||
231 | #define jffs2_dbg_prewrite_paranoia_check(c, ofs, len) \ | ||
232 | __jffs2_dbg_prewrite_paranoia_check(c, ofs, len) | ||
233 | #else | ||
234 | #define jffs2_dbg_fragtree_paranoia_check(f) | ||
235 | #define jffs2_dbg_fragtree_paranoia_check_nolock(f) | ||
236 | #define jffs2_dbg_acct_paranoia_check(c, jeb) | ||
237 | #define jffs2_dbg_acct_paranoia_check_nolock(c, jeb) | ||
238 | #define jffs2_dbg_prewrite_paranoia_check(c, ofs, len) | ||
239 | #endif /* !JFFS2_PARANOIA_CHECKS */ | ||
240 | |||
241 | #ifdef JFFS2_DBG_DUMPS | ||
242 | #define jffs2_dbg_dump_jeb(c, jeb) \ | ||
243 | __jffs2_dbg_dump_jeb(c, jeb); | ||
244 | #define jffs2_dbg_dump_jeb_nolock(jeb) \ | ||
245 | __jffs2_dbg_dump_jeb_nolock(jeb); | ||
246 | #define jffs2_dbg_dump_block_lists(c) \ | ||
247 | __jffs2_dbg_dump_block_lists(c) | ||
248 | #define jffs2_dbg_dump_block_lists_nolock(c) \ | ||
249 | __jffs2_dbg_dump_block_lists_nolock(c) | ||
250 | #define jffs2_dbg_dump_fragtree(f) \ | ||
251 | __jffs2_dbg_dump_fragtree(f); | ||
252 | #define jffs2_dbg_dump_fragtree_nolock(f) \ | ||
253 | __jffs2_dbg_dump_fragtree_nolock(f); | ||
254 | #define jffs2_dbg_dump_buffer(buf, len, offs) \ | ||
255 | __jffs2_dbg_dump_buffer(*buf, len, offs); | ||
256 | #define jffs2_dbg_dump_node(c, ofs) \ | ||
257 | __jffs2_dbg_dump_node(c, ofs); | ||
258 | #else | ||
259 | #define jffs2_dbg_dump_jeb(c, jeb) | ||
260 | #define jffs2_dbg_dump_jeb_nolock(jeb) | ||
261 | #define jffs2_dbg_dump_block_lists(c) | ||
262 | #define jffs2_dbg_dump_block_lists_nolock(c) | ||
263 | #define jffs2_dbg_dump_fragtree(f) | ||
264 | #define jffs2_dbg_dump_fragtree_nolock(f) | ||
265 | #define jffs2_dbg_dump_buffer(buf, len, offs) | ||
266 | #define jffs2_dbg_dump_node(c, ofs) | ||
267 | #endif /* !JFFS2_DBG_DUMPS */ | ||
268 | |||
269 | #ifdef JFFS2_DBG_SANITY_CHECKS | ||
270 | #define jffs2_dbg_acct_sanity_check(c, jeb) \ | ||
271 | __jffs2_dbg_acct_sanity_check(c, jeb) | ||
272 | #define jffs2_dbg_acct_sanity_check_nolock(c, jeb) \ | ||
273 | __jffs2_dbg_acct_sanity_check_nolock(c, jeb) | ||
274 | #else | ||
275 | #define jffs2_dbg_acct_sanity_check(c, jeb) | ||
276 | #define jffs2_dbg_acct_sanity_check_nolock(c, jeb) | ||
277 | #endif /* !JFFS2_DBG_SANITY_CHECKS */ | ||
278 | |||
279 | #endif /* _JFFS2_DEBUG_H_ */ | ||
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 3ca0d25eef1d..a7bf9cb2567f 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: dir.c,v 1.86 2005/07/06 12:13:09 dwmw2 Exp $ | 10 | * $Id: dir.c,v 1.90 2005/11/07 11:14:39 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -64,7 +64,7 @@ struct inode_operations jffs2_dir_inode_operations = | |||
64 | 64 | ||
65 | 65 | ||
66 | /* We keep the dirent list sorted in increasing order of name hash, | 66 | /* We keep the dirent list sorted in increasing order of name hash, |
67 | and we use the same hash function as the dentries. Makes this | 67 | and we use the same hash function as the dentries. Makes this |
68 | nice and simple | 68 | nice and simple |
69 | */ | 69 | */ |
70 | static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, | 70 | static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, |
@@ -85,7 +85,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, | |||
85 | 85 | ||
86 | /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ | 86 | /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ |
87 | for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { | 87 | for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { |
88 | if (fd_list->nhash == target->d_name.hash && | 88 | if (fd_list->nhash == target->d_name.hash && |
89 | (!fd || fd_list->version > fd->version) && | 89 | (!fd || fd_list->version > fd->version) && |
90 | strlen(fd_list->name) == target->d_name.len && | 90 | strlen(fd_list->name) == target->d_name.len && |
91 | !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { | 91 | !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { |
@@ -147,7 +147,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
147 | curofs++; | 147 | curofs++; |
148 | /* First loop: curofs = 2; offset = 2 */ | 148 | /* First loop: curofs = 2; offset = 2 */ |
149 | if (curofs < offset) { | 149 | if (curofs < offset) { |
150 | D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", | 150 | D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", |
151 | fd->name, fd->ino, fd->type, curofs, offset)); | 151 | fd->name, fd->ino, fd->type, curofs, offset)); |
152 | continue; | 152 | continue; |
153 | } | 153 | } |
@@ -182,7 +182,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
182 | ri = jffs2_alloc_raw_inode(); | 182 | ri = jffs2_alloc_raw_inode(); |
183 | if (!ri) | 183 | if (!ri) |
184 | return -ENOMEM; | 184 | return -ENOMEM; |
185 | 185 | ||
186 | c = JFFS2_SB_INFO(dir_i->i_sb); | 186 | c = JFFS2_SB_INFO(dir_i->i_sb); |
187 | 187 | ||
188 | D1(printk(KERN_DEBUG "jffs2_create()\n")); | 188 | D1(printk(KERN_DEBUG "jffs2_create()\n")); |
@@ -203,7 +203,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
203 | f = JFFS2_INODE_INFO(inode); | 203 | f = JFFS2_INODE_INFO(inode); |
204 | dir_f = JFFS2_INODE_INFO(dir_i); | 204 | dir_f = JFFS2_INODE_INFO(dir_i); |
205 | 205 | ||
206 | ret = jffs2_do_create(c, dir_f, f, ri, | 206 | ret = jffs2_do_create(c, dir_f, f, ri, |
207 | dentry->d_name.name, dentry->d_name.len); | 207 | dentry->d_name.name, dentry->d_name.len); |
208 | 208 | ||
209 | if (ret) { | 209 | if (ret) { |
@@ -232,11 +232,14 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) | |||
232 | struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); | 232 | struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); |
233 | struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode); | 233 | struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode); |
234 | int ret; | 234 | int ret; |
235 | uint32_t now = get_seconds(); | ||
235 | 236 | ||
236 | ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, | 237 | ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, |
237 | dentry->d_name.len, dead_f); | 238 | dentry->d_name.len, dead_f, now); |
238 | if (dead_f->inocache) | 239 | if (dead_f->inocache) |
239 | dentry->d_inode->i_nlink = dead_f->inocache->nlink; | 240 | dentry->d_inode->i_nlink = dead_f->inocache->nlink; |
241 | if (!ret) | ||
242 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); | ||
240 | return ret; | 243 | return ret; |
241 | } | 244 | } |
242 | /***********************************************************************/ | 245 | /***********************************************************************/ |
@@ -249,6 +252,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de | |||
249 | struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); | 252 | struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); |
250 | int ret; | 253 | int ret; |
251 | uint8_t type; | 254 | uint8_t type; |
255 | uint32_t now; | ||
252 | 256 | ||
253 | /* Don't let people make hard links to bad inodes. */ | 257 | /* Don't let people make hard links to bad inodes. */ |
254 | if (!f->inocache) | 258 | if (!f->inocache) |
@@ -261,13 +265,15 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de | |||
261 | type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; | 265 | type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; |
262 | if (!type) type = DT_REG; | 266 | if (!type) type = DT_REG; |
263 | 267 | ||
264 | ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len); | 268 | now = get_seconds(); |
269 | ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); | ||
265 | 270 | ||
266 | if (!ret) { | 271 | if (!ret) { |
267 | down(&f->sem); | 272 | down(&f->sem); |
268 | old_dentry->d_inode->i_nlink = ++f->inocache->nlink; | 273 | old_dentry->d_inode->i_nlink = ++f->inocache->nlink; |
269 | up(&f->sem); | 274 | up(&f->sem); |
270 | d_instantiate(dentry, old_dentry->d_inode); | 275 | d_instantiate(dentry, old_dentry->d_inode); |
276 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); | ||
271 | atomic_inc(&old_dentry->d_inode->i_count); | 277 | atomic_inc(&old_dentry->d_inode->i_count); |
272 | } | 278 | } |
273 | return ret; | 279 | return ret; |
@@ -297,14 +303,15 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
297 | 303 | ||
298 | if (!ri) | 304 | if (!ri) |
299 | return -ENOMEM; | 305 | return -ENOMEM; |
300 | 306 | ||
301 | c = JFFS2_SB_INFO(dir_i->i_sb); | 307 | c = JFFS2_SB_INFO(dir_i->i_sb); |
302 | 308 | ||
303 | /* Try to reserve enough space for both node and dirent. | 309 | /* Try to reserve enough space for both node and dirent. |
304 | * Just the node will do for now, though | 310 | * Just the node will do for now, though |
305 | */ | 311 | */ |
306 | namelen = dentry->d_name.len; | 312 | namelen = dentry->d_name.len; |
307 | ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); | 313 | ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, |
314 | ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); | ||
308 | 315 | ||
309 | if (ret) { | 316 | if (ret) { |
310 | jffs2_free_raw_inode(ri); | 317 | jffs2_free_raw_inode(ri); |
@@ -331,7 +338,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
331 | ri->compr = JFFS2_COMPR_NONE; | 338 | ri->compr = JFFS2_COMPR_NONE; |
332 | ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); | 339 | ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); |
333 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 340 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
334 | 341 | ||
335 | fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); | 342 | fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); |
336 | 343 | ||
337 | jffs2_free_raw_inode(ri); | 344 | jffs2_free_raw_inode(ri); |
@@ -344,9 +351,9 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
344 | return PTR_ERR(fn); | 351 | return PTR_ERR(fn); |
345 | } | 352 | } |
346 | 353 | ||
347 | /* We use f->dents field to store the target path. */ | 354 | /* We use f->target field to store the target path. */ |
348 | f->dents = kmalloc(targetlen + 1, GFP_KERNEL); | 355 | f->target = kmalloc(targetlen + 1, GFP_KERNEL); |
349 | if (!f->dents) { | 356 | if (!f->target) { |
350 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); | 357 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); |
351 | up(&f->sem); | 358 | up(&f->sem); |
352 | jffs2_complete_reservation(c); | 359 | jffs2_complete_reservation(c); |
@@ -354,17 +361,18 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
354 | return -ENOMEM; | 361 | return -ENOMEM; |
355 | } | 362 | } |
356 | 363 | ||
357 | memcpy(f->dents, target, targetlen + 1); | 364 | memcpy(f->target, target, targetlen + 1); |
358 | D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents)); | 365 | D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target)); |
359 | 366 | ||
360 | /* No data here. Only a metadata node, which will be | 367 | /* No data here. Only a metadata node, which will be |
361 | obsoleted by the first data write | 368 | obsoleted by the first data write |
362 | */ | 369 | */ |
363 | f->metadata = fn; | 370 | f->metadata = fn; |
364 | up(&f->sem); | 371 | up(&f->sem); |
365 | 372 | ||
366 | jffs2_complete_reservation(c); | 373 | jffs2_complete_reservation(c); |
367 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); | 374 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, |
375 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | ||
368 | if (ret) { | 376 | if (ret) { |
369 | /* Eep. */ | 377 | /* Eep. */ |
370 | jffs2_clear_inode(inode); | 378 | jffs2_clear_inode(inode); |
@@ -399,7 +407,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
399 | fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); | 407 | fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); |
400 | 408 | ||
401 | if (IS_ERR(fd)) { | 409 | if (IS_ERR(fd)) { |
402 | /* dirent failed to write. Delete the inode normally | 410 | /* dirent failed to write. Delete the inode normally |
403 | as if it were the final unlink() */ | 411 | as if it were the final unlink() */ |
404 | jffs2_complete_reservation(c); | 412 | jffs2_complete_reservation(c); |
405 | jffs2_free_raw_dirent(rd); | 413 | jffs2_free_raw_dirent(rd); |
@@ -442,14 +450,15 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
442 | ri = jffs2_alloc_raw_inode(); | 450 | ri = jffs2_alloc_raw_inode(); |
443 | if (!ri) | 451 | if (!ri) |
444 | return -ENOMEM; | 452 | return -ENOMEM; |
445 | 453 | ||
446 | c = JFFS2_SB_INFO(dir_i->i_sb); | 454 | c = JFFS2_SB_INFO(dir_i->i_sb); |
447 | 455 | ||
448 | /* Try to reserve enough space for both node and dirent. | 456 | /* Try to reserve enough space for both node and dirent. |
449 | * Just the node will do for now, though | 457 | * Just the node will do for now, though |
450 | */ | 458 | */ |
451 | namelen = dentry->d_name.len; | 459 | namelen = dentry->d_name.len; |
452 | ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); | 460 | ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL, |
461 | JFFS2_SUMMARY_INODE_SIZE); | ||
453 | 462 | ||
454 | if (ret) { | 463 | if (ret) { |
455 | jffs2_free_raw_inode(ri); | 464 | jffs2_free_raw_inode(ri); |
@@ -473,7 +482,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
473 | 482 | ||
474 | ri->data_crc = cpu_to_je32(0); | 483 | ri->data_crc = cpu_to_je32(0); |
475 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 484 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
476 | 485 | ||
477 | fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); | 486 | fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); |
478 | 487 | ||
479 | jffs2_free_raw_inode(ri); | 488 | jffs2_free_raw_inode(ri); |
@@ -485,20 +494,21 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
485 | jffs2_clear_inode(inode); | 494 | jffs2_clear_inode(inode); |
486 | return PTR_ERR(fn); | 495 | return PTR_ERR(fn); |
487 | } | 496 | } |
488 | /* No data here. Only a metadata node, which will be | 497 | /* No data here. Only a metadata node, which will be |
489 | obsoleted by the first data write | 498 | obsoleted by the first data write |
490 | */ | 499 | */ |
491 | f->metadata = fn; | 500 | f->metadata = fn; |
492 | up(&f->sem); | 501 | up(&f->sem); |
493 | 502 | ||
494 | jffs2_complete_reservation(c); | 503 | jffs2_complete_reservation(c); |
495 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); | 504 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, |
505 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | ||
496 | if (ret) { | 506 | if (ret) { |
497 | /* Eep. */ | 507 | /* Eep. */ |
498 | jffs2_clear_inode(inode); | 508 | jffs2_clear_inode(inode); |
499 | return ret; | 509 | return ret; |
500 | } | 510 | } |
501 | 511 | ||
502 | rd = jffs2_alloc_raw_dirent(); | 512 | rd = jffs2_alloc_raw_dirent(); |
503 | if (!rd) { | 513 | if (!rd) { |
504 | /* Argh. Now we treat it like a normal delete */ | 514 | /* Argh. Now we treat it like a normal delete */ |
@@ -525,9 +535,9 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
525 | rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); | 535 | rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); |
526 | 536 | ||
527 | fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); | 537 | fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); |
528 | 538 | ||
529 | if (IS_ERR(fd)) { | 539 | if (IS_ERR(fd)) { |
530 | /* dirent failed to write. Delete the inode normally | 540 | /* dirent failed to write. Delete the inode normally |
531 | as if it were the final unlink() */ | 541 | as if it were the final unlink() */ |
532 | jffs2_complete_reservation(c); | 542 | jffs2_complete_reservation(c); |
533 | jffs2_free_raw_dirent(rd); | 543 | jffs2_free_raw_dirent(rd); |
@@ -589,19 +599,20 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
589 | ri = jffs2_alloc_raw_inode(); | 599 | ri = jffs2_alloc_raw_inode(); |
590 | if (!ri) | 600 | if (!ri) |
591 | return -ENOMEM; | 601 | return -ENOMEM; |
592 | 602 | ||
593 | c = JFFS2_SB_INFO(dir_i->i_sb); | 603 | c = JFFS2_SB_INFO(dir_i->i_sb); |
594 | 604 | ||
595 | if (S_ISBLK(mode) || S_ISCHR(mode)) { | 605 | if (S_ISBLK(mode) || S_ISCHR(mode)) { |
596 | dev = cpu_to_je16(old_encode_dev(rdev)); | 606 | dev = cpu_to_je16(old_encode_dev(rdev)); |
597 | devlen = sizeof(dev); | 607 | devlen = sizeof(dev); |
598 | } | 608 | } |
599 | 609 | ||
600 | /* Try to reserve enough space for both node and dirent. | 610 | /* Try to reserve enough space for both node and dirent. |
601 | * Just the node will do for now, though | 611 | * Just the node will do for now, though |
602 | */ | 612 | */ |
603 | namelen = dentry->d_name.len; | 613 | namelen = dentry->d_name.len; |
604 | ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL); | 614 | ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, |
615 | ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); | ||
605 | 616 | ||
606 | if (ret) { | 617 | if (ret) { |
607 | jffs2_free_raw_inode(ri); | 618 | jffs2_free_raw_inode(ri); |
@@ -627,7 +638,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
627 | ri->compr = JFFS2_COMPR_NONE; | 638 | ri->compr = JFFS2_COMPR_NONE; |
628 | ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); | 639 | ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); |
629 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 640 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
630 | 641 | ||
631 | fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL); | 642 | fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL); |
632 | 643 | ||
633 | jffs2_free_raw_inode(ri); | 644 | jffs2_free_raw_inode(ri); |
@@ -639,14 +650,15 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
639 | jffs2_clear_inode(inode); | 650 | jffs2_clear_inode(inode); |
640 | return PTR_ERR(fn); | 651 | return PTR_ERR(fn); |
641 | } | 652 | } |
642 | /* No data here. Only a metadata node, which will be | 653 | /* No data here. Only a metadata node, which will be |
643 | obsoleted by the first data write | 654 | obsoleted by the first data write |
644 | */ | 655 | */ |
645 | f->metadata = fn; | 656 | f->metadata = fn; |
646 | up(&f->sem); | 657 | up(&f->sem); |
647 | 658 | ||
648 | jffs2_complete_reservation(c); | 659 | jffs2_complete_reservation(c); |
649 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); | 660 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, |
661 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | ||
650 | if (ret) { | 662 | if (ret) { |
651 | /* Eep. */ | 663 | /* Eep. */ |
652 | jffs2_clear_inode(inode); | 664 | jffs2_clear_inode(inode); |
@@ -682,9 +694,9 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
682 | rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); | 694 | rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); |
683 | 695 | ||
684 | fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); | 696 | fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); |
685 | 697 | ||
686 | if (IS_ERR(fd)) { | 698 | if (IS_ERR(fd)) { |
687 | /* dirent failed to write. Delete the inode normally | 699 | /* dirent failed to write. Delete the inode normally |
688 | as if it were the final unlink() */ | 700 | as if it were the final unlink() */ |
689 | jffs2_complete_reservation(c); | 701 | jffs2_complete_reservation(c); |
690 | jffs2_free_raw_dirent(rd); | 702 | jffs2_free_raw_dirent(rd); |
@@ -716,8 +728,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
716 | struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); | 728 | struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); |
717 | struct jffs2_inode_info *victim_f = NULL; | 729 | struct jffs2_inode_info *victim_f = NULL; |
718 | uint8_t type; | 730 | uint8_t type; |
731 | uint32_t now; | ||
719 | 732 | ||
720 | /* The VFS will check for us and prevent trying to rename a | 733 | /* The VFS will check for us and prevent trying to rename a |
721 | * file over a directory and vice versa, but if it's a directory, | 734 | * file over a directory and vice versa, but if it's a directory, |
722 | * the VFS can't check whether the victim is empty. The filesystem | 735 | * the VFS can't check whether the victim is empty. The filesystem |
723 | * needs to do that for itself. | 736 | * needs to do that for itself. |
@@ -739,19 +752,20 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
739 | } | 752 | } |
740 | 753 | ||
741 | /* XXX: We probably ought to alloc enough space for | 754 | /* XXX: We probably ought to alloc enough space for |
742 | both nodes at the same time. Writing the new link, | 755 | both nodes at the same time. Writing the new link, |
743 | then getting -ENOSPC, is quite bad :) | 756 | then getting -ENOSPC, is quite bad :) |
744 | */ | 757 | */ |
745 | 758 | ||
746 | /* Make a hard link */ | 759 | /* Make a hard link */ |
747 | 760 | ||
748 | /* XXX: This is ugly */ | 761 | /* XXX: This is ugly */ |
749 | type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; | 762 | type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; |
750 | if (!type) type = DT_REG; | 763 | if (!type) type = DT_REG; |
751 | 764 | ||
752 | ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), | 765 | now = get_seconds(); |
766 | ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), | ||
753 | old_dentry->d_inode->i_ino, type, | 767 | old_dentry->d_inode->i_ino, type, |
754 | new_dentry->d_name.name, new_dentry->d_name.len); | 768 | new_dentry->d_name.name, new_dentry->d_name.len, now); |
755 | 769 | ||
756 | if (ret) | 770 | if (ret) |
757 | return ret; | 771 | return ret; |
@@ -768,14 +782,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
768 | } | 782 | } |
769 | } | 783 | } |
770 | 784 | ||
771 | /* If it was a directory we moved, and there was no victim, | 785 | /* If it was a directory we moved, and there was no victim, |
772 | increase i_nlink on its new parent */ | 786 | increase i_nlink on its new parent */ |
773 | if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) | 787 | if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) |
774 | new_dir_i->i_nlink++; | 788 | new_dir_i->i_nlink++; |
775 | 789 | ||
776 | /* Unlink the original */ | 790 | /* Unlink the original */ |
777 | ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), | 791 | ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), |
778 | old_dentry->d_name.name, old_dentry->d_name.len, NULL); | 792 | old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); |
779 | 793 | ||
780 | /* We don't touch inode->i_nlink */ | 794 | /* We don't touch inode->i_nlink */ |
781 | 795 | ||
@@ -792,12 +806,15 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
792 | /* Might as well let the VFS know */ | 806 | /* Might as well let the VFS know */ |
793 | d_instantiate(new_dentry, old_dentry->d_inode); | 807 | d_instantiate(new_dentry, old_dentry->d_inode); |
794 | atomic_inc(&old_dentry->d_inode->i_count); | 808 | atomic_inc(&old_dentry->d_inode->i_count); |
809 | new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now); | ||
795 | return ret; | 810 | return ret; |
796 | } | 811 | } |
797 | 812 | ||
798 | if (S_ISDIR(old_dentry->d_inode->i_mode)) | 813 | if (S_ISDIR(old_dentry->d_inode->i_mode)) |
799 | old_dir_i->i_nlink--; | 814 | old_dir_i->i_nlink--; |
800 | 815 | ||
816 | new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); | ||
817 | |||
801 | return 0; | 818 | return 0; |
802 | } | 819 | } |
803 | 820 | ||
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 787d84ac2bcd..dad68fdffe9e 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: erase.c,v 1.80 2005/07/14 19:46:24 joern Exp $ | 10 | * $Id: erase.c,v 1.85 2005/09/20 14:53:15 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -24,7 +24,7 @@ struct erase_priv_struct { | |||
24 | struct jffs2_eraseblock *jeb; | 24 | struct jffs2_eraseblock *jeb; |
25 | struct jffs2_sb_info *c; | 25 | struct jffs2_sb_info *c; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | #ifndef __ECOS | 28 | #ifndef __ECOS |
29 | static void jffs2_erase_callback(struct erase_info *); | 29 | static void jffs2_erase_callback(struct erase_info *); |
30 | #endif | 30 | #endif |
@@ -48,7 +48,8 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
48 | #else /* Linux */ | 48 | #else /* Linux */ |
49 | struct erase_info *instr; | 49 | struct erase_info *instr; |
50 | 50 | ||
51 | D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size)); | 51 | D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#08x (range %#08x-%#08x)\n", |
52 | jeb->offset, jeb->offset, jeb->offset + c->sector_size)); | ||
52 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); | 53 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); |
53 | if (!instr) { | 54 | if (!instr) { |
54 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); | 55 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); |
@@ -70,7 +71,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
70 | instr->callback = jffs2_erase_callback; | 71 | instr->callback = jffs2_erase_callback; |
71 | instr->priv = (unsigned long)(&instr[1]); | 72 | instr->priv = (unsigned long)(&instr[1]); |
72 | instr->fail_addr = 0xffffffff; | 73 | instr->fail_addr = 0xffffffff; |
73 | 74 | ||
74 | ((struct erase_priv_struct *)instr->priv)->jeb = jeb; | 75 | ((struct erase_priv_struct *)instr->priv)->jeb = jeb; |
75 | ((struct erase_priv_struct *)instr->priv)->c = c; | 76 | ((struct erase_priv_struct *)instr->priv)->c = c; |
76 | 77 | ||
@@ -95,7 +96,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
95 | return; | 96 | return; |
96 | } | 97 | } |
97 | 98 | ||
98 | if (ret == -EROFS) | 99 | if (ret == -EROFS) |
99 | printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset); | 100 | printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset); |
100 | else | 101 | else |
101 | printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); | 102 | printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); |
@@ -196,7 +197,7 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
196 | c->nr_erasing_blocks--; | 197 | c->nr_erasing_blocks--; |
197 | spin_unlock(&c->erase_completion_lock); | 198 | spin_unlock(&c->erase_completion_lock); |
198 | wake_up(&c->erase_wait); | 199 | wake_up(&c->erase_wait); |
199 | } | 200 | } |
200 | 201 | ||
201 | #ifndef __ECOS | 202 | #ifndef __ECOS |
202 | static void jffs2_erase_callback(struct erase_info *instr) | 203 | static void jffs2_erase_callback(struct erase_info *instr) |
@@ -208,7 +209,7 @@ static void jffs2_erase_callback(struct erase_info *instr) | |||
208 | jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr); | 209 | jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr); |
209 | } else { | 210 | } else { |
210 | jffs2_erase_succeeded(priv->c, priv->jeb); | 211 | jffs2_erase_succeeded(priv->c, priv->jeb); |
211 | } | 212 | } |
212 | kfree(instr); | 213 | kfree(instr); |
213 | } | 214 | } |
214 | #endif /* !__ECOS */ | 215 | #endif /* !__ECOS */ |
@@ -226,13 +227,13 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
226 | /* Walk the inode's list once, removing any nodes from this eraseblock */ | 227 | /* Walk the inode's list once, removing any nodes from this eraseblock */ |
227 | while (1) { | 228 | while (1) { |
228 | if (!(*prev)->next_in_ino) { | 229 | if (!(*prev)->next_in_ino) { |
229 | /* We're looking at the jffs2_inode_cache, which is | 230 | /* We're looking at the jffs2_inode_cache, which is |
230 | at the end of the linked list. Stash it and continue | 231 | at the end of the linked list. Stash it and continue |
231 | from the beginning of the list */ | 232 | from the beginning of the list */ |
232 | ic = (struct jffs2_inode_cache *)(*prev); | 233 | ic = (struct jffs2_inode_cache *)(*prev); |
233 | prev = &ic->nodes; | 234 | prev = &ic->nodes; |
234 | continue; | 235 | continue; |
235 | } | 236 | } |
236 | 237 | ||
237 | if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) { | 238 | if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) { |
238 | /* It's in the block we're erasing */ | 239 | /* It's in the block we're erasing */ |
@@ -266,7 +267,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
266 | printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG); | 267 | printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG); |
267 | 268 | ||
268 | this = ic->nodes; | 269 | this = ic->nodes; |
269 | 270 | ||
270 | while(this) { | 271 | while(this) { |
271 | printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this)); | 272 | printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this)); |
272 | if (++i == 5) { | 273 | if (++i == 5) { |
@@ -289,7 +290,7 @@ static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_erase | |||
289 | while(jeb->first_node) { | 290 | while(jeb->first_node) { |
290 | ref = jeb->first_node; | 291 | ref = jeb->first_node; |
291 | jeb->first_node = ref->next_phys; | 292 | jeb->first_node = ref->next_phys; |
292 | 293 | ||
293 | /* Remove from the inode-list */ | 294 | /* Remove from the inode-list */ |
294 | if (ref->next_in_ino) | 295 | if (ref->next_in_ino) |
295 | jffs2_remove_node_refs_from_ino_list(c, ref, jeb); | 296 | jffs2_remove_node_refs_from_ino_list(c, ref, jeb); |
@@ -306,7 +307,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
306 | uint32_t ofs; | 307 | uint32_t ofs; |
307 | size_t retlen; | 308 | size_t retlen; |
308 | int ret = -EIO; | 309 | int ret = -EIO; |
309 | 310 | ||
310 | ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 311 | ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
311 | if (!ebuf) { | 312 | if (!ebuf) { |
312 | printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset); | 313 | printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset); |
@@ -360,7 +361,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
360 | case -EIO: goto filebad; | 361 | case -EIO: goto filebad; |
361 | } | 362 | } |
362 | 363 | ||
363 | /* Write the erase complete marker */ | 364 | /* Write the erase complete marker */ |
364 | D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset)); | 365 | D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset)); |
365 | bad_offset = jeb->offset; | 366 | bad_offset = jeb->offset; |
366 | 367 | ||
@@ -398,7 +399,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
398 | vecs[0].iov_base = (unsigned char *) ▮ | 399 | vecs[0].iov_base = (unsigned char *) ▮ |
399 | vecs[0].iov_len = sizeof(marker); | 400 | vecs[0].iov_len = sizeof(marker); |
400 | ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen); | 401 | ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen); |
401 | 402 | ||
402 | if (ret || retlen != sizeof(marker)) { | 403 | if (ret || retlen != sizeof(marker)) { |
403 | if (ret) | 404 | if (ret) |
404 | printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n", | 405 | printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n", |
@@ -415,9 +416,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
415 | marker_ref->next_phys = NULL; | 416 | marker_ref->next_phys = NULL; |
416 | marker_ref->flash_offset = jeb->offset | REF_NORMAL; | 417 | marker_ref->flash_offset = jeb->offset | REF_NORMAL; |
417 | marker_ref->__totlen = c->cleanmarker_size; | 418 | marker_ref->__totlen = c->cleanmarker_size; |
418 | 419 | ||
419 | jeb->first_node = jeb->last_node = marker_ref; | 420 | jeb->first_node = jeb->last_node = marker_ref; |
420 | 421 | ||
421 | jeb->free_size = c->sector_size - c->cleanmarker_size; | 422 | jeb->free_size = c->sector_size - c->cleanmarker_size; |
422 | jeb->used_size = c->cleanmarker_size; | 423 | jeb->used_size = c->cleanmarker_size; |
423 | jeb->dirty_size = 0; | 424 | jeb->dirty_size = 0; |
@@ -429,8 +430,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
429 | c->free_size += jeb->free_size; | 430 | c->free_size += jeb->free_size; |
430 | c->used_size += jeb->used_size; | 431 | c->used_size += jeb->used_size; |
431 | 432 | ||
432 | ACCT_SANITY_CHECK(c,jeb); | 433 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); |
433 | D1(ACCT_PARANOIA_CHECK(jeb)); | 434 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
434 | 435 | ||
435 | list_add_tail(&jeb->list, &c->free_list); | 436 | list_add_tail(&jeb->list, &c->free_list); |
436 | c->nr_erasing_blocks--; | 437 | c->nr_erasing_blocks--; |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 8279bf0133ff..935f273dc57b 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $ | 10 | * $Id: file.c,v 1.104 2005/10/18 23:29:35 tpoynor Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -34,8 +34,8 @@ int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync) | |||
34 | 34 | ||
35 | /* Trigger GC to flush any pending writes for this inode */ | 35 | /* Trigger GC to flush any pending writes for this inode */ |
36 | jffs2_flush_wbuf_gc(c, inode->i_ino); | 36 | jffs2_flush_wbuf_gc(c, inode->i_ino); |
37 | 37 | ||
38 | return 0; | 38 | return 0; |
39 | } | 39 | } |
40 | 40 | ||
41 | struct file_operations jffs2_file_operations = | 41 | struct file_operations jffs2_file_operations = |
@@ -107,7 +107,7 @@ static int jffs2_readpage (struct file *filp, struct page *pg) | |||
107 | { | 107 | { |
108 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); | 108 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); |
109 | int ret; | 109 | int ret; |
110 | 110 | ||
111 | down(&f->sem); | 111 | down(&f->sem); |
112 | ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); | 112 | ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); |
113 | up(&f->sem); | 113 | up(&f->sem); |
@@ -130,11 +130,12 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, | |||
130 | struct jffs2_raw_inode ri; | 130 | struct jffs2_raw_inode ri; |
131 | struct jffs2_full_dnode *fn; | 131 | struct jffs2_full_dnode *fn; |
132 | uint32_t phys_ofs, alloc_len; | 132 | uint32_t phys_ofs, alloc_len; |
133 | 133 | ||
134 | D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", | 134 | D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", |
135 | (unsigned int)inode->i_size, pageofs)); | 135 | (unsigned int)inode->i_size, pageofs)); |
136 | 136 | ||
137 | ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); | 137 | ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, |
138 | ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); | ||
138 | if (ret) | 139 | if (ret) |
139 | return ret; | 140 | return ret; |
140 | 141 | ||
@@ -159,7 +160,7 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, | |||
159 | ri.compr = JFFS2_COMPR_ZERO; | 160 | ri.compr = JFFS2_COMPR_ZERO; |
160 | ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); | 161 | ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); |
161 | ri.data_crc = cpu_to_je32(0); | 162 | ri.data_crc = cpu_to_je32(0); |
162 | 163 | ||
163 | fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL); | 164 | fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL); |
164 | 165 | ||
165 | if (IS_ERR(fn)) { | 166 | if (IS_ERR(fn)) { |
@@ -186,7 +187,7 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, | |||
186 | inode->i_size = pageofs; | 187 | inode->i_size = pageofs; |
187 | up(&f->sem); | 188 | up(&f->sem); |
188 | } | 189 | } |
189 | 190 | ||
190 | /* Read in the page if it wasn't already present, unless it's a whole page */ | 191 | /* Read in the page if it wasn't already present, unless it's a whole page */ |
191 | if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { | 192 | if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { |
192 | down(&f->sem); | 193 | down(&f->sem); |
@@ -217,7 +218,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, | |||
217 | if (!start && end == PAGE_CACHE_SIZE) { | 218 | if (!start && end == PAGE_CACHE_SIZE) { |
218 | /* We need to avoid deadlock with page_cache_read() in | 219 | /* We need to avoid deadlock with page_cache_read() in |
219 | jffs2_garbage_collect_pass(). So we have to mark the | 220 | jffs2_garbage_collect_pass(). So we have to mark the |
220 | page up to date, to prevent page_cache_read() from | 221 | page up to date, to prevent page_cache_read() from |
221 | trying to re-lock it. */ | 222 | trying to re-lock it. */ |
222 | SetPageUptodate(pg); | 223 | SetPageUptodate(pg); |
223 | } | 224 | } |
@@ -251,7 +252,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, | |||
251 | /* There was an error writing. */ | 252 | /* There was an error writing. */ |
252 | SetPageError(pg); | 253 | SetPageError(pg); |
253 | } | 254 | } |
254 | 255 | ||
255 | /* Adjust writtenlen for the padding we did, so we don't confuse our caller */ | 256 | /* Adjust writtenlen for the padding we did, so we don't confuse our caller */ |
256 | if (writtenlen < (start&3)) | 257 | if (writtenlen < (start&3)) |
257 | writtenlen = 0; | 258 | writtenlen = 0; |
@@ -262,7 +263,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, | |||
262 | if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) { | 263 | if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) { |
263 | inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; | 264 | inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; |
264 | inode->i_blocks = (inode->i_size + 511) >> 9; | 265 | inode->i_blocks = (inode->i_size + 511) >> 9; |
265 | 266 | ||
266 | inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); | 267 | inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); |
267 | } | 268 | } |
268 | } | 269 | } |
@@ -271,13 +272,13 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, | |||
271 | 272 | ||
272 | if (start+writtenlen < end) { | 273 | if (start+writtenlen < end) { |
273 | /* generic_file_write has written more to the page cache than we've | 274 | /* generic_file_write has written more to the page cache than we've |
274 | actually written to the medium. Mark the page !Uptodate so that | 275 | actually written to the medium. Mark the page !Uptodate so that |
275 | it gets reread */ | 276 | it gets reread */ |
276 | D1(printk(KERN_DEBUG "jffs2_commit_write(): Not all bytes written. Marking page !uptodate\n")); | 277 | D1(printk(KERN_DEBUG "jffs2_commit_write(): Not all bytes written. Marking page !uptodate\n")); |
277 | SetPageError(pg); | 278 | SetPageError(pg); |
278 | ClearPageUptodate(pg); | 279 | ClearPageUptodate(pg); |
279 | } | 280 | } |
280 | 281 | ||
281 | D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret)); | 282 | D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",start+writtenlen==end?0:ret)); |
282 | return writtenlen?writtenlen:ret; | 283 | return start+writtenlen==end?0:ret; |
283 | } | 284 | } |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 5687c3f42002..543420665c5b 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: fs.c,v 1.56 2005/07/06 12:13:09 dwmw2 Exp $ | 10 | * $Id: fs.c,v 1.66 2005/09/27 13:17:29 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -40,7 +40,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
40 | int ret; | 40 | int ret; |
41 | D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); | 41 | D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); |
42 | ret = inode_change_ok(inode, iattr); | 42 | ret = inode_change_ok(inode, iattr); |
43 | if (ret) | 43 | if (ret) |
44 | return ret; | 44 | return ret; |
45 | 45 | ||
46 | /* Special cases - we don't want more than one data node | 46 | /* Special cases - we don't want more than one data node |
@@ -73,8 +73,9 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
73 | kfree(mdata); | 73 | kfree(mdata); |
74 | return -ENOMEM; | 74 | return -ENOMEM; |
75 | } | 75 | } |
76 | 76 | ||
77 | ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL); | 77 | ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, |
78 | ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); | ||
78 | if (ret) { | 79 | if (ret) { |
79 | jffs2_free_raw_inode(ri); | 80 | jffs2_free_raw_inode(ri); |
80 | if (S_ISLNK(inode->i_mode & S_IFMT)) | 81 | if (S_ISLNK(inode->i_mode & S_IFMT)) |
@@ -83,7 +84,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
83 | } | 84 | } |
84 | down(&f->sem); | 85 | down(&f->sem); |
85 | ivalid = iattr->ia_valid; | 86 | ivalid = iattr->ia_valid; |
86 | 87 | ||
87 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 88 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
88 | ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); | 89 | ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); |
89 | ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); | 90 | ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); |
@@ -99,7 +100,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
99 | if (iattr->ia_mode & S_ISGID && | 100 | if (iattr->ia_mode & S_ISGID && |
100 | !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID)) | 101 | !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID)) |
101 | ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID); | 102 | ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID); |
102 | else | 103 | else |
103 | ri->mode = cpu_to_jemode(iattr->ia_mode); | 104 | ri->mode = cpu_to_jemode(iattr->ia_mode); |
104 | else | 105 | else |
105 | ri->mode = cpu_to_jemode(inode->i_mode); | 106 | ri->mode = cpu_to_jemode(inode->i_mode); |
@@ -128,7 +129,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
128 | new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL); | 129 | new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL); |
129 | if (S_ISLNK(inode->i_mode)) | 130 | if (S_ISLNK(inode->i_mode)) |
130 | kfree(mdata); | 131 | kfree(mdata); |
131 | 132 | ||
132 | if (IS_ERR(new_metadata)) { | 133 | if (IS_ERR(new_metadata)) { |
133 | jffs2_complete_reservation(c); | 134 | jffs2_complete_reservation(c); |
134 | jffs2_free_raw_inode(ri); | 135 | jffs2_free_raw_inode(ri); |
@@ -147,7 +148,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
147 | old_metadata = f->metadata; | 148 | old_metadata = f->metadata; |
148 | 149 | ||
149 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) | 150 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) |
150 | jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size); | 151 | jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size); |
151 | 152 | ||
152 | if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { | 153 | if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { |
153 | jffs2_add_full_dnode_to_inode(c, f, new_metadata); | 154 | jffs2_add_full_dnode_to_inode(c, f, new_metadata); |
@@ -166,7 +167,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
166 | jffs2_complete_reservation(c); | 167 | jffs2_complete_reservation(c); |
167 | 168 | ||
168 | /* We have to do the vmtruncate() without f->sem held, since | 169 | /* We have to do the vmtruncate() without f->sem held, since |
169 | some pages may be locked and waiting for it in readpage(). | 170 | some pages may be locked and waiting for it in readpage(). |
170 | We are protected from a simultaneous write() extending i_size | 171 | We are protected from a simultaneous write() extending i_size |
171 | back past iattr->ia_size, because do_truncate() holds the | 172 | back past iattr->ia_size, because do_truncate() holds the |
172 | generic inode semaphore. */ | 173 | generic inode semaphore. */ |
@@ -194,31 +195,27 @@ int jffs2_statfs(struct super_block *sb, struct kstatfs *buf) | |||
194 | buf->f_namelen = JFFS2_MAX_NAME_LEN; | 195 | buf->f_namelen = JFFS2_MAX_NAME_LEN; |
195 | 196 | ||
196 | spin_lock(&c->erase_completion_lock); | 197 | spin_lock(&c->erase_completion_lock); |
197 | |||
198 | avail = c->dirty_size + c->free_size; | 198 | avail = c->dirty_size + c->free_size; |
199 | if (avail > c->sector_size * c->resv_blocks_write) | 199 | if (avail > c->sector_size * c->resv_blocks_write) |
200 | avail -= c->sector_size * c->resv_blocks_write; | 200 | avail -= c->sector_size * c->resv_blocks_write; |
201 | else | 201 | else |
202 | avail = 0; | 202 | avail = 0; |
203 | spin_unlock(&c->erase_completion_lock); | ||
203 | 204 | ||
204 | buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; | 205 | buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; |
205 | 206 | ||
206 | D2(jffs2_dump_block_lists(c)); | ||
207 | |||
208 | spin_unlock(&c->erase_completion_lock); | ||
209 | |||
210 | return 0; | 207 | return 0; |
211 | } | 208 | } |
212 | 209 | ||
213 | 210 | ||
214 | void jffs2_clear_inode (struct inode *inode) | 211 | void jffs2_clear_inode (struct inode *inode) |
215 | { | 212 | { |
216 | /* We can forget about this inode for now - drop all | 213 | /* We can forget about this inode for now - drop all |
217 | * the nodelists associated with it, etc. | 214 | * the nodelists associated with it, etc. |
218 | */ | 215 | */ |
219 | struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); | 216 | struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); |
220 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | 217 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); |
221 | 218 | ||
222 | D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); | 219 | D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); |
223 | 220 | ||
224 | jffs2_do_clear_inode(c, f); | 221 | jffs2_do_clear_inode(c, f); |
@@ -237,7 +234,7 @@ void jffs2_read_inode (struct inode *inode) | |||
237 | c = JFFS2_SB_INFO(inode->i_sb); | 234 | c = JFFS2_SB_INFO(inode->i_sb); |
238 | 235 | ||
239 | jffs2_init_inode_info(f); | 236 | jffs2_init_inode_info(f); |
240 | 237 | ||
241 | ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); | 238 | ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); |
242 | 239 | ||
243 | if (ret) { | 240 | if (ret) { |
@@ -257,14 +254,14 @@ void jffs2_read_inode (struct inode *inode) | |||
257 | 254 | ||
258 | inode->i_blksize = PAGE_SIZE; | 255 | inode->i_blksize = PAGE_SIZE; |
259 | inode->i_blocks = (inode->i_size + 511) >> 9; | 256 | inode->i_blocks = (inode->i_size + 511) >> 9; |
260 | 257 | ||
261 | switch (inode->i_mode & S_IFMT) { | 258 | switch (inode->i_mode & S_IFMT) { |
262 | jint16_t rdev; | 259 | jint16_t rdev; |
263 | 260 | ||
264 | case S_IFLNK: | 261 | case S_IFLNK: |
265 | inode->i_op = &jffs2_symlink_inode_operations; | 262 | inode->i_op = &jffs2_symlink_inode_operations; |
266 | break; | 263 | break; |
267 | 264 | ||
268 | case S_IFDIR: | 265 | case S_IFDIR: |
269 | { | 266 | { |
270 | struct jffs2_full_dirent *fd; | 267 | struct jffs2_full_dirent *fd; |
@@ -301,7 +298,7 @@ void jffs2_read_inode (struct inode *inode) | |||
301 | jffs2_do_clear_inode(c, f); | 298 | jffs2_do_clear_inode(c, f); |
302 | make_bad_inode(inode); | 299 | make_bad_inode(inode); |
303 | return; | 300 | return; |
304 | } | 301 | } |
305 | 302 | ||
306 | case S_IFSOCK: | 303 | case S_IFSOCK: |
307 | case S_IFIFO: | 304 | case S_IFIFO: |
@@ -357,11 +354,11 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) | |||
357 | down(&c->alloc_sem); | 354 | down(&c->alloc_sem); |
358 | jffs2_flush_wbuf_pad(c); | 355 | jffs2_flush_wbuf_pad(c); |
359 | up(&c->alloc_sem); | 356 | up(&c->alloc_sem); |
360 | } | 357 | } |
361 | 358 | ||
362 | if (!(*flags & MS_RDONLY)) | 359 | if (!(*flags & MS_RDONLY)) |
363 | jffs2_start_garbage_collect_thread(c); | 360 | jffs2_start_garbage_collect_thread(c); |
364 | 361 | ||
365 | *flags |= MS_NOATIME; | 362 | *flags |= MS_NOATIME; |
366 | 363 | ||
367 | return 0; | 364 | return 0; |
@@ -395,9 +392,9 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i | |||
395 | D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode)); | 392 | D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode)); |
396 | 393 | ||
397 | c = JFFS2_SB_INFO(sb); | 394 | c = JFFS2_SB_INFO(sb); |
398 | 395 | ||
399 | inode = new_inode(sb); | 396 | inode = new_inode(sb); |
400 | 397 | ||
401 | if (!inode) | 398 | if (!inode) |
402 | return ERR_PTR(-ENOMEM); | 399 | return ERR_PTR(-ENOMEM); |
403 | 400 | ||
@@ -461,40 +458,24 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
461 | #endif | 458 | #endif |
462 | 459 | ||
463 | c->flash_size = c->mtd->size; | 460 | c->flash_size = c->mtd->size; |
464 | 461 | c->sector_size = c->mtd->erasesize; | |
465 | /* | ||
466 | * Check, if we have to concatenate physical blocks to larger virtual blocks | ||
467 | * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation) | ||
468 | */ | ||
469 | c->sector_size = c->mtd->erasesize; | ||
470 | blocks = c->flash_size / c->sector_size; | 462 | blocks = c->flash_size / c->sector_size; |
471 | if (!(c->mtd->flags & MTD_NO_VIRTBLOCKS)) { | ||
472 | while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) { | ||
473 | blocks >>= 1; | ||
474 | c->sector_size <<= 1; | ||
475 | } | ||
476 | } | ||
477 | 463 | ||
478 | /* | 464 | /* |
479 | * Size alignment check | 465 | * Size alignment check |
480 | */ | 466 | */ |
481 | if ((c->sector_size * blocks) != c->flash_size) { | 467 | if ((c->sector_size * blocks) != c->flash_size) { |
482 | c->flash_size = c->sector_size * blocks; | 468 | c->flash_size = c->sector_size * blocks; |
483 | printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n", | 469 | printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n", |
484 | c->flash_size / 1024); | 470 | c->flash_size / 1024); |
485 | } | 471 | } |
486 | 472 | ||
487 | if (c->sector_size != c->mtd->erasesize) | ||
488 | printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", | ||
489 | c->mtd->erasesize / 1024, c->sector_size / 1024); | ||
490 | |||
491 | if (c->flash_size < 5*c->sector_size) { | 473 | if (c->flash_size < 5*c->sector_size) { |
492 | printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size); | 474 | printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size); |
493 | return -EINVAL; | 475 | return -EINVAL; |
494 | } | 476 | } |
495 | 477 | ||
496 | c->cleanmarker_size = sizeof(struct jffs2_unknown_node); | 478 | c->cleanmarker_size = sizeof(struct jffs2_unknown_node); |
497 | /* Joern -- stick alignment for weird 8-byte-page flash here */ | ||
498 | 479 | ||
499 | /* NAND (or other bizarre) flash... do setup accordingly */ | 480 | /* NAND (or other bizarre) flash... do setup accordingly */ |
500 | ret = jffs2_flash_setup(c); | 481 | ret = jffs2_flash_setup(c); |
@@ -517,7 +498,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
517 | root_i = iget(sb, 1); | 498 | root_i = iget(sb, 1); |
518 | if (is_bad_inode(root_i)) { | 499 | if (is_bad_inode(root_i)) { |
519 | D1(printk(KERN_WARNING "get root inode failed\n")); | 500 | D1(printk(KERN_WARNING "get root inode failed\n")); |
520 | goto out_nodes; | 501 | goto out_root_i; |
521 | } | 502 | } |
522 | 503 | ||
523 | D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n")); | 504 | D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n")); |
@@ -535,10 +516,9 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
535 | 516 | ||
536 | out_root_i: | 517 | out_root_i: |
537 | iput(root_i); | 518 | iput(root_i); |
538 | out_nodes: | ||
539 | jffs2_free_ino_caches(c); | 519 | jffs2_free_ino_caches(c); |
540 | jffs2_free_raw_node_refs(c); | 520 | jffs2_free_raw_node_refs(c); |
541 | if (c->mtd->flags & MTD_NO_VIRTBLOCKS) | 521 | if (jffs2_blocks_use_vmalloc(c)) |
542 | vfree(c->blocks); | 522 | vfree(c->blocks); |
543 | else | 523 | else |
544 | kfree(c->blocks); | 524 | kfree(c->blocks); |
@@ -563,16 +543,16 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, | |||
563 | struct jffs2_inode_cache *ic; | 543 | struct jffs2_inode_cache *ic; |
564 | if (!nlink) { | 544 | if (!nlink) { |
565 | /* The inode has zero nlink but its nodes weren't yet marked | 545 | /* The inode has zero nlink but its nodes weren't yet marked |
566 | obsolete. This has to be because we're still waiting for | 546 | obsolete. This has to be because we're still waiting for |
567 | the final (close() and) iput() to happen. | 547 | the final (close() and) iput() to happen. |
568 | 548 | ||
569 | There's a possibility that the final iput() could have | 549 | There's a possibility that the final iput() could have |
570 | happened while we were contemplating. In order to ensure | 550 | happened while we were contemplating. In order to ensure |
571 | that we don't cause a new read_inode() (which would fail) | 551 | that we don't cause a new read_inode() (which would fail) |
572 | for the inode in question, we use ilookup() in this case | 552 | for the inode in question, we use ilookup() in this case |
573 | instead of iget(). | 553 | instead of iget(). |
574 | 554 | ||
575 | The nlink can't _become_ zero at this point because we're | 555 | The nlink can't _become_ zero at this point because we're |
576 | holding the alloc_sem, and jffs2_do_unlink() would also | 556 | holding the alloc_sem, and jffs2_do_unlink() would also |
577 | need that while decrementing nlink on any inode. | 557 | need that while decrementing nlink on any inode. |
578 | */ | 558 | */ |
@@ -619,19 +599,19 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, | |||
619 | return JFFS2_INODE_INFO(inode); | 599 | return JFFS2_INODE_INFO(inode); |
620 | } | 600 | } |
621 | 601 | ||
622 | unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, | 602 | unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, |
623 | struct jffs2_inode_info *f, | 603 | struct jffs2_inode_info *f, |
624 | unsigned long offset, | 604 | unsigned long offset, |
625 | unsigned long *priv) | 605 | unsigned long *priv) |
626 | { | 606 | { |
627 | struct inode *inode = OFNI_EDONI_2SFFJ(f); | 607 | struct inode *inode = OFNI_EDONI_2SFFJ(f); |
628 | struct page *pg; | 608 | struct page *pg; |
629 | 609 | ||
630 | pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, | 610 | pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, |
631 | (void *)jffs2_do_readpage_unlock, inode); | 611 | (void *)jffs2_do_readpage_unlock, inode); |
632 | if (IS_ERR(pg)) | 612 | if (IS_ERR(pg)) |
633 | return (void *)pg; | 613 | return (void *)pg; |
634 | 614 | ||
635 | *priv = (unsigned long)pg; | 615 | *priv = (unsigned long)pg; |
636 | return kmap(pg); | 616 | return kmap(pg); |
637 | } | 617 | } |
@@ -648,7 +628,7 @@ void jffs2_gc_release_page(struct jffs2_sb_info *c, | |||
648 | 628 | ||
649 | static int jffs2_flash_setup(struct jffs2_sb_info *c) { | 629 | static int jffs2_flash_setup(struct jffs2_sb_info *c) { |
650 | int ret = 0; | 630 | int ret = 0; |
651 | 631 | ||
652 | if (jffs2_cleanmarker_oob(c)) { | 632 | if (jffs2_cleanmarker_oob(c)) { |
653 | /* NAND flash... do setup accordingly */ | 633 | /* NAND flash... do setup accordingly */ |
654 | ret = jffs2_nand_flash_setup(c); | 634 | ret = jffs2_nand_flash_setup(c); |
@@ -662,14 +642,21 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) { | |||
662 | if (ret) | 642 | if (ret) |
663 | return ret; | 643 | return ret; |
664 | } | 644 | } |
665 | 645 | ||
666 | /* and Dataflash */ | 646 | /* and Dataflash */ |
667 | if (jffs2_dataflash(c)) { | 647 | if (jffs2_dataflash(c)) { |
668 | ret = jffs2_dataflash_setup(c); | 648 | ret = jffs2_dataflash_setup(c); |
669 | if (ret) | 649 | if (ret) |
670 | return ret; | 650 | return ret; |
671 | } | 651 | } |
672 | 652 | ||
653 | /* and Intel "Sibley" flash */ | ||
654 | if (jffs2_nor_wbuf_flash(c)) { | ||
655 | ret = jffs2_nor_wbuf_flash_setup(c); | ||
656 | if (ret) | ||
657 | return ret; | ||
658 | } | ||
659 | |||
673 | return ret; | 660 | return ret; |
674 | } | 661 | } |
675 | 662 | ||
@@ -683,9 +670,14 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { | |||
683 | if (jffs2_nor_ecc(c)) { | 670 | if (jffs2_nor_ecc(c)) { |
684 | jffs2_nor_ecc_flash_cleanup(c); | 671 | jffs2_nor_ecc_flash_cleanup(c); |
685 | } | 672 | } |
686 | 673 | ||
687 | /* and DataFlash */ | 674 | /* and DataFlash */ |
688 | if (jffs2_dataflash(c)) { | 675 | if (jffs2_dataflash(c)) { |
689 | jffs2_dataflash_cleanup(c); | 676 | jffs2_dataflash_cleanup(c); |
690 | } | 677 | } |
678 | |||
679 | /* and Intel "Sibley" flash */ | ||
680 | if (jffs2_nor_wbuf_flash(c)) { | ||
681 | jffs2_nor_wbuf_flash_cleanup(c); | ||
682 | } | ||
691 | } | 683 | } |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 7086cd634503..f9ffece453a3 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $ | 10 | * $Id: gc.c,v 1.155 2005/11/07 11:14:39 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -21,14 +21,14 @@ | |||
21 | #include "nodelist.h" | 21 | #include "nodelist.h" |
22 | #include "compr.h" | 22 | #include "compr.h" |
23 | 23 | ||
24 | static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | 24 | static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, |
25 | struct jffs2_inode_cache *ic, | 25 | struct jffs2_inode_cache *ic, |
26 | struct jffs2_raw_node_ref *raw); | 26 | struct jffs2_raw_node_ref *raw); |
27 | static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 27 | static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
28 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); | 28 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); |
29 | static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 29 | static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
30 | struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); | 30 | struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); |
31 | static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 31 | static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
32 | struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); | 32 | struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); |
33 | static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 33 | static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
34 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, | 34 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, |
@@ -55,7 +55,7 @@ again: | |||
55 | D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); | 55 | D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); |
56 | nextlist = &c->bad_used_list; | 56 | nextlist = &c->bad_used_list; |
57 | } else if (n < 50 && !list_empty(&c->erasable_list)) { | 57 | } else if (n < 50 && !list_empty(&c->erasable_list)) { |
58 | /* Note that most of them will have gone directly to be erased. | 58 | /* Note that most of them will have gone directly to be erased. |
59 | So don't favour the erasable_list _too_ much. */ | 59 | So don't favour the erasable_list _too_ much. */ |
60 | D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n")); | 60 | D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n")); |
61 | nextlist = &c->erasable_list; | 61 | nextlist = &c->erasable_list; |
@@ -101,7 +101,7 @@ again: | |||
101 | printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset); | 101 | printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset); |
102 | BUG(); | 102 | BUG(); |
103 | } | 103 | } |
104 | 104 | ||
105 | /* Have we accidentally picked a clean block with wasted space ? */ | 105 | /* Have we accidentally picked a clean block with wasted space ? */ |
106 | if (ret->wasted_size) { | 106 | if (ret->wasted_size) { |
107 | D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size)); | 107 | D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size)); |
@@ -111,7 +111,6 @@ again: | |||
111 | ret->wasted_size = 0; | 111 | ret->wasted_size = 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | D2(jffs2_dump_block_lists(c)); | ||
115 | return ret; | 114 | return ret; |
116 | } | 115 | } |
117 | 116 | ||
@@ -137,12 +136,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
137 | 136 | ||
138 | /* We can't start doing GC yet. We haven't finished checking | 137 | /* We can't start doing GC yet. We haven't finished checking |
139 | the node CRCs etc. Do it now. */ | 138 | the node CRCs etc. Do it now. */ |
140 | 139 | ||
141 | /* checked_ino is protected by the alloc_sem */ | 140 | /* checked_ino is protected by the alloc_sem */ |
142 | if (c->checked_ino > c->highest_ino) { | 141 | if (c->checked_ino > c->highest_ino) { |
143 | printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", | 142 | printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", |
144 | c->unchecked_size); | 143 | c->unchecked_size); |
145 | D2(jffs2_dump_block_lists(c)); | 144 | jffs2_dbg_dump_block_lists_nolock(c); |
146 | spin_unlock(&c->erase_completion_lock); | 145 | spin_unlock(&c->erase_completion_lock); |
147 | BUG(); | 146 | BUG(); |
148 | } | 147 | } |
@@ -179,7 +178,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
179 | 178 | ||
180 | case INO_STATE_READING: | 179 | case INO_STATE_READING: |
181 | /* We need to wait for it to finish, lest we move on | 180 | /* We need to wait for it to finish, lest we move on |
182 | and trigger the BUG() above while we haven't yet | 181 | and trigger the BUG() above while we haven't yet |
183 | finished checking all its nodes */ | 182 | finished checking all its nodes */ |
184 | D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino)); | 183 | D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino)); |
185 | up(&c->alloc_sem); | 184 | up(&c->alloc_sem); |
@@ -229,13 +228,13 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
229 | } | 228 | } |
230 | 229 | ||
231 | raw = jeb->gc_node; | 230 | raw = jeb->gc_node; |
232 | 231 | ||
233 | while(ref_obsolete(raw)) { | 232 | while(ref_obsolete(raw)) { |
234 | D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); | 233 | D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); |
235 | raw = raw->next_phys; | 234 | raw = raw->next_phys; |
236 | if (unlikely(!raw)) { | 235 | if (unlikely(!raw)) { |
237 | printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); | 236 | printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); |
238 | printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", | 237 | printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", |
239 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); | 238 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); |
240 | jeb->gc_node = raw; | 239 | jeb->gc_node = raw; |
241 | spin_unlock(&c->erase_completion_lock); | 240 | spin_unlock(&c->erase_completion_lock); |
@@ -260,7 +259,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
260 | ic = jffs2_raw_ref_to_ic(raw); | 259 | ic = jffs2_raw_ref_to_ic(raw); |
261 | 260 | ||
262 | /* We need to hold the inocache. Either the erase_completion_lock or | 261 | /* We need to hold the inocache. Either the erase_completion_lock or |
263 | the inocache_lock are sufficient; we trade down since the inocache_lock | 262 | the inocache_lock are sufficient; we trade down since the inocache_lock |
264 | causes less contention. */ | 263 | causes less contention. */ |
265 | spin_lock(&c->inocache_lock); | 264 | spin_lock(&c->inocache_lock); |
266 | 265 | ||
@@ -279,14 +278,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
279 | 278 | ||
280 | switch(ic->state) { | 279 | switch(ic->state) { |
281 | case INO_STATE_CHECKEDABSENT: | 280 | case INO_STATE_CHECKEDABSENT: |
282 | /* It's been checked, but it's not currently in-core. | 281 | /* It's been checked, but it's not currently in-core. |
283 | We can just copy any pristine nodes, but have | 282 | We can just copy any pristine nodes, but have |
284 | to prevent anyone else from doing read_inode() while | 283 | to prevent anyone else from doing read_inode() while |
285 | we're at it, so we set the state accordingly */ | 284 | we're at it, so we set the state accordingly */ |
286 | if (ref_flags(raw) == REF_PRISTINE) | 285 | if (ref_flags(raw) == REF_PRISTINE) |
287 | ic->state = INO_STATE_GC; | 286 | ic->state = INO_STATE_GC; |
288 | else { | 287 | else { |
289 | D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", | 288 | D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", |
290 | ic->ino)); | 289 | ic->ino)); |
291 | } | 290 | } |
292 | break; | 291 | break; |
@@ -299,8 +298,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
299 | case INO_STATE_CHECKING: | 298 | case INO_STATE_CHECKING: |
300 | case INO_STATE_GC: | 299 | case INO_STATE_GC: |
301 | /* Should never happen. We should have finished checking | 300 | /* Should never happen. We should have finished checking |
302 | by the time we actually start doing any GC, and since | 301 | by the time we actually start doing any GC, and since |
303 | we're holding the alloc_sem, no other garbage collection | 302 | we're holding the alloc_sem, no other garbage collection |
304 | can happen. | 303 | can happen. |
305 | */ | 304 | */ |
306 | printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", | 305 | printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", |
@@ -320,21 +319,21 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
320 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", | 319 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", |
321 | ic->ino, ic->state)); | 320 | ic->ino, ic->state)); |
322 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); | 321 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); |
323 | /* And because we dropped the alloc_sem we must start again from the | 322 | /* And because we dropped the alloc_sem we must start again from the |
324 | beginning. Ponder chance of livelock here -- we're returning success | 323 | beginning. Ponder chance of livelock here -- we're returning success |
325 | without actually making any progress. | 324 | without actually making any progress. |
326 | 325 | ||
327 | Q: What are the chances that the inode is back in INO_STATE_READING | 326 | Q: What are the chances that the inode is back in INO_STATE_READING |
328 | again by the time we next enter this function? And that this happens | 327 | again by the time we next enter this function? And that this happens |
329 | enough times to cause a real delay? | 328 | enough times to cause a real delay? |
330 | 329 | ||
331 | A: Small enough that I don't care :) | 330 | A: Small enough that I don't care :) |
332 | */ | 331 | */ |
333 | return 0; | 332 | return 0; |
334 | } | 333 | } |
335 | 334 | ||
336 | /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the | 335 | /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the |
337 | node intact, and we don't have to muck about with the fragtree etc. | 336 | node intact, and we don't have to muck about with the fragtree etc. |
338 | because we know it's not in-core. If it _was_ in-core, we go through | 337 | because we know it's not in-core. If it _was_ in-core, we go through |
339 | all the iget() crap anyway */ | 338 | all the iget() crap anyway */ |
340 | 339 | ||
@@ -454,7 +453,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era | |||
454 | if (!ret) { | 453 | if (!ret) { |
455 | /* Urgh. Return it sensibly. */ | 454 | /* Urgh. Return it sensibly. */ |
456 | frag->node->raw = f->inocache->nodes; | 455 | frag->node->raw = f->inocache->nodes; |
457 | } | 456 | } |
458 | if (ret != -EBADFD) | 457 | if (ret != -EBADFD) |
459 | goto upnout; | 458 | goto upnout; |
460 | } | 459 | } |
@@ -468,7 +467,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era | |||
468 | } | 467 | } |
469 | goto upnout; | 468 | goto upnout; |
470 | } | 469 | } |
471 | 470 | ||
472 | /* Wasn't a dnode. Try dirent */ | 471 | /* Wasn't a dnode. Try dirent */ |
473 | for (fd = f->dents; fd; fd=fd->next) { | 472 | for (fd = f->dents; fd; fd=fd->next) { |
474 | if (fd->raw == raw) | 473 | if (fd->raw == raw) |
@@ -485,7 +484,8 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era | |||
485 | if (ref_obsolete(raw)) { | 484 | if (ref_obsolete(raw)) { |
486 | printk(KERN_WARNING "But it's obsolete so we don't mind too much\n"); | 485 | printk(KERN_WARNING "But it's obsolete so we don't mind too much\n"); |
487 | } else { | 486 | } else { |
488 | ret = -EIO; | 487 | jffs2_dbg_dump_node(c, ref_offset(raw)); |
488 | BUG(); | ||
489 | } | 489 | } |
490 | } | 490 | } |
491 | upnout: | 491 | upnout: |
@@ -494,7 +494,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era | |||
494 | return ret; | 494 | return ret; |
495 | } | 495 | } |
496 | 496 | ||
497 | static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | 497 | static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, |
498 | struct jffs2_inode_cache *ic, | 498 | struct jffs2_inode_cache *ic, |
499 | struct jffs2_raw_node_ref *raw) | 499 | struct jffs2_raw_node_ref *raw) |
500 | { | 500 | { |
@@ -513,8 +513,11 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
513 | /* Ask for a small amount of space (or the totlen if smaller) because we | 513 | /* Ask for a small amount of space (or the totlen if smaller) because we |
514 | don't want to force wastage of the end of a block if splitting would | 514 | don't want to force wastage of the end of a block if splitting would |
515 | work. */ | 515 | work. */ |
516 | ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, | 516 | ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + |
517 | rawlen), &phys_ofs, &alloclen); | 517 | JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen); |
518 | /* this is not the exact summary size of it, | ||
519 | it is only an upper estimation */ | ||
520 | |||
518 | if (ret) | 521 | if (ret) |
519 | return ret; | 522 | return ret; |
520 | 523 | ||
@@ -577,7 +580,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
577 | } | 580 | } |
578 | break; | 581 | break; |
579 | default: | 582 | default: |
580 | printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", | 583 | printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", |
581 | ref_offset(raw), je16_to_cpu(node->u.nodetype)); | 584 | ref_offset(raw), je16_to_cpu(node->u.nodetype)); |
582 | goto bail; | 585 | goto bail; |
583 | } | 586 | } |
@@ -618,17 +621,19 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
618 | retried = 1; | 621 | retried = 1; |
619 | 622 | ||
620 | D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n")); | 623 | D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n")); |
621 | |||
622 | ACCT_SANITY_CHECK(c,jeb); | ||
623 | D1(ACCT_PARANOIA_CHECK(jeb)); | ||
624 | 624 | ||
625 | ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy); | 625 | jffs2_dbg_acct_sanity_check(c,jeb); |
626 | jffs2_dbg_acct_paranoia_check(c, jeb); | ||
627 | |||
628 | ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy, rawlen); | ||
629 | /* this is not the exact summary size of it, | ||
630 | it is only an upper estimation */ | ||
626 | 631 | ||
627 | if (!ret) { | 632 | if (!ret) { |
628 | D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs)); | 633 | D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs)); |
629 | 634 | ||
630 | ACCT_SANITY_CHECK(c,jeb); | 635 | jffs2_dbg_acct_sanity_check(c,jeb); |
631 | D1(ACCT_PARANOIA_CHECK(jeb)); | 636 | jffs2_dbg_acct_paranoia_check(c, jeb); |
632 | 637 | ||
633 | goto retry; | 638 | goto retry; |
634 | } | 639 | } |
@@ -664,7 +669,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
664 | goto out_node; | 669 | goto out_node; |
665 | } | 670 | } |
666 | 671 | ||
667 | static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 672 | static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
668 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) | 673 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) |
669 | { | 674 | { |
670 | struct jffs2_full_dnode *new_fn; | 675 | struct jffs2_full_dnode *new_fn; |
@@ -679,7 +684,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
679 | S_ISCHR(JFFS2_F_I_MODE(f)) ) { | 684 | S_ISCHR(JFFS2_F_I_MODE(f)) ) { |
680 | /* For these, we don't actually need to read the old node */ | 685 | /* For these, we don't actually need to read the old node */ |
681 | /* FIXME: for minor or major > 255. */ | 686 | /* FIXME: for minor or major > 255. */ |
682 | dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | | 687 | dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | |
683 | JFFS2_F_I_RDEV_MIN(f))); | 688 | JFFS2_F_I_RDEV_MIN(f))); |
684 | mdata = (char *)&dev; | 689 | mdata = (char *)&dev; |
685 | mdatalen = sizeof(dev); | 690 | mdatalen = sizeof(dev); |
@@ -700,14 +705,15 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
700 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bites of symlink target\n", mdatalen)); | 705 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bites of symlink target\n", mdatalen)); |
701 | 706 | ||
702 | } | 707 | } |
703 | 708 | ||
704 | ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen); | 709 | ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen, |
710 | JFFS2_SUMMARY_INODE_SIZE); | ||
705 | if (ret) { | 711 | if (ret) { |
706 | printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", | 712 | printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", |
707 | sizeof(ri)+ mdatalen, ret); | 713 | sizeof(ri)+ mdatalen, ret); |
708 | goto out; | 714 | goto out; |
709 | } | 715 | } |
710 | 716 | ||
711 | last_frag = frag_last(&f->fragtree); | 717 | last_frag = frag_last(&f->fragtree); |
712 | if (last_frag) | 718 | if (last_frag) |
713 | /* Fetch the inode length from the fragtree rather then | 719 | /* Fetch the inode length from the fragtree rather then |
@@ -715,7 +721,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
715 | ilen = last_frag->ofs + last_frag->size; | 721 | ilen = last_frag->ofs + last_frag->size; |
716 | else | 722 | else |
717 | ilen = JFFS2_F_I_SIZE(f); | 723 | ilen = JFFS2_F_I_SIZE(f); |
718 | 724 | ||
719 | memset(&ri, 0, sizeof(ri)); | 725 | memset(&ri, 0, sizeof(ri)); |
720 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 726 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
721 | ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); | 727 | ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); |
@@ -754,7 +760,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
754 | return ret; | 760 | return ret; |
755 | } | 761 | } |
756 | 762 | ||
757 | static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 763 | static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
758 | struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) | 764 | struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) |
759 | { | 765 | { |
760 | struct jffs2_full_dirent *new_fd; | 766 | struct jffs2_full_dirent *new_fd; |
@@ -771,12 +777,18 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er | |||
771 | rd.pino = cpu_to_je32(f->inocache->ino); | 777 | rd.pino = cpu_to_je32(f->inocache->ino); |
772 | rd.version = cpu_to_je32(++f->highest_version); | 778 | rd.version = cpu_to_je32(++f->highest_version); |
773 | rd.ino = cpu_to_je32(fd->ino); | 779 | rd.ino = cpu_to_je32(fd->ino); |
774 | rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f))); | 780 | /* If the times on this inode were set by explicit utime() they can be different, |
781 | so refrain from splatting them. */ | ||
782 | if (JFFS2_F_I_MTIME(f) == JFFS2_F_I_CTIME(f)) | ||
783 | rd.mctime = cpu_to_je32(JFFS2_F_I_MTIME(f)); | ||
784 | else | ||
785 | rd.mctime = cpu_to_je32(0); | ||
775 | rd.type = fd->type; | 786 | rd.type = fd->type; |
776 | rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); | 787 | rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); |
777 | rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); | 788 | rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); |
778 | 789 | ||
779 | ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); | 790 | ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen, |
791 | JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize)); | ||
780 | if (ret) { | 792 | if (ret) { |
781 | printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", | 793 | printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", |
782 | sizeof(rd)+rd.nsize, ret); | 794 | sizeof(rd)+rd.nsize, ret); |
@@ -792,7 +804,7 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er | |||
792 | return 0; | 804 | return 0; |
793 | } | 805 | } |
794 | 806 | ||
795 | static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 807 | static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
796 | struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) | 808 | struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) |
797 | { | 809 | { |
798 | struct jffs2_full_dirent **fdp = &f->dents; | 810 | struct jffs2_full_dirent **fdp = &f->dents; |
@@ -831,7 +843,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
831 | if (ref_totlen(c, NULL, raw) != rawlen) | 843 | if (ref_totlen(c, NULL, raw) != rawlen) |
832 | continue; | 844 | continue; |
833 | 845 | ||
834 | /* Doesn't matter if there's one in the same erase block. We're going to | 846 | /* Doesn't matter if there's one in the same erase block. We're going to |
835 | delete it too at the same time. */ | 847 | delete it too at the same time. */ |
836 | if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) | 848 | if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) |
837 | continue; | 849 | continue; |
@@ -883,6 +895,9 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
883 | kfree(rd); | 895 | kfree(rd); |
884 | } | 896 | } |
885 | 897 | ||
898 | /* FIXME: If we're deleting a dirent which contains the current mtime and ctime, | ||
899 | we should update the metadata node with those times accordingly */ | ||
900 | |||
886 | /* No need for it any more. Just mark it obsolete and remove it from the list */ | 901 | /* No need for it any more. Just mark it obsolete and remove it from the list */ |
887 | while (*fdp) { | 902 | while (*fdp) { |
888 | if ((*fdp) == fd) { | 903 | if ((*fdp) == fd) { |
@@ -912,13 +927,13 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
912 | 927 | ||
913 | D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", | 928 | D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", |
914 | f->inocache->ino, start, end)); | 929 | f->inocache->ino, start, end)); |
915 | 930 | ||
916 | memset(&ri, 0, sizeof(ri)); | 931 | memset(&ri, 0, sizeof(ri)); |
917 | 932 | ||
918 | if(fn->frags > 1) { | 933 | if(fn->frags > 1) { |
919 | size_t readlen; | 934 | size_t readlen; |
920 | uint32_t crc; | 935 | uint32_t crc; |
921 | /* It's partially obsoleted by a later write. So we have to | 936 | /* It's partially obsoleted by a later write. So we have to |
922 | write it out again with the _same_ version as before */ | 937 | write it out again with the _same_ version as before */ |
923 | ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); | 938 | ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); |
924 | if (readlen != sizeof(ri) || ret) { | 939 | if (readlen != sizeof(ri) || ret) { |
@@ -940,16 +955,16 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
940 | crc = crc32(0, &ri, sizeof(ri)-8); | 955 | crc = crc32(0, &ri, sizeof(ri)-8); |
941 | if (crc != je32_to_cpu(ri.node_crc)) { | 956 | if (crc != je32_to_cpu(ri.node_crc)) { |
942 | printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", | 957 | printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", |
943 | ref_offset(fn->raw), | 958 | ref_offset(fn->raw), |
944 | je32_to_cpu(ri.node_crc), crc); | 959 | je32_to_cpu(ri.node_crc), crc); |
945 | /* FIXME: We could possibly deal with this by writing new holes for each frag */ | 960 | /* FIXME: We could possibly deal with this by writing new holes for each frag */ |
946 | printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", | 961 | printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", |
947 | start, end, f->inocache->ino); | 962 | start, end, f->inocache->ino); |
948 | goto fill; | 963 | goto fill; |
949 | } | 964 | } |
950 | if (ri.compr != JFFS2_COMPR_ZERO) { | 965 | if (ri.compr != JFFS2_COMPR_ZERO) { |
951 | printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw)); | 966 | printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw)); |
952 | printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", | 967 | printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", |
953 | start, end, f->inocache->ino); | 968 | start, end, f->inocache->ino); |
954 | goto fill; | 969 | goto fill; |
955 | } | 970 | } |
@@ -967,7 +982,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
967 | ri.csize = cpu_to_je32(0); | 982 | ri.csize = cpu_to_je32(0); |
968 | ri.compr = JFFS2_COMPR_ZERO; | 983 | ri.compr = JFFS2_COMPR_ZERO; |
969 | } | 984 | } |
970 | 985 | ||
971 | frag = frag_last(&f->fragtree); | 986 | frag = frag_last(&f->fragtree); |
972 | if (frag) | 987 | if (frag) |
973 | /* Fetch the inode length from the fragtree rather then | 988 | /* Fetch the inode length from the fragtree rather then |
@@ -986,7 +1001,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
986 | ri.data_crc = cpu_to_je32(0); | 1001 | ri.data_crc = cpu_to_je32(0); |
987 | ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); | 1002 | ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); |
988 | 1003 | ||
989 | ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); | 1004 | ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen, |
1005 | JFFS2_SUMMARY_INODE_SIZE); | ||
990 | if (ret) { | 1006 | if (ret) { |
991 | printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", | 1007 | printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", |
992 | sizeof(ri), ret); | 1008 | sizeof(ri), ret); |
@@ -1008,10 +1024,10 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
1008 | return 0; | 1024 | return 0; |
1009 | } | 1025 | } |
1010 | 1026 | ||
1011 | /* | 1027 | /* |
1012 | * We should only get here in the case where the node we are | 1028 | * We should only get here in the case where the node we are |
1013 | * replacing had more than one frag, so we kept the same version | 1029 | * replacing had more than one frag, so we kept the same version |
1014 | * number as before. (Except in case of error -- see 'goto fill;' | 1030 | * number as before. (Except in case of error -- see 'goto fill;' |
1015 | * above.) | 1031 | * above.) |
1016 | */ | 1032 | */ |
1017 | D1(if(unlikely(fn->frags <= 1)) { | 1033 | D1(if(unlikely(fn->frags <= 1)) { |
@@ -1023,7 +1039,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
1023 | /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */ | 1039 | /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */ |
1024 | mark_ref_normal(new_fn->raw); | 1040 | mark_ref_normal(new_fn->raw); |
1025 | 1041 | ||
1026 | for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); | 1042 | for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); |
1027 | frag; frag = frag_next(frag)) { | 1043 | frag; frag = frag_next(frag)) { |
1028 | if (frag->ofs > fn->size + fn->ofs) | 1044 | if (frag->ofs > fn->size + fn->ofs) |
1029 | break; | 1045 | break; |
@@ -1041,10 +1057,10 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
1041 | printk(KERN_WARNING "jffs2_garbage_collect_hole: New node has no frags!\n"); | 1057 | printk(KERN_WARNING "jffs2_garbage_collect_hole: New node has no frags!\n"); |
1042 | BUG(); | 1058 | BUG(); |
1043 | } | 1059 | } |
1044 | 1060 | ||
1045 | jffs2_mark_node_obsolete(c, fn->raw); | 1061 | jffs2_mark_node_obsolete(c, fn->raw); |
1046 | jffs2_free_full_dnode(fn); | 1062 | jffs2_free_full_dnode(fn); |
1047 | 1063 | ||
1048 | return 0; | 1064 | return 0; |
1049 | } | 1065 | } |
1050 | 1066 | ||
@@ -1054,12 +1070,12 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1054 | { | 1070 | { |
1055 | struct jffs2_full_dnode *new_fn; | 1071 | struct jffs2_full_dnode *new_fn; |
1056 | struct jffs2_raw_inode ri; | 1072 | struct jffs2_raw_inode ri; |
1057 | uint32_t alloclen, phys_ofs, offset, orig_end, orig_start; | 1073 | uint32_t alloclen, phys_ofs, offset, orig_end, orig_start; |
1058 | int ret = 0; | 1074 | int ret = 0; |
1059 | unsigned char *comprbuf = NULL, *writebuf; | 1075 | unsigned char *comprbuf = NULL, *writebuf; |
1060 | unsigned long pg; | 1076 | unsigned long pg; |
1061 | unsigned char *pg_ptr; | 1077 | unsigned char *pg_ptr; |
1062 | 1078 | ||
1063 | memset(&ri, 0, sizeof(ri)); | 1079 | memset(&ri, 0, sizeof(ri)); |
1064 | 1080 | ||
1065 | D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n", | 1081 | D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n", |
@@ -1071,8 +1087,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1071 | if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) { | 1087 | if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) { |
1072 | /* Attempt to do some merging. But only expand to cover logically | 1088 | /* Attempt to do some merging. But only expand to cover logically |
1073 | adjacent frags if the block containing them is already considered | 1089 | adjacent frags if the block containing them is already considered |
1074 | to be dirty. Otherwise we end up with GC just going round in | 1090 | to be dirty. Otherwise we end up with GC just going round in |
1075 | circles dirtying the nodes it already wrote out, especially | 1091 | circles dirtying the nodes it already wrote out, especially |
1076 | on NAND where we have small eraseblocks and hence a much higher | 1092 | on NAND where we have small eraseblocks and hence a much higher |
1077 | chance of nodes having to be split to cross boundaries. */ | 1093 | chance of nodes having to be split to cross boundaries. */ |
1078 | 1094 | ||
@@ -1106,7 +1122,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1106 | break; | 1122 | break; |
1107 | } else { | 1123 | } else { |
1108 | 1124 | ||
1109 | /* OK, it's a frag which extends to the beginning of the page. Does it live | 1125 | /* OK, it's a frag which extends to the beginning of the page. Does it live |
1110 | in a block which is still considered clean? If so, don't obsolete it. | 1126 | in a block which is still considered clean? If so, don't obsolete it. |
1111 | If not, cover it anyway. */ | 1127 | If not, cover it anyway. */ |
1112 | 1128 | ||
@@ -1156,7 +1172,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1156 | break; | 1172 | break; |
1157 | } else { | 1173 | } else { |
1158 | 1174 | ||
1159 | /* OK, it's a frag which extends to the beginning of the page. Does it live | 1175 | /* OK, it's a frag which extends to the beginning of the page. Does it live |
1160 | in a block which is still considered clean? If so, don't obsolete it. | 1176 | in a block which is still considered clean? If so, don't obsolete it. |
1161 | If not, cover it anyway. */ | 1177 | If not, cover it anyway. */ |
1162 | 1178 | ||
@@ -1183,14 +1199,14 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1183 | break; | 1199 | break; |
1184 | } | 1200 | } |
1185 | } | 1201 | } |
1186 | D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", | 1202 | D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", |
1187 | orig_start, orig_end, start, end)); | 1203 | orig_start, orig_end, start, end)); |
1188 | 1204 | ||
1189 | D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); | 1205 | D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); |
1190 | BUG_ON(end < orig_end); | 1206 | BUG_ON(end < orig_end); |
1191 | BUG_ON(start > orig_start); | 1207 | BUG_ON(start > orig_start); |
1192 | } | 1208 | } |
1193 | 1209 | ||
1194 | /* First, use readpage() to read the appropriate page into the page cache */ | 1210 | /* First, use readpage() to read the appropriate page into the page cache */ |
1195 | /* Q: What happens if we actually try to GC the _same_ page for which commit_write() | 1211 | /* Q: What happens if we actually try to GC the _same_ page for which commit_write() |
1196 | * triggered garbage collection in the first place? | 1212 | * triggered garbage collection in the first place? |
@@ -1211,7 +1227,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1211 | uint32_t cdatalen; | 1227 | uint32_t cdatalen; |
1212 | uint16_t comprtype = JFFS2_COMPR_NONE; | 1228 | uint16_t comprtype = JFFS2_COMPR_NONE; |
1213 | 1229 | ||
1214 | ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen); | 1230 | ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, |
1231 | &alloclen, JFFS2_SUMMARY_INODE_SIZE); | ||
1215 | 1232 | ||
1216 | if (ret) { | 1233 | if (ret) { |
1217 | printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", | 1234 | printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", |
@@ -1246,7 +1263,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1246 | ri.usercompr = (comprtype >> 8) & 0xff; | 1263 | ri.usercompr = (comprtype >> 8) & 0xff; |
1247 | ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); | 1264 | ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); |
1248 | ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); | 1265 | ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); |
1249 | 1266 | ||
1250 | new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC); | 1267 | new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC); |
1251 | 1268 | ||
1252 | jffs2_free_comprbuf(comprbuf, writebuf); | 1269 | jffs2_free_comprbuf(comprbuf, writebuf); |
@@ -1268,4 +1285,3 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1268 | jffs2_gc_release_page(c, pg_ptr, &pg); | 1285 | jffs2_gc_release_page(c, pg_ptr, &pg); |
1269 | return ret; | 1286 | return ret; |
1270 | } | 1287 | } |
1271 | |||
diff --git a/fs/jffs2/histo.h b/fs/jffs2/histo.h index 84f184f0836f..22a93a08210c 100644 --- a/fs/jffs2/histo.h +++ b/fs/jffs2/histo.h | |||
@@ -1,3 +1,3 @@ | |||
1 | /* This file provides the bit-probabilities for the input file */ | 1 | /* This file provides the bit-probabilities for the input file */ |
2 | #define BIT_DIVIDER 629 | 2 | #define BIT_DIVIDER 629 |
3 | static int bits[9] = { 179,167,183,165,159,198,178,119,}; /* ia32 .so files */ | 3 | static int bits[9] = { 179,167,183,165,159,198,178,119,}; /* ia32 .so files */ |
diff --git a/fs/jffs2/histo_mips.h b/fs/jffs2/histo_mips.h index 9a443268d885..fa3dac19a109 100644 --- a/fs/jffs2/histo_mips.h +++ b/fs/jffs2/histo_mips.h | |||
@@ -1,2 +1,2 @@ | |||
1 | #define BIT_DIVIDER_MIPS 1043 | 1 | #define BIT_DIVIDER_MIPS 1043 |
2 | static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */ | 2 | static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */ |
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c index 238c7992064c..69099835de1c 100644 --- a/fs/jffs2/ioctl.c +++ b/fs/jffs2/ioctl.c | |||
@@ -7,17 +7,17 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: ioctl.c,v 1.9 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: ioctl.c,v 1.10 2005/11/07 11:14:40 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
15 | 15 | ||
16 | int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | 16 | int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
17 | unsigned long arg) | 17 | unsigned long arg) |
18 | { | 18 | { |
19 | /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which | 19 | /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which |
20 | will include compression support etc. */ | 20 | will include compression support etc. */ |
21 | return -ENOTTY; | 21 | return -ENOTTY; |
22 | } | 22 | } |
23 | 23 | ||
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 5abb431c2a00..036cbd11c004 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: malloc.c,v 1.28 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: malloc.c,v 1.31 2005/11/07 11:14:40 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -17,15 +17,6 @@ | |||
17 | #include <linux/jffs2.h> | 17 | #include <linux/jffs2.h> |
18 | #include "nodelist.h" | 18 | #include "nodelist.h" |
19 | 19 | ||
20 | #if 0 | ||
21 | #define JFFS2_SLAB_POISON SLAB_POISON | ||
22 | #else | ||
23 | #define JFFS2_SLAB_POISON 0 | ||
24 | #endif | ||
25 | |||
26 | // replace this by #define D3 (x) x for cache debugging | ||
27 | #define D3(x) | ||
28 | |||
29 | /* These are initialised to NULL in the kernel startup code. | 20 | /* These are initialised to NULL in the kernel startup code. |
30 | If you're porting to other operating systems, beware */ | 21 | If you're porting to other operating systems, beware */ |
31 | static kmem_cache_t *full_dnode_slab; | 22 | static kmem_cache_t *full_dnode_slab; |
@@ -38,45 +29,45 @@ static kmem_cache_t *inode_cache_slab; | |||
38 | 29 | ||
39 | int __init jffs2_create_slab_caches(void) | 30 | int __init jffs2_create_slab_caches(void) |
40 | { | 31 | { |
41 | full_dnode_slab = kmem_cache_create("jffs2_full_dnode", | 32 | full_dnode_slab = kmem_cache_create("jffs2_full_dnode", |
42 | sizeof(struct jffs2_full_dnode), | 33 | sizeof(struct jffs2_full_dnode), |
43 | 0, JFFS2_SLAB_POISON, NULL, NULL); | 34 | 0, 0, NULL, NULL); |
44 | if (!full_dnode_slab) | 35 | if (!full_dnode_slab) |
45 | goto err; | 36 | goto err; |
46 | 37 | ||
47 | raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", | 38 | raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", |
48 | sizeof(struct jffs2_raw_dirent), | 39 | sizeof(struct jffs2_raw_dirent), |
49 | 0, JFFS2_SLAB_POISON, NULL, NULL); | 40 | 0, 0, NULL, NULL); |
50 | if (!raw_dirent_slab) | 41 | if (!raw_dirent_slab) |
51 | goto err; | 42 | goto err; |
52 | 43 | ||
53 | raw_inode_slab = kmem_cache_create("jffs2_raw_inode", | 44 | raw_inode_slab = kmem_cache_create("jffs2_raw_inode", |
54 | sizeof(struct jffs2_raw_inode), | 45 | sizeof(struct jffs2_raw_inode), |
55 | 0, JFFS2_SLAB_POISON, NULL, NULL); | 46 | 0, 0, NULL, NULL); |
56 | if (!raw_inode_slab) | 47 | if (!raw_inode_slab) |
57 | goto err; | 48 | goto err; |
58 | 49 | ||
59 | tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", | 50 | tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", |
60 | sizeof(struct jffs2_tmp_dnode_info), | 51 | sizeof(struct jffs2_tmp_dnode_info), |
61 | 0, JFFS2_SLAB_POISON, NULL, NULL); | 52 | 0, 0, NULL, NULL); |
62 | if (!tmp_dnode_info_slab) | 53 | if (!tmp_dnode_info_slab) |
63 | goto err; | 54 | goto err; |
64 | 55 | ||
65 | raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", | 56 | raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", |
66 | sizeof(struct jffs2_raw_node_ref), | 57 | sizeof(struct jffs2_raw_node_ref), |
67 | 0, JFFS2_SLAB_POISON, NULL, NULL); | 58 | 0, 0, NULL, NULL); |
68 | if (!raw_node_ref_slab) | 59 | if (!raw_node_ref_slab) |
69 | goto err; | 60 | goto err; |
70 | 61 | ||
71 | node_frag_slab = kmem_cache_create("jffs2_node_frag", | 62 | node_frag_slab = kmem_cache_create("jffs2_node_frag", |
72 | sizeof(struct jffs2_node_frag), | 63 | sizeof(struct jffs2_node_frag), |
73 | 0, JFFS2_SLAB_POISON, NULL, NULL); | 64 | 0, 0, NULL, NULL); |
74 | if (!node_frag_slab) | 65 | if (!node_frag_slab) |
75 | goto err; | 66 | goto err; |
76 | 67 | ||
77 | inode_cache_slab = kmem_cache_create("jffs2_inode_cache", | 68 | inode_cache_slab = kmem_cache_create("jffs2_inode_cache", |
78 | sizeof(struct jffs2_inode_cache), | 69 | sizeof(struct jffs2_inode_cache), |
79 | 0, JFFS2_SLAB_POISON, NULL, NULL); | 70 | 0, 0, NULL, NULL); |
80 | if (inode_cache_slab) | 71 | if (inode_cache_slab) |
81 | return 0; | 72 | return 0; |
82 | err: | 73 | err: |
@@ -104,102 +95,113 @@ void jffs2_destroy_slab_caches(void) | |||
104 | 95 | ||
105 | struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) | 96 | struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) |
106 | { | 97 | { |
107 | return kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); | 98 | struct jffs2_full_dirent *ret; |
99 | ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); | ||
100 | dbg_memalloc("%p\n", ret); | ||
101 | return ret; | ||
108 | } | 102 | } |
109 | 103 | ||
110 | void jffs2_free_full_dirent(struct jffs2_full_dirent *x) | 104 | void jffs2_free_full_dirent(struct jffs2_full_dirent *x) |
111 | { | 105 | { |
106 | dbg_memalloc("%p\n", x); | ||
112 | kfree(x); | 107 | kfree(x); |
113 | } | 108 | } |
114 | 109 | ||
115 | struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) | 110 | struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) |
116 | { | 111 | { |
117 | struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); | 112 | struct jffs2_full_dnode *ret; |
118 | D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret)); | 113 | ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); |
114 | dbg_memalloc("%p\n", ret); | ||
119 | return ret; | 115 | return ret; |
120 | } | 116 | } |
121 | 117 | ||
122 | void jffs2_free_full_dnode(struct jffs2_full_dnode *x) | 118 | void jffs2_free_full_dnode(struct jffs2_full_dnode *x) |
123 | { | 119 | { |
124 | D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x)); | 120 | dbg_memalloc("%p\n", x); |
125 | kmem_cache_free(full_dnode_slab, x); | 121 | kmem_cache_free(full_dnode_slab, x); |
126 | } | 122 | } |
127 | 123 | ||
128 | struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) | 124 | struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) |
129 | { | 125 | { |
130 | struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); | 126 | struct jffs2_raw_dirent *ret; |
131 | D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret)); | 127 | ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); |
128 | dbg_memalloc("%p\n", ret); | ||
132 | return ret; | 129 | return ret; |
133 | } | 130 | } |
134 | 131 | ||
135 | void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) | 132 | void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) |
136 | { | 133 | { |
137 | D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x)); | 134 | dbg_memalloc("%p\n", x); |
138 | kmem_cache_free(raw_dirent_slab, x); | 135 | kmem_cache_free(raw_dirent_slab, x); |
139 | } | 136 | } |
140 | 137 | ||
141 | struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) | 138 | struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) |
142 | { | 139 | { |
143 | struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); | 140 | struct jffs2_raw_inode *ret; |
144 | D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret)); | 141 | ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); |
142 | dbg_memalloc("%p\n", ret); | ||
145 | return ret; | 143 | return ret; |
146 | } | 144 | } |
147 | 145 | ||
148 | void jffs2_free_raw_inode(struct jffs2_raw_inode *x) | 146 | void jffs2_free_raw_inode(struct jffs2_raw_inode *x) |
149 | { | 147 | { |
150 | D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x)); | 148 | dbg_memalloc("%p\n", x); |
151 | kmem_cache_free(raw_inode_slab, x); | 149 | kmem_cache_free(raw_inode_slab, x); |
152 | } | 150 | } |
153 | 151 | ||
154 | struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) | 152 | struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) |
155 | { | 153 | { |
156 | struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); | 154 | struct jffs2_tmp_dnode_info *ret; |
157 | D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret)); | 155 | ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); |
156 | dbg_memalloc("%p\n", | ||
157 | ret); | ||
158 | return ret; | 158 | return ret; |
159 | } | 159 | } |
160 | 160 | ||
161 | void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) | 161 | void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) |
162 | { | 162 | { |
163 | D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x)); | 163 | dbg_memalloc("%p\n", x); |
164 | kmem_cache_free(tmp_dnode_info_slab, x); | 164 | kmem_cache_free(tmp_dnode_info_slab, x); |
165 | } | 165 | } |
166 | 166 | ||
167 | struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) | 167 | struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) |
168 | { | 168 | { |
169 | struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); | 169 | struct jffs2_raw_node_ref *ret; |
170 | D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret)); | 170 | ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); |
171 | dbg_memalloc("%p\n", ret); | ||
171 | return ret; | 172 | return ret; |
172 | } | 173 | } |
173 | 174 | ||
174 | void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) | 175 | void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) |
175 | { | 176 | { |
176 | D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x)); | 177 | dbg_memalloc("%p\n", x); |
177 | kmem_cache_free(raw_node_ref_slab, x); | 178 | kmem_cache_free(raw_node_ref_slab, x); |
178 | } | 179 | } |
179 | 180 | ||
180 | struct jffs2_node_frag *jffs2_alloc_node_frag(void) | 181 | struct jffs2_node_frag *jffs2_alloc_node_frag(void) |
181 | { | 182 | { |
182 | struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); | 183 | struct jffs2_node_frag *ret; |
183 | D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret)); | 184 | ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); |
185 | dbg_memalloc("%p\n", ret); | ||
184 | return ret; | 186 | return ret; |
185 | } | 187 | } |
186 | 188 | ||
187 | void jffs2_free_node_frag(struct jffs2_node_frag *x) | 189 | void jffs2_free_node_frag(struct jffs2_node_frag *x) |
188 | { | 190 | { |
189 | D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x)); | 191 | dbg_memalloc("%p\n", x); |
190 | kmem_cache_free(node_frag_slab, x); | 192 | kmem_cache_free(node_frag_slab, x); |
191 | } | 193 | } |
192 | 194 | ||
193 | struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) | 195 | struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) |
194 | { | 196 | { |
195 | struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); | 197 | struct jffs2_inode_cache *ret; |
196 | D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); | 198 | ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); |
199 | dbg_memalloc("%p\n", ret); | ||
197 | return ret; | 200 | return ret; |
198 | } | 201 | } |
199 | 202 | ||
200 | void jffs2_free_inode_cache(struct jffs2_inode_cache *x) | 203 | void jffs2_free_inode_cache(struct jffs2_inode_cache *x) |
201 | { | 204 | { |
202 | D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x)); | 205 | dbg_memalloc("%p\n", x); |
203 | kmem_cache_free(inode_cache_slab, x); | 206 | kmem_cache_free(inode_cache_slab, x); |
204 | } | 207 | } |
205 | |||
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 4991c348f6ec..c79eebb8ab32 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: nodelist.c,v 1.98 2005/07/10 15:15:32 dedekind Exp $ | 10 | * $Id: nodelist.c,v 1.115 2005/11/07 11:14:40 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -24,469 +24,832 @@ | |||
24 | void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) | 24 | void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) |
25 | { | 25 | { |
26 | struct jffs2_full_dirent **prev = list; | 26 | struct jffs2_full_dirent **prev = list; |
27 | D1(printk(KERN_DEBUG "jffs2_add_fd_to_list( %p, %p (->%p))\n", new, list, *list)); | 27 | |
28 | dbg_dentlist("add dirent \"%s\", ino #%u\n", new->name, new->ino); | ||
28 | 29 | ||
29 | while ((*prev) && (*prev)->nhash <= new->nhash) { | 30 | while ((*prev) && (*prev)->nhash <= new->nhash) { |
30 | if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { | 31 | if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { |
31 | /* Duplicate. Free one */ | 32 | /* Duplicate. Free one */ |
32 | if (new->version < (*prev)->version) { | 33 | if (new->version < (*prev)->version) { |
33 | D1(printk(KERN_DEBUG "Eep! Marking new dirent node obsolete\n")); | 34 | dbg_dentlist("Eep! Marking new dirent node is obsolete, old is \"%s\", ino #%u\n", |
34 | D1(printk(KERN_DEBUG "New dirent is \"%s\"->ino #%u. Old is \"%s\"->ino #%u\n", new->name, new->ino, (*prev)->name, (*prev)->ino)); | 35 | (*prev)->name, (*prev)->ino); |
35 | jffs2_mark_node_obsolete(c, new->raw); | 36 | jffs2_mark_node_obsolete(c, new->raw); |
36 | jffs2_free_full_dirent(new); | 37 | jffs2_free_full_dirent(new); |
37 | } else { | 38 | } else { |
38 | D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) obsolete\n", (*prev)->ino)); | 39 | dbg_dentlist("marking old dirent \"%s\", ino #%u bsolete\n", |
40 | (*prev)->name, (*prev)->ino); | ||
39 | new->next = (*prev)->next; | 41 | new->next = (*prev)->next; |
40 | jffs2_mark_node_obsolete(c, ((*prev)->raw)); | 42 | jffs2_mark_node_obsolete(c, ((*prev)->raw)); |
41 | jffs2_free_full_dirent(*prev); | 43 | jffs2_free_full_dirent(*prev); |
42 | *prev = new; | 44 | *prev = new; |
43 | } | 45 | } |
44 | goto out; | 46 | return; |
45 | } | 47 | } |
46 | prev = &((*prev)->next); | 48 | prev = &((*prev)->next); |
47 | } | 49 | } |
48 | new->next = *prev; | 50 | new->next = *prev; |
49 | *prev = new; | 51 | *prev = new; |
52 | } | ||
53 | |||
54 | void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) | ||
55 | { | ||
56 | struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); | ||
57 | |||
58 | dbg_fragtree("truncating fragtree to 0x%08x bytes\n", size); | ||
59 | |||
60 | /* We know frag->ofs <= size. That's what lookup does for us */ | ||
61 | if (frag && frag->ofs != size) { | ||
62 | if (frag->ofs+frag->size > size) { | ||
63 | frag->size = size - frag->ofs; | ||
64 | } | ||
65 | frag = frag_next(frag); | ||
66 | } | ||
67 | while (frag && frag->ofs >= size) { | ||
68 | struct jffs2_node_frag *next = frag_next(frag); | ||
69 | |||
70 | frag_erase(frag, list); | ||
71 | jffs2_obsolete_node_frag(c, frag); | ||
72 | frag = next; | ||
73 | } | ||
50 | 74 | ||
51 | out: | 75 | if (size == 0) |
52 | D2(while(*list) { | 76 | return; |
53 | printk(KERN_DEBUG "Dirent \"%s\" (hash 0x%08x, ino #%u\n", (*list)->name, (*list)->nhash, (*list)->ino); | 77 | |
54 | list = &(*list)->next; | 78 | /* |
55 | }); | 79 | * If the last fragment starts at the RAM page boundary, it is |
80 | * REF_PRISTINE irrespective of its size. | ||
81 | */ | ||
82 | frag = frag_last(list); | ||
83 | if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) { | ||
84 | dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n", | ||
85 | frag->ofs, frag->ofs + frag->size); | ||
86 | frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE; | ||
87 | } | ||
56 | } | 88 | } |
57 | 89 | ||
58 | /* | 90 | void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) |
59 | * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in | ||
60 | * order of increasing version. | ||
61 | */ | ||
62 | static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) | ||
63 | { | 91 | { |
64 | struct rb_node **p = &list->rb_node; | 92 | if (this->node) { |
65 | struct rb_node * parent = NULL; | 93 | this->node->frags--; |
66 | struct jffs2_tmp_dnode_info *this; | 94 | if (!this->node->frags) { |
67 | 95 | /* The node has no valid frags left. It's totally obsoleted */ | |
68 | while (*p) { | 96 | dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", |
69 | parent = *p; | 97 | ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size); |
70 | this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); | 98 | jffs2_mark_node_obsolete(c, this->node->raw); |
71 | 99 | jffs2_free_full_dnode(this->node); | |
72 | /* There may actually be a collision here, but it doesn't | 100 | } else { |
73 | actually matter. As long as the two nodes with the same | 101 | dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", |
74 | version are together, it's all fine. */ | 102 | ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, this->node->frags); |
75 | if (tn->version < this->version) | 103 | mark_ref_normal(this->node->raw); |
76 | p = &(*p)->rb_left; | 104 | } |
77 | else | ||
78 | p = &(*p)->rb_right; | ||
79 | } | ||
80 | 105 | ||
81 | rb_link_node(&tn->rb, parent, p); | 106 | } |
82 | rb_insert_color(&tn->rb, list); | 107 | jffs2_free_node_frag(this); |
83 | } | 108 | } |
84 | 109 | ||
85 | static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) | 110 | static void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) |
86 | { | 111 | { |
87 | struct rb_node *this; | 112 | struct rb_node *parent = &base->rb; |
88 | struct jffs2_tmp_dnode_info *tn; | 113 | struct rb_node **link = &parent; |
89 | 114 | ||
90 | this = list->rb_node; | 115 | dbg_fragtree2("insert frag (0x%04x-0x%04x)\n", newfrag->ofs, newfrag->ofs + newfrag->size); |
91 | 116 | ||
92 | /* Now at bottom of tree */ | 117 | while (*link) { |
93 | while (this) { | 118 | parent = *link; |
94 | if (this->rb_left) | 119 | base = rb_entry(parent, struct jffs2_node_frag, rb); |
95 | this = this->rb_left; | 120 | |
96 | else if (this->rb_right) | 121 | if (newfrag->ofs > base->ofs) |
97 | this = this->rb_right; | 122 | link = &base->rb.rb_right; |
123 | else if (newfrag->ofs < base->ofs) | ||
124 | link = &base->rb.rb_left; | ||
98 | else { | 125 | else { |
99 | tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); | 126 | JFFS2_ERROR("duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); |
100 | jffs2_free_full_dnode(tn->fn); | 127 | BUG(); |
101 | jffs2_free_tmp_dnode_info(tn); | ||
102 | |||
103 | this = this->rb_parent; | ||
104 | if (!this) | ||
105 | break; | ||
106 | |||
107 | if (this->rb_left == &tn->rb) | ||
108 | this->rb_left = NULL; | ||
109 | else if (this->rb_right == &tn->rb) | ||
110 | this->rb_right = NULL; | ||
111 | else BUG(); | ||
112 | } | 128 | } |
113 | } | 129 | } |
114 | list->rb_node = NULL; | 130 | |
131 | rb_link_node(&newfrag->rb, &base->rb, link); | ||
115 | } | 132 | } |
116 | 133 | ||
117 | static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) | 134 | /* |
135 | * Allocate and initializes a new fragment. | ||
136 | */ | ||
137 | static inline struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size) | ||
118 | { | 138 | { |
119 | struct jffs2_full_dirent *next; | 139 | struct jffs2_node_frag *newfrag; |
120 | 140 | ||
121 | while (fd) { | 141 | newfrag = jffs2_alloc_node_frag(); |
122 | next = fd->next; | 142 | if (likely(newfrag)) { |
123 | jffs2_free_full_dirent(fd); | 143 | newfrag->ofs = ofs; |
124 | fd = next; | 144 | newfrag->size = size; |
145 | newfrag->node = fn; | ||
146 | } else { | ||
147 | JFFS2_ERROR("cannot allocate a jffs2_node_frag object\n"); | ||
125 | } | 148 | } |
149 | |||
150 | return newfrag; | ||
126 | } | 151 | } |
127 | 152 | ||
128 | /* Returns first valid node after 'ref'. May return 'ref' */ | 153 | /* |
129 | static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref) | 154 | * Called when there is no overlapping fragment exist. Inserts a hole before the new |
155 | * fragment and inserts the new fragment to the fragtree. | ||
156 | */ | ||
157 | static int no_overlapping_node(struct jffs2_sb_info *c, struct rb_root *root, | ||
158 | struct jffs2_node_frag *newfrag, | ||
159 | struct jffs2_node_frag *this, uint32_t lastend) | ||
130 | { | 160 | { |
131 | while (ref && ref->next_in_ino) { | 161 | if (lastend < newfrag->node->ofs) { |
132 | if (!ref_obsolete(ref)) | 162 | /* put a hole in before the new fragment */ |
133 | return ref; | 163 | struct jffs2_node_frag *holefrag; |
134 | D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref))); | 164 | |
135 | ref = ref->next_in_ino; | 165 | holefrag= new_fragment(NULL, lastend, newfrag->node->ofs - lastend); |
166 | if (unlikely(!holefrag)) { | ||
167 | jffs2_free_node_frag(newfrag); | ||
168 | return -ENOMEM; | ||
169 | } | ||
170 | |||
171 | if (this) { | ||
172 | /* By definition, the 'this' node has no right-hand child, | ||
173 | because there are no frags with offset greater than it. | ||
174 | So that's where we want to put the hole */ | ||
175 | dbg_fragtree2("add hole frag %#04x-%#04x on the right of the new frag.\n", | ||
176 | holefrag->ofs, holefrag->ofs + holefrag->size); | ||
177 | rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); | ||
178 | } else { | ||
179 | dbg_fragtree2("Add hole frag %#04x-%#04x to the root of the tree.\n", | ||
180 | holefrag->ofs, holefrag->ofs + holefrag->size); | ||
181 | rb_link_node(&holefrag->rb, NULL, &root->rb_node); | ||
182 | } | ||
183 | rb_insert_color(&holefrag->rb, root); | ||
184 | this = holefrag; | ||
185 | } | ||
186 | |||
187 | if (this) { | ||
188 | /* By definition, the 'this' node has no right-hand child, | ||
189 | because there are no frags with offset greater than it. | ||
190 | So that's where we want to put new fragment */ | ||
191 | dbg_fragtree2("add the new node at the right\n"); | ||
192 | rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); | ||
193 | } else { | ||
194 | dbg_fragtree2("insert the new node at the root of the tree\n"); | ||
195 | rb_link_node(&newfrag->rb, NULL, &root->rb_node); | ||
136 | } | 196 | } |
137 | return NULL; | 197 | rb_insert_color(&newfrag->rb, root); |
198 | |||
199 | return 0; | ||
138 | } | 200 | } |
139 | 201 | ||
140 | /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated | 202 | /* Doesn't set inode->i_size */ |
141 | with this ino, returning the former in order of version */ | 203 | static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *root, struct jffs2_node_frag *newfrag) |
204 | { | ||
205 | struct jffs2_node_frag *this; | ||
206 | uint32_t lastend; | ||
207 | |||
208 | /* Skip all the nodes which are completed before this one starts */ | ||
209 | this = jffs2_lookup_node_frag(root, newfrag->node->ofs); | ||
210 | |||
211 | if (this) { | ||
212 | dbg_fragtree2("lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", | ||
213 | this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this); | ||
214 | lastend = this->ofs + this->size; | ||
215 | } else { | ||
216 | dbg_fragtree2("lookup gave no frag\n"); | ||
217 | lastend = 0; | ||
218 | } | ||
219 | |||
220 | /* See if we ran off the end of the fragtree */ | ||
221 | if (lastend <= newfrag->ofs) { | ||
222 | /* We did */ | ||
223 | |||
224 | /* Check if 'this' node was on the same page as the new node. | ||
225 | If so, both 'this' and the new node get marked REF_NORMAL so | ||
226 | the GC can take a look. | ||
227 | */ | ||
228 | if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { | ||
229 | if (this->node) | ||
230 | mark_ref_normal(this->node->raw); | ||
231 | mark_ref_normal(newfrag->node->raw); | ||
232 | } | ||
233 | |||
234 | return no_overlapping_node(c, root, newfrag, this, lastend); | ||
235 | } | ||
142 | 236 | ||
143 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 237 | if (this->node) |
144 | struct rb_root *tnp, struct jffs2_full_dirent **fdp, | 238 | dbg_fragtree2("dealing with frag %u-%u, phys %#08x(%d).\n", |
145 | uint32_t *highest_version, uint32_t *latest_mctime, | 239 | this->ofs, this->ofs + this->size, |
146 | uint32_t *mctime_ver) | 240 | ref_offset(this->node->raw), ref_flags(this->node->raw)); |
241 | else | ||
242 | dbg_fragtree2("dealing with hole frag %u-%u.\n", | ||
243 | this->ofs, this->ofs + this->size); | ||
244 | |||
245 | /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, | ||
246 | * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs | ||
247 | */ | ||
248 | if (newfrag->ofs > this->ofs) { | ||
249 | /* This node isn't completely obsoleted. The start of it remains valid */ | ||
250 | |||
251 | /* Mark the new node and the partially covered node REF_NORMAL -- let | ||
252 | the GC take a look at them */ | ||
253 | mark_ref_normal(newfrag->node->raw); | ||
254 | if (this->node) | ||
255 | mark_ref_normal(this->node->raw); | ||
256 | |||
257 | if (this->ofs + this->size > newfrag->ofs + newfrag->size) { | ||
258 | /* The new node splits 'this' frag into two */ | ||
259 | struct jffs2_node_frag *newfrag2; | ||
260 | |||
261 | if (this->node) | ||
262 | dbg_fragtree2("split old frag 0x%04x-0x%04x, phys 0x%08x\n", | ||
263 | this->ofs, this->ofs+this->size, ref_offset(this->node->raw)); | ||
264 | else | ||
265 | dbg_fragtree2("split old hole frag 0x%04x-0x%04x\n", | ||
266 | this->ofs, this->ofs+this->size); | ||
267 | |||
268 | /* New second frag pointing to this's node */ | ||
269 | newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size, | ||
270 | this->ofs + this->size - newfrag->ofs - newfrag->size); | ||
271 | if (unlikely(!newfrag2)) | ||
272 | return -ENOMEM; | ||
273 | if (this->node) | ||
274 | this->node->frags++; | ||
275 | |||
276 | /* Adjust size of original 'this' */ | ||
277 | this->size = newfrag->ofs - this->ofs; | ||
278 | |||
279 | /* Now, we know there's no node with offset | ||
280 | greater than this->ofs but smaller than | ||
281 | newfrag2->ofs or newfrag->ofs, for obvious | ||
282 | reasons. So we can do a tree insert from | ||
283 | 'this' to insert newfrag, and a tree insert | ||
284 | from newfrag to insert newfrag2. */ | ||
285 | jffs2_fragtree_insert(newfrag, this); | ||
286 | rb_insert_color(&newfrag->rb, root); | ||
287 | |||
288 | jffs2_fragtree_insert(newfrag2, newfrag); | ||
289 | rb_insert_color(&newfrag2->rb, root); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | /* New node just reduces 'this' frag in size, doesn't split it */ | ||
294 | this->size = newfrag->ofs - this->ofs; | ||
295 | |||
296 | /* Again, we know it lives down here in the tree */ | ||
297 | jffs2_fragtree_insert(newfrag, this); | ||
298 | rb_insert_color(&newfrag->rb, root); | ||
299 | } else { | ||
300 | /* New frag starts at the same point as 'this' used to. Replace | ||
301 | it in the tree without doing a delete and insertion */ | ||
302 | dbg_fragtree2("inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", | ||
303 | newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, this, this->ofs, this->ofs+this->size); | ||
304 | |||
305 | rb_replace_node(&this->rb, &newfrag->rb, root); | ||
306 | |||
307 | if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { | ||
308 | dbg_fragtree2("obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size); | ||
309 | jffs2_obsolete_node_frag(c, this); | ||
310 | } else { | ||
311 | this->ofs += newfrag->size; | ||
312 | this->size -= newfrag->size; | ||
313 | |||
314 | jffs2_fragtree_insert(this, newfrag); | ||
315 | rb_insert_color(&this->rb, root); | ||
316 | return 0; | ||
317 | } | ||
318 | } | ||
319 | /* OK, now we have newfrag added in the correct place in the tree, but | ||
320 | frag_next(newfrag) may be a fragment which is overlapped by it | ||
321 | */ | ||
322 | while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { | ||
323 | /* 'this' frag is obsoleted completely. */ | ||
324 | dbg_fragtree2("obsoleting node frag %p (%x-%x) and removing from tree\n", | ||
325 | this, this->ofs, this->ofs+this->size); | ||
326 | rb_erase(&this->rb, root); | ||
327 | jffs2_obsolete_node_frag(c, this); | ||
328 | } | ||
329 | /* Now we're pointing at the first frag which isn't totally obsoleted by | ||
330 | the new frag */ | ||
331 | |||
332 | if (!this || newfrag->ofs + newfrag->size == this->ofs) | ||
333 | return 0; | ||
334 | |||
335 | /* Still some overlap but we don't need to move it in the tree */ | ||
336 | this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); | ||
337 | this->ofs = newfrag->ofs + newfrag->size; | ||
338 | |||
339 | /* And mark them REF_NORMAL so the GC takes a look at them */ | ||
340 | if (this->node) | ||
341 | mark_ref_normal(this->node->raw); | ||
342 | mark_ref_normal(newfrag->node->raw); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | /* | ||
348 | * Given an inode, probably with existing tree of fragments, add the new node | ||
349 | * to the fragment tree. | ||
350 | */ | ||
351 | int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) | ||
147 | { | 352 | { |
148 | struct jffs2_raw_node_ref *ref, *valid_ref; | 353 | int ret; |
149 | struct jffs2_tmp_dnode_info *tn; | 354 | struct jffs2_node_frag *newfrag; |
150 | struct rb_root ret_tn = RB_ROOT; | ||
151 | struct jffs2_full_dirent *fd, *ret_fd = NULL; | ||
152 | union jffs2_node_union node; | ||
153 | size_t retlen; | ||
154 | int err; | ||
155 | |||
156 | *mctime_ver = 0; | ||
157 | |||
158 | D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino)); | ||
159 | 355 | ||
160 | spin_lock(&c->erase_completion_lock); | 356 | if (unlikely(!fn->size)) |
357 | return 0; | ||
161 | 358 | ||
162 | valid_ref = jffs2_first_valid_node(f->inocache->nodes); | 359 | newfrag = new_fragment(fn, fn->ofs, fn->size); |
360 | if (unlikely(!newfrag)) | ||
361 | return -ENOMEM; | ||
362 | newfrag->node->frags = 1; | ||
163 | 363 | ||
164 | if (!valid_ref && (f->inocache->ino != 1)) | 364 | dbg_fragtree("adding node %#04x-%#04x @0x%08x on flash, newfrag *%p\n", |
165 | printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); | 365 | fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); |
166 | 366 | ||
167 | while (valid_ref) { | 367 | ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); |
168 | /* We can hold a pointer to a non-obsolete node without the spinlock, | 368 | if (unlikely(ret)) |
169 | but _obsolete_ nodes may disappear at any time, if the block | 369 | return ret; |
170 | they're in gets erased. So if we mark 'ref' obsolete while we're | ||
171 | not holding the lock, it can go away immediately. For that reason, | ||
172 | we find the next valid node first, before processing 'ref'. | ||
173 | */ | ||
174 | ref = valid_ref; | ||
175 | valid_ref = jffs2_first_valid_node(ref->next_in_ino); | ||
176 | spin_unlock(&c->erase_completion_lock); | ||
177 | 370 | ||
178 | cond_resched(); | 371 | /* If we now share a page with other nodes, mark either previous |
372 | or next node REF_NORMAL, as appropriate. */ | ||
373 | if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { | ||
374 | struct jffs2_node_frag *prev = frag_prev(newfrag); | ||
375 | |||
376 | mark_ref_normal(fn->raw); | ||
377 | /* If we don't start at zero there's _always_ a previous */ | ||
378 | if (prev->node) | ||
379 | mark_ref_normal(prev->node->raw); | ||
380 | } | ||
381 | |||
382 | if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { | ||
383 | struct jffs2_node_frag *next = frag_next(newfrag); | ||
384 | |||
385 | if (next) { | ||
386 | mark_ref_normal(fn->raw); | ||
387 | if (next->node) | ||
388 | mark_ref_normal(next->node->raw); | ||
389 | } | ||
390 | } | ||
391 | jffs2_dbg_fragtree_paranoia_check_nolock(f); | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * Check the data CRC of the node. | ||
398 | * | ||
399 | * Returns: 0 if the data CRC is correct; | ||
400 | * 1 - if incorrect; | ||
401 | * error code if an error occured. | ||
402 | */ | ||
403 | static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) | ||
404 | { | ||
405 | struct jffs2_raw_node_ref *ref = tn->fn->raw; | ||
406 | int err = 0, pointed = 0; | ||
407 | struct jffs2_eraseblock *jeb; | ||
408 | unsigned char *buffer; | ||
409 | uint32_t crc, ofs, retlen, len; | ||
410 | |||
411 | BUG_ON(tn->csize == 0); | ||
412 | |||
413 | if (!jffs2_is_writebuffered(c)) | ||
414 | goto adj_acc; | ||
415 | |||
416 | /* Calculate how many bytes were already checked */ | ||
417 | ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode); | ||
418 | len = ofs % c->wbuf_pagesize; | ||
419 | if (likely(len)) | ||
420 | len = c->wbuf_pagesize - len; | ||
421 | |||
422 | if (len >= tn->csize) { | ||
423 | dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n", | ||
424 | ref_offset(ref), tn->csize, ofs); | ||
425 | goto adj_acc; | ||
426 | } | ||
427 | |||
428 | ofs += len; | ||
429 | len = tn->csize - len; | ||
430 | |||
431 | dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n", | ||
432 | ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); | ||
433 | |||
434 | #ifndef __ECOS | ||
435 | /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), | ||
436 | * adding and jffs2_flash_read_end() interface. */ | ||
437 | if (c->mtd->point) { | ||
438 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); | ||
439 | if (!err && retlen < tn->csize) { | ||
440 | JFFS2_WARNING("MTD point returned len too short: %u instead of %u.\n", retlen, tn->csize); | ||
441 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | ||
442 | } else if (err) | ||
443 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); | ||
444 | else | ||
445 | pointed = 1; /* succefully pointed to device */ | ||
446 | } | ||
447 | #endif | ||
448 | |||
449 | if (!pointed) { | ||
450 | buffer = kmalloc(len, GFP_KERNEL); | ||
451 | if (unlikely(!buffer)) | ||
452 | return -ENOMEM; | ||
179 | 453 | ||
180 | /* FIXME: point() */ | 454 | /* TODO: this is very frequent pattern, make it a separate |
181 | err = jffs2_flash_read(c, (ref_offset(ref)), | 455 | * routine */ |
182 | min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)), | 456 | err = jffs2_flash_read(c, ofs, len, &retlen, buffer); |
183 | &retlen, (void *)&node); | ||
184 | if (err) { | 457 | if (err) { |
185 | printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref)); | 458 | JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); |
186 | goto free_out; | 459 | goto free_out; |
187 | } | 460 | } |
188 | |||
189 | 461 | ||
190 | /* Check we've managed to read at least the common node header */ | 462 | if (retlen != len) { |
191 | if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) { | 463 | JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ofs, retlen, len); |
192 | printk(KERN_WARNING "short read in get_inode_nodes()\n"); | ||
193 | err = -EIO; | 464 | err = -EIO; |
194 | goto free_out; | 465 | goto free_out; |
195 | } | 466 | } |
196 | 467 | } | |
197 | switch (je16_to_cpu(node.u.nodetype)) { | ||
198 | case JFFS2_NODETYPE_DIRENT: | ||
199 | D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref))); | ||
200 | if (ref_flags(ref) == REF_UNCHECKED) { | ||
201 | printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref)); | ||
202 | BUG(); | ||
203 | } | ||
204 | if (retlen < sizeof(node.d)) { | ||
205 | printk(KERN_WARNING "short read in get_inode_nodes()\n"); | ||
206 | err = -EIO; | ||
207 | goto free_out; | ||
208 | } | ||
209 | /* sanity check */ | ||
210 | if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) { | ||
211 | printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n", | ||
212 | ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen)); | ||
213 | jffs2_mark_node_obsolete(c, ref); | ||
214 | spin_lock(&c->erase_completion_lock); | ||
215 | continue; | ||
216 | } | ||
217 | if (je32_to_cpu(node.d.version) > *highest_version) | ||
218 | *highest_version = je32_to_cpu(node.d.version); | ||
219 | if (ref_obsolete(ref)) { | ||
220 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ | ||
221 | printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n", | ||
222 | ref_offset(ref)); | ||
223 | BUG(); | ||
224 | } | ||
225 | |||
226 | fd = jffs2_alloc_full_dirent(node.d.nsize+1); | ||
227 | if (!fd) { | ||
228 | err = -ENOMEM; | ||
229 | goto free_out; | ||
230 | } | ||
231 | fd->raw = ref; | ||
232 | fd->version = je32_to_cpu(node.d.version); | ||
233 | fd->ino = je32_to_cpu(node.d.ino); | ||
234 | fd->type = node.d.type; | ||
235 | |||
236 | /* Pick out the mctime of the latest dirent */ | ||
237 | if(fd->version > *mctime_ver) { | ||
238 | *mctime_ver = fd->version; | ||
239 | *latest_mctime = je32_to_cpu(node.d.mctime); | ||
240 | } | ||
241 | 468 | ||
242 | /* memcpy as much of the name as possible from the raw | 469 | /* Continue calculating CRC */ |
243 | dirent we've already read from the flash | 470 | crc = crc32(tn->partial_crc, buffer, len); |
244 | */ | 471 | if(!pointed) |
245 | if (retlen > sizeof(struct jffs2_raw_dirent)) | 472 | kfree(buffer); |
246 | memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); | 473 | #ifndef __ECOS |
247 | 474 | else | |
248 | /* Do we need to copy any more of the name directly | 475 | c->mtd->unpoint(c->mtd, buffer, ofs, len); |
249 | from the flash? | 476 | #endif |
250 | */ | ||
251 | if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) { | ||
252 | /* FIXME: point() */ | ||
253 | int already = retlen - sizeof(struct jffs2_raw_dirent); | ||
254 | |||
255 | err = jffs2_flash_read(c, (ref_offset(ref)) + retlen, | ||
256 | node.d.nsize - already, &retlen, &fd->name[already]); | ||
257 | if (!err && retlen != node.d.nsize - already) | ||
258 | err = -EIO; | ||
259 | |||
260 | if (err) { | ||
261 | printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err); | ||
262 | jffs2_free_full_dirent(fd); | ||
263 | goto free_out; | ||
264 | } | ||
265 | } | ||
266 | fd->nhash = full_name_hash(fd->name, node.d.nsize); | ||
267 | fd->next = NULL; | ||
268 | fd->name[node.d.nsize] = '\0'; | ||
269 | /* Wheee. We now have a complete jffs2_full_dirent structure, with | ||
270 | the name in it and everything. Link it into the list | ||
271 | */ | ||
272 | D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino)); | ||
273 | jffs2_add_fd_to_list(c, fd, &ret_fd); | ||
274 | break; | ||
275 | |||
276 | case JFFS2_NODETYPE_INODE: | ||
277 | D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref))); | ||
278 | if (retlen < sizeof(node.i)) { | ||
279 | printk(KERN_WARNING "read too short for dnode\n"); | ||
280 | err = -EIO; | ||
281 | goto free_out; | ||
282 | } | ||
283 | if (je32_to_cpu(node.i.version) > *highest_version) | ||
284 | *highest_version = je32_to_cpu(node.i.version); | ||
285 | D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version)); | ||
286 | |||
287 | if (ref_obsolete(ref)) { | ||
288 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ | ||
289 | printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n", | ||
290 | ref_offset(ref)); | ||
291 | BUG(); | ||
292 | } | ||
293 | 477 | ||
294 | /* If we've never checked the CRCs on this node, check them now. */ | 478 | if (crc != tn->data_crc) { |
295 | if (ref_flags(ref) == REF_UNCHECKED) { | 479 | JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", |
296 | uint32_t crc, len; | 480 | ofs, tn->data_crc, crc); |
297 | struct jffs2_eraseblock *jeb; | 481 | return 1; |
298 | 482 | } | |
299 | crc = crc32(0, &node, sizeof(node.i)-8); | ||
300 | if (crc != je32_to_cpu(node.i.node_crc)) { | ||
301 | printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", | ||
302 | ref_offset(ref), je32_to_cpu(node.i.node_crc), crc); | ||
303 | jffs2_mark_node_obsolete(c, ref); | ||
304 | spin_lock(&c->erase_completion_lock); | ||
305 | continue; | ||
306 | } | ||
307 | |||
308 | /* sanity checks */ | ||
309 | if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) || | ||
310 | PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) { | ||
311 | printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n", | ||
312 | ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino), | ||
313 | je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize), | ||
314 | je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize)); | ||
315 | jffs2_mark_node_obsolete(c, ref); | ||
316 | spin_lock(&c->erase_completion_lock); | ||
317 | continue; | ||
318 | } | ||
319 | 483 | ||
320 | if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) { | 484 | adj_acc: |
321 | unsigned char *buf=NULL; | 485 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; |
322 | uint32_t pointed = 0; | 486 | len = ref_totlen(c, jeb, ref); |
323 | #ifndef __ECOS | 487 | |
324 | if (c->mtd->point) { | 488 | /* |
325 | err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), | 489 | * Mark the node as having been checked and fix the |
326 | &retlen, &buf); | 490 | * accounting accordingly. |
327 | if (!err && retlen < je32_to_cpu(node.i.csize)) { | 491 | */ |
328 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); | 492 | spin_lock(&c->erase_completion_lock); |
329 | c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); | 493 | jeb->used_size += len; |
330 | } else if (err){ | 494 | jeb->unchecked_size -= len; |
331 | D1(printk(KERN_DEBUG "MTD point failed %d\n", err)); | 495 | c->used_size += len; |
332 | } else | 496 | c->unchecked_size -= len; |
333 | pointed = 1; /* succefully pointed to device */ | 497 | spin_unlock(&c->erase_completion_lock); |
334 | } | 498 | |
335 | #endif | 499 | return 0; |
336 | if(!pointed){ | 500 | |
337 | buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL); | 501 | free_out: |
338 | if (!buf) | 502 | if(!pointed) |
339 | return -ENOMEM; | 503 | kfree(buffer); |
340 | |||
341 | err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), | ||
342 | &retlen, buf); | ||
343 | if (!err && retlen != je32_to_cpu(node.i.csize)) | ||
344 | err = -EIO; | ||
345 | if (err) { | ||
346 | kfree(buf); | ||
347 | return err; | ||
348 | } | ||
349 | } | ||
350 | crc = crc32(0, buf, je32_to_cpu(node.i.csize)); | ||
351 | if(!pointed) | ||
352 | kfree(buf); | ||
353 | #ifndef __ECOS | 504 | #ifndef __ECOS |
354 | else | 505 | else |
355 | c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); | 506 | c->mtd->unpoint(c->mtd, buffer, ofs, len); |
356 | #endif | 507 | #endif |
508 | return err; | ||
509 | } | ||
357 | 510 | ||
358 | if (crc != je32_to_cpu(node.i.data_crc)) { | 511 | /* |
359 | printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", | 512 | * Helper function for jffs2_add_older_frag_to_fragtree(). |
360 | ref_offset(ref), je32_to_cpu(node.i.data_crc), crc); | 513 | * |
361 | jffs2_mark_node_obsolete(c, ref); | 514 | * Checks the node if we are in the checking stage. |
362 | spin_lock(&c->erase_completion_lock); | 515 | */ |
363 | continue; | 516 | static inline int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn) |
364 | } | 517 | { |
365 | 518 | int ret; | |
366 | } | ||
367 | 519 | ||
368 | /* Mark the node as having been checked and fix the accounting accordingly */ | 520 | BUG_ON(ref_obsolete(tn->fn->raw)); |
369 | spin_lock(&c->erase_completion_lock); | 521 | |
370 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | 522 | /* We only check the data CRC of unchecked nodes */ |
371 | len = ref_totlen(c, jeb, ref); | 523 | if (ref_flags(tn->fn->raw) != REF_UNCHECKED) |
372 | 524 | return 0; | |
373 | jeb->used_size += len; | 525 | |
374 | jeb->unchecked_size -= len; | 526 | dbg_fragtree2("check node %#04x-%#04x, phys offs %#08x.\n", |
375 | c->used_size += len; | 527 | tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw)); |
376 | c->unchecked_size -= len; | 528 | |
377 | 529 | ret = check_node_data(c, tn); | |
378 | /* If node covers at least a whole page, or if it starts at the | 530 | if (unlikely(ret < 0)) { |
379 | beginning of a page and runs to the end of the file, or if | 531 | JFFS2_ERROR("check_node_data() returned error: %d.\n", |
380 | it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. | 532 | ret); |
381 | 533 | } else if (unlikely(ret > 0)) { | |
382 | If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) | 534 | dbg_fragtree2("CRC error, mark it obsolete.\n"); |
383 | when the overlapping node(s) get added to the tree anyway. | 535 | jffs2_mark_node_obsolete(c, tn->fn->raw); |
384 | */ | 536 | } |
385 | if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) || | 537 | |
386 | ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) && | 538 | return ret; |
387 | (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) { | 539 | } |
388 | D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref))); | 540 | |
389 | ref->flash_offset = ref_offset(ref) | REF_PRISTINE; | 541 | /* |
390 | } else { | 542 | * Helper function for jffs2_add_older_frag_to_fragtree(). |
391 | D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref))); | 543 | * |
392 | ref->flash_offset = ref_offset(ref) | REF_NORMAL; | 544 | * Called when the new fragment that is being inserted |
393 | } | 545 | * splits a hole fragment. |
394 | spin_unlock(&c->erase_completion_lock); | 546 | */ |
547 | static int split_hole(struct jffs2_sb_info *c, struct rb_root *root, | ||
548 | struct jffs2_node_frag *newfrag, struct jffs2_node_frag *hole) | ||
549 | { | ||
550 | dbg_fragtree2("fragment %#04x-%#04x splits the hole %#04x-%#04x\n", | ||
551 | newfrag->ofs, newfrag->ofs + newfrag->size, hole->ofs, hole->ofs + hole->size); | ||
552 | |||
553 | if (hole->ofs == newfrag->ofs) { | ||
554 | /* | ||
555 | * Well, the new fragment actually starts at the same offset as | ||
556 | * the hole. | ||
557 | */ | ||
558 | if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) { | ||
559 | /* | ||
560 | * We replace the overlapped left part of the hole by | ||
561 | * the new node. | ||
562 | */ | ||
563 | |||
564 | dbg_fragtree2("insert fragment %#04x-%#04x and cut the left part of the hole\n", | ||
565 | newfrag->ofs, newfrag->ofs + newfrag->size); | ||
566 | rb_replace_node(&hole->rb, &newfrag->rb, root); | ||
567 | |||
568 | hole->ofs += newfrag->size; | ||
569 | hole->size -= newfrag->size; | ||
570 | |||
571 | /* | ||
572 | * We know that 'hole' should be the right hand | ||
573 | * fragment. | ||
574 | */ | ||
575 | jffs2_fragtree_insert(hole, newfrag); | ||
576 | rb_insert_color(&hole->rb, root); | ||
577 | } else { | ||
578 | /* | ||
579 | * Ah, the new fragment is of the same size as the hole. | ||
580 | * Relace the hole by it. | ||
581 | */ | ||
582 | dbg_fragtree2("insert fragment %#04x-%#04x and overwrite hole\n", | ||
583 | newfrag->ofs, newfrag->ofs + newfrag->size); | ||
584 | rb_replace_node(&hole->rb, &newfrag->rb, root); | ||
585 | jffs2_free_node_frag(hole); | ||
586 | } | ||
587 | } else { | ||
588 | /* The new fragment lefts some hole space at the left */ | ||
589 | |||
590 | struct jffs2_node_frag * newfrag2 = NULL; | ||
591 | |||
592 | if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) { | ||
593 | /* The new frag also lefts some space at the right */ | ||
594 | newfrag2 = new_fragment(NULL, newfrag->ofs + | ||
595 | newfrag->size, hole->ofs + hole->size | ||
596 | - newfrag->ofs - newfrag->size); | ||
597 | if (unlikely(!newfrag2)) { | ||
598 | jffs2_free_node_frag(newfrag); | ||
599 | return -ENOMEM; | ||
395 | } | 600 | } |
601 | } | ||
602 | |||
603 | hole->size = newfrag->ofs - hole->ofs; | ||
604 | dbg_fragtree2("left the hole %#04x-%#04x at the left and inserd fragment %#04x-%#04x\n", | ||
605 | hole->ofs, hole->ofs + hole->size, newfrag->ofs, newfrag->ofs + newfrag->size); | ||
606 | |||
607 | jffs2_fragtree_insert(newfrag, hole); | ||
608 | rb_insert_color(&newfrag->rb, root); | ||
609 | |||
610 | if (newfrag2) { | ||
611 | dbg_fragtree2("left the hole %#04x-%#04x at the right\n", | ||
612 | newfrag2->ofs, newfrag2->ofs + newfrag2->size); | ||
613 | jffs2_fragtree_insert(newfrag2, newfrag); | ||
614 | rb_insert_color(&newfrag2->rb, root); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * This function is used when we build inode. It expects the nodes are passed | ||
623 | * in the decreasing version order. The whole point of this is to improve the | ||
624 | * inodes checking on NAND: we check the nodes' data CRC only when they are not | ||
625 | * obsoleted. Previously, add_frag_to_fragtree() function was used and | ||
626 | * nodes were passed to it in the increasing version ordes and CRCs of all | ||
627 | * nodes were checked. | ||
628 | * | ||
629 | * Note: tn->fn->size shouldn't be zero. | ||
630 | * | ||
631 | * Returns 0 if the node was inserted | ||
632 | * 1 if it wasn't inserted (since it is obsolete) | ||
633 | * < 0 an if error occured | ||
634 | */ | ||
635 | int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | ||
636 | struct jffs2_tmp_dnode_info *tn) | ||
637 | { | ||
638 | struct jffs2_node_frag *this, *newfrag; | ||
639 | uint32_t lastend; | ||
640 | struct jffs2_full_dnode *fn = tn->fn; | ||
641 | struct rb_root *root = &f->fragtree; | ||
642 | uint32_t fn_size = fn->size, fn_ofs = fn->ofs; | ||
643 | int err, checked = 0; | ||
644 | int ref_flag; | ||
645 | |||
646 | dbg_fragtree("insert fragment %#04x-%#04x, ver %u\n", fn_ofs, fn_ofs + fn_size, tn->version); | ||
647 | |||
648 | /* Skip all the nodes which are completed before this one starts */ | ||
649 | this = jffs2_lookup_node_frag(root, fn_ofs); | ||
650 | if (this) | ||
651 | dbg_fragtree2("'this' found %#04x-%#04x (%s)\n", this->ofs, this->ofs + this->size, this->node ? "data" : "hole"); | ||
652 | |||
653 | if (this) | ||
654 | lastend = this->ofs + this->size; | ||
655 | else | ||
656 | lastend = 0; | ||
657 | |||
658 | /* Detect the preliminary type of node */ | ||
659 | if (fn->size >= PAGE_CACHE_SIZE) | ||
660 | ref_flag = REF_PRISTINE; | ||
661 | else | ||
662 | ref_flag = REF_NORMAL; | ||
663 | |||
664 | /* See if we ran off the end of the root */ | ||
665 | if (lastend <= fn_ofs) { | ||
666 | /* We did */ | ||
667 | |||
668 | /* | ||
669 | * We are going to insert the new node into the | ||
670 | * fragment tree, so check it. | ||
671 | */ | ||
672 | err = check_node(c, f, tn); | ||
673 | if (err != 0) | ||
674 | return err; | ||
675 | |||
676 | fn->frags = 1; | ||
677 | |||
678 | newfrag = new_fragment(fn, fn_ofs, fn_size); | ||
679 | if (unlikely(!newfrag)) | ||
680 | return -ENOMEM; | ||
681 | |||
682 | err = no_overlapping_node(c, root, newfrag, this, lastend); | ||
683 | if (unlikely(err != 0)) { | ||
684 | jffs2_free_node_frag(newfrag); | ||
685 | return err; | ||
686 | } | ||
687 | |||
688 | goto out_ok; | ||
689 | } | ||
396 | 690 | ||
397 | tn = jffs2_alloc_tmp_dnode_info(); | 691 | fn->frags = 0; |
398 | if (!tn) { | 692 | |
399 | D1(printk(KERN_DEBUG "alloc tn failed\n")); | 693 | while (1) { |
400 | err = -ENOMEM; | 694 | /* |
401 | goto free_out; | 695 | * Here we have: |
696 | * fn_ofs < this->ofs + this->size && fn_ofs >= this->ofs. | ||
697 | * | ||
698 | * Remember, 'this' has higher version, any non-hole node | ||
699 | * which is already in the fragtree is newer then the newly | ||
700 | * inserted. | ||
701 | */ | ||
702 | if (!this->node) { | ||
703 | /* | ||
704 | * 'this' is the hole fragment, so at least the | ||
705 | * beginning of the new fragment is valid. | ||
706 | */ | ||
707 | |||
708 | /* | ||
709 | * We are going to insert the new node into the | ||
710 | * fragment tree, so check it. | ||
711 | */ | ||
712 | if (!checked) { | ||
713 | err = check_node(c, f, tn); | ||
714 | if (unlikely(err != 0)) | ||
715 | return err; | ||
716 | checked = 1; | ||
402 | } | 717 | } |
403 | 718 | ||
404 | tn->fn = jffs2_alloc_full_dnode(); | 719 | if (this->ofs + this->size >= fn_ofs + fn_size) { |
405 | if (!tn->fn) { | 720 | /* We split the hole on two parts */ |
406 | D1(printk(KERN_DEBUG "alloc fn failed\n")); | 721 | |
407 | err = -ENOMEM; | 722 | fn->frags += 1; |
408 | jffs2_free_tmp_dnode_info(tn); | 723 | newfrag = new_fragment(fn, fn_ofs, fn_size); |
409 | goto free_out; | 724 | if (unlikely(!newfrag)) |
725 | return -ENOMEM; | ||
726 | |||
727 | err = split_hole(c, root, newfrag, this); | ||
728 | if (unlikely(err)) | ||
729 | return err; | ||
730 | goto out_ok; | ||
410 | } | 731 | } |
411 | tn->version = je32_to_cpu(node.i.version); | 732 | |
412 | tn->fn->ofs = je32_to_cpu(node.i.offset); | 733 | /* |
413 | /* There was a bug where we wrote hole nodes out with | 734 | * The beginning of the new fragment is valid since it |
414 | csize/dsize swapped. Deal with it */ | 735 | * overlaps the hole node. |
415 | if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize)) | 736 | */ |
416 | tn->fn->size = je32_to_cpu(node.i.csize); | 737 | |
417 | else // normal case... | 738 | ref_flag = REF_NORMAL; |
418 | tn->fn->size = je32_to_cpu(node.i.dsize); | 739 | |
419 | tn->fn->raw = ref; | 740 | fn->frags += 1; |
420 | D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", | 741 | newfrag = new_fragment(fn, fn_ofs, |
421 | ref_offset(ref), je32_to_cpu(node.i.version), | 742 | this->ofs + this->size - fn_ofs); |
422 | je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize))); | 743 | if (unlikely(!newfrag)) |
423 | jffs2_add_tn_to_tree(tn, &ret_tn); | 744 | return -ENOMEM; |
424 | break; | 745 | |
425 | 746 | if (fn_ofs == this->ofs) { | |
426 | default: | 747 | /* |
427 | if (ref_flags(ref) == REF_UNCHECKED) { | 748 | * The new node starts at the same offset as |
428 | struct jffs2_eraseblock *jeb; | 749 | * the hole and supersieds the hole. |
429 | uint32_t len; | 750 | */ |
430 | 751 | dbg_fragtree2("add the new fragment instead of hole %#04x-%#04x, refcnt %d\n", | |
431 | printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n", | 752 | fn_ofs, fn_ofs + this->ofs + this->size - fn_ofs, fn->frags); |
432 | je16_to_cpu(node.u.nodetype), ref_offset(ref)); | 753 | |
433 | 754 | rb_replace_node(&this->rb, &newfrag->rb, root); | |
434 | /* Mark the node as having been checked and fix the accounting accordingly */ | 755 | jffs2_free_node_frag(this); |
435 | spin_lock(&c->erase_completion_lock); | 756 | } else { |
436 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | 757 | /* |
437 | len = ref_totlen(c, jeb, ref); | 758 | * The hole becomes shorter as its right part |
438 | 759 | * is supersieded by the new fragment. | |
439 | jeb->used_size += len; | 760 | */ |
440 | jeb->unchecked_size -= len; | 761 | dbg_fragtree2("reduce size of hole %#04x-%#04x to %#04x-%#04x\n", |
441 | c->used_size += len; | 762 | this->ofs, this->ofs + this->size, this->ofs, this->ofs + this->size - newfrag->size); |
442 | c->unchecked_size -= len; | 763 | |
443 | 764 | dbg_fragtree2("add new fragment %#04x-%#04x, refcnt %d\n", fn_ofs, | |
444 | mark_ref_normal(ref); | 765 | fn_ofs + this->ofs + this->size - fn_ofs, fn->frags); |
445 | spin_unlock(&c->erase_completion_lock); | 766 | |
767 | this->size -= newfrag->size; | ||
768 | jffs2_fragtree_insert(newfrag, this); | ||
769 | rb_insert_color(&newfrag->rb, root); | ||
446 | } | 770 | } |
447 | node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype)); | 771 | |
448 | if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) { | 772 | fn_ofs += newfrag->size; |
449 | /* Hmmm. This should have been caught at scan time. */ | 773 | fn_size -= newfrag->size; |
450 | printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n", | 774 | this = rb_entry(rb_next(&newfrag->rb), |
451 | ref_offset(ref)); | 775 | struct jffs2_node_frag, rb); |
452 | printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n", | 776 | |
453 | je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen), | 777 | dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n", |
454 | je32_to_cpu(node.u.hdr_crc)); | 778 | this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)"); |
455 | jffs2_mark_node_obsolete(c, ref); | 779 | } |
456 | } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) { | 780 | |
457 | case JFFS2_FEATURE_INCOMPAT: | 781 | /* |
458 | printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); | 782 | * 'This' node is not the hole so it obsoletes the new fragment |
459 | /* EEP */ | 783 | * either fully or partially. |
460 | BUG(); | 784 | */ |
461 | break; | 785 | if (this->ofs + this->size >= fn_ofs + fn_size) { |
462 | case JFFS2_FEATURE_ROCOMPAT: | 786 | /* The new node is obsolete, drop it */ |
463 | printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); | 787 | if (fn->frags == 0) { |
464 | if (!(c->flags & JFFS2_SB_FLAG_RO)) | 788 | dbg_fragtree2("%#04x-%#04x is obsolete, mark it obsolete\n", fn_ofs, fn_ofs + fn_size); |
465 | BUG(); | 789 | ref_flag = REF_OBSOLETE; |
466 | break; | ||
467 | case JFFS2_FEATURE_RWCOMPAT_COPY: | ||
468 | printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); | ||
469 | break; | ||
470 | case JFFS2_FEATURE_RWCOMPAT_DELETE: | ||
471 | printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); | ||
472 | jffs2_mark_node_obsolete(c, ref); | ||
473 | break; | ||
474 | } | 790 | } |
791 | goto out_ok; | ||
792 | } else { | ||
793 | struct jffs2_node_frag *new_this; | ||
794 | |||
795 | /* 'This' node obsoletes the beginning of the new node */ | ||
796 | dbg_fragtree2("the beginning %#04x-%#04x is obsolete\n", fn_ofs, this->ofs + this->size); | ||
797 | |||
798 | ref_flag = REF_NORMAL; | ||
799 | |||
800 | fn_size -= this->ofs + this->size - fn_ofs; | ||
801 | fn_ofs = this->ofs + this->size; | ||
802 | dbg_fragtree2("now considering %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size); | ||
803 | |||
804 | new_this = rb_entry(rb_next(&this->rb), struct jffs2_node_frag, rb); | ||
805 | if (!new_this) { | ||
806 | /* | ||
807 | * There is no next fragment. Add the rest of | ||
808 | * the new node as the right-hand child. | ||
809 | */ | ||
810 | if (!checked) { | ||
811 | err = check_node(c, f, tn); | ||
812 | if (unlikely(err != 0)) | ||
813 | return err; | ||
814 | checked = 1; | ||
815 | } | ||
475 | 816 | ||
817 | fn->frags += 1; | ||
818 | newfrag = new_fragment(fn, fn_ofs, fn_size); | ||
819 | if (unlikely(!newfrag)) | ||
820 | return -ENOMEM; | ||
821 | |||
822 | dbg_fragtree2("there are no more fragments, insert %#04x-%#04x\n", | ||
823 | newfrag->ofs, newfrag->ofs + newfrag->size); | ||
824 | rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); | ||
825 | rb_insert_color(&newfrag->rb, root); | ||
826 | goto out_ok; | ||
827 | } else { | ||
828 | this = new_this; | ||
829 | dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n", | ||
830 | this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)"); | ||
831 | } | ||
476 | } | 832 | } |
477 | spin_lock(&c->erase_completion_lock); | 833 | } |
834 | |||
835 | out_ok: | ||
836 | BUG_ON(fn->size < PAGE_CACHE_SIZE && ref_flag == REF_PRISTINE); | ||
478 | 837 | ||
838 | if (ref_flag == REF_OBSOLETE) { | ||
839 | dbg_fragtree2("the node is obsolete now\n"); | ||
840 | /* jffs2_mark_node_obsolete() will adjust space accounting */ | ||
841 | jffs2_mark_node_obsolete(c, fn->raw); | ||
842 | return 1; | ||
479 | } | 843 | } |
844 | |||
845 | dbg_fragtree2("the node is \"%s\" now\n", ref_flag == REF_NORMAL ? "REF_NORMAL" : "REF_PRISTINE"); | ||
846 | |||
847 | /* Space accounting was adjusted at check_node_data() */ | ||
848 | spin_lock(&c->erase_completion_lock); | ||
849 | fn->raw->flash_offset = ref_offset(fn->raw) | ref_flag; | ||
480 | spin_unlock(&c->erase_completion_lock); | 850 | spin_unlock(&c->erase_completion_lock); |
481 | *tnp = ret_tn; | ||
482 | *fdp = ret_fd; | ||
483 | 851 | ||
484 | return 0; | 852 | return 0; |
485 | |||
486 | free_out: | ||
487 | jffs2_free_tmp_dnode_info_list(&ret_tn); | ||
488 | jffs2_free_full_dirent_list(ret_fd); | ||
489 | return err; | ||
490 | } | 853 | } |
491 | 854 | ||
492 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) | 855 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) |
@@ -499,24 +862,21 @@ void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache | |||
499 | 862 | ||
500 | /* During mount, this needs no locking. During normal operation, its | 863 | /* During mount, this needs no locking. During normal operation, its |
501 | callers want to do other stuff while still holding the inocache_lock. | 864 | callers want to do other stuff while still holding the inocache_lock. |
502 | Rather than introducing special case get_ino_cache functions or | 865 | Rather than introducing special case get_ino_cache functions or |
503 | callbacks, we just let the caller do the locking itself. */ | 866 | callbacks, we just let the caller do the locking itself. */ |
504 | 867 | ||
505 | struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) | 868 | struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) |
506 | { | 869 | { |
507 | struct jffs2_inode_cache *ret; | 870 | struct jffs2_inode_cache *ret; |
508 | 871 | ||
509 | D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino)); | ||
510 | |||
511 | ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; | 872 | ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; |
512 | while (ret && ret->ino < ino) { | 873 | while (ret && ret->ino < ino) { |
513 | ret = ret->next; | 874 | ret = ret->next; |
514 | } | 875 | } |
515 | 876 | ||
516 | if (ret && ret->ino != ino) | 877 | if (ret && ret->ino != ino) |
517 | ret = NULL; | 878 | ret = NULL; |
518 | 879 | ||
519 | D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino)); | ||
520 | return ret; | 880 | return ret; |
521 | } | 881 | } |
522 | 882 | ||
@@ -528,7 +888,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new | |||
528 | if (!new->ino) | 888 | if (!new->ino) |
529 | new->ino = ++c->highest_ino; | 889 | new->ino = ++c->highest_ino; |
530 | 890 | ||
531 | D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); | 891 | dbg_inocache("add %p (ino #%u)\n", new, new->ino); |
532 | 892 | ||
533 | prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; | 893 | prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; |
534 | 894 | ||
@@ -544,11 +904,12 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new | |||
544 | void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) | 904 | void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) |
545 | { | 905 | { |
546 | struct jffs2_inode_cache **prev; | 906 | struct jffs2_inode_cache **prev; |
547 | D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); | 907 | |
908 | dbg_inocache("del %p (ino #%u)\n", old, old->ino); | ||
548 | spin_lock(&c->inocache_lock); | 909 | spin_lock(&c->inocache_lock); |
549 | 910 | ||
550 | prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; | 911 | prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; |
551 | 912 | ||
552 | while ((*prev) && (*prev)->ino < old->ino) { | 913 | while ((*prev) && (*prev)->ino < old->ino) { |
553 | prev = &(*prev)->next; | 914 | prev = &(*prev)->next; |
554 | } | 915 | } |
@@ -558,7 +919,7 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) | |||
558 | 919 | ||
559 | /* Free it now unless it's in READING or CLEARING state, which | 920 | /* Free it now unless it's in READING or CLEARING state, which |
560 | are the transitions upon read_inode() and clear_inode(). The | 921 | are the transitions upon read_inode() and clear_inode(). The |
561 | rest of the time we know nobody else is looking at it, and | 922 | rest of the time we know nobody else is looking at it, and |
562 | if it's held by read_inode() or clear_inode() they'll free it | 923 | if it's held by read_inode() or clear_inode() they'll free it |
563 | for themselves. */ | 924 | for themselves. */ |
564 | if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) | 925 | if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) |
@@ -571,7 +932,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) | |||
571 | { | 932 | { |
572 | int i; | 933 | int i; |
573 | struct jffs2_inode_cache *this, *next; | 934 | struct jffs2_inode_cache *this, *next; |
574 | 935 | ||
575 | for (i=0; i<INOCACHE_HASHSIZE; i++) { | 936 | for (i=0; i<INOCACHE_HASHSIZE; i++) { |
576 | this = c->inocache_list[i]; | 937 | this = c->inocache_list[i]; |
577 | while (this) { | 938 | while (this) { |
@@ -598,38 +959,30 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) | |||
598 | c->blocks[i].first_node = c->blocks[i].last_node = NULL; | 959 | c->blocks[i].first_node = c->blocks[i].last_node = NULL; |
599 | } | 960 | } |
600 | } | 961 | } |
601 | 962 | ||
602 | struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) | 963 | struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) |
603 | { | 964 | { |
604 | /* The common case in lookup is that there will be a node | 965 | /* The common case in lookup is that there will be a node |
605 | which precisely matches. So we go looking for that first */ | 966 | which precisely matches. So we go looking for that first */ |
606 | struct rb_node *next; | 967 | struct rb_node *next; |
607 | struct jffs2_node_frag *prev = NULL; | 968 | struct jffs2_node_frag *prev = NULL; |
608 | struct jffs2_node_frag *frag = NULL; | 969 | struct jffs2_node_frag *frag = NULL; |
609 | 970 | ||
610 | D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset)); | 971 | dbg_fragtree2("root %p, offset %d\n", fragtree, offset); |
611 | 972 | ||
612 | next = fragtree->rb_node; | 973 | next = fragtree->rb_node; |
613 | 974 | ||
614 | while(next) { | 975 | while(next) { |
615 | frag = rb_entry(next, struct jffs2_node_frag, rb); | 976 | frag = rb_entry(next, struct jffs2_node_frag, rb); |
616 | 977 | ||
617 | D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n", | ||
618 | frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right)); | ||
619 | if (frag->ofs + frag->size <= offset) { | 978 | if (frag->ofs + frag->size <= offset) { |
620 | D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n", | ||
621 | frag->ofs, frag->ofs+frag->size)); | ||
622 | /* Remember the closest smaller match on the way down */ | 979 | /* Remember the closest smaller match on the way down */ |
623 | if (!prev || frag->ofs > prev->ofs) | 980 | if (!prev || frag->ofs > prev->ofs) |
624 | prev = frag; | 981 | prev = frag; |
625 | next = frag->rb.rb_right; | 982 | next = frag->rb.rb_right; |
626 | } else if (frag->ofs > offset) { | 983 | } else if (frag->ofs > offset) { |
627 | D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n", | ||
628 | frag->ofs, frag->ofs+frag->size)); | ||
629 | next = frag->rb.rb_left; | 984 | next = frag->rb.rb_left; |
630 | } else { | 985 | } else { |
631 | D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n", | ||
632 | frag->ofs, frag->ofs+frag->size)); | ||
633 | return frag; | 986 | return frag; |
634 | } | 987 | } |
635 | } | 988 | } |
@@ -638,11 +991,11 @@ struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_ | |||
638 | and return the closest smaller one */ | 991 | and return the closest smaller one */ |
639 | 992 | ||
640 | if (prev) | 993 | if (prev) |
641 | D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n", | 994 | dbg_fragtree2("no match. Returning frag %#04x-%#04x, closest previous\n", |
642 | prev->ofs, prev->ofs+prev->size)); | 995 | prev->ofs, prev->ofs+prev->size); |
643 | else | 996 | else |
644 | D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n")); | 997 | dbg_fragtree2("returning NULL, empty fragtree\n"); |
645 | 998 | ||
646 | return prev; | 999 | return prev; |
647 | } | 1000 | } |
648 | 1001 | ||
@@ -656,39 +1009,32 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) | |||
656 | if (!root->rb_node) | 1009 | if (!root->rb_node) |
657 | return; | 1010 | return; |
658 | 1011 | ||
659 | frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb)); | 1012 | dbg_fragtree("killing\n"); |
660 | 1013 | ||
1014 | frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb)); | ||
661 | while(frag) { | 1015 | while(frag) { |
662 | if (frag->rb.rb_left) { | 1016 | if (frag->rb.rb_left) { |
663 | D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n", | ||
664 | frag, frag->ofs, frag->ofs+frag->size)); | ||
665 | frag = frag_left(frag); | 1017 | frag = frag_left(frag); |
666 | continue; | 1018 | continue; |
667 | } | 1019 | } |
668 | if (frag->rb.rb_right) { | 1020 | if (frag->rb.rb_right) { |
669 | D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n", | ||
670 | frag, frag->ofs, frag->ofs+frag->size)); | ||
671 | frag = frag_right(frag); | 1021 | frag = frag_right(frag); |
672 | continue; | 1022 | continue; |
673 | } | 1023 | } |
674 | 1024 | ||
675 | D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n", | ||
676 | frag->ofs, frag->ofs+frag->size, frag->node, | ||
677 | frag->node?frag->node->frags:0)); | ||
678 | |||
679 | if (frag->node && !(--frag->node->frags)) { | 1025 | if (frag->node && !(--frag->node->frags)) { |
680 | /* Not a hole, and it's the final remaining frag | 1026 | /* Not a hole, and it's the final remaining frag |
681 | of this node. Free the node */ | 1027 | of this node. Free the node */ |
682 | if (c) | 1028 | if (c) |
683 | jffs2_mark_node_obsolete(c, frag->node->raw); | 1029 | jffs2_mark_node_obsolete(c, frag->node->raw); |
684 | 1030 | ||
685 | jffs2_free_full_dnode(frag->node); | 1031 | jffs2_free_full_dnode(frag->node); |
686 | } | 1032 | } |
687 | parent = frag_parent(frag); | 1033 | parent = frag_parent(frag); |
688 | if (parent) { | 1034 | if (parent) { |
689 | if (frag_left(parent) == frag) | 1035 | if (frag_left(parent) == frag) |
690 | parent->rb.rb_left = NULL; | 1036 | parent->rb.rb_left = NULL; |
691 | else | 1037 | else |
692 | parent->rb.rb_right = NULL; | 1038 | parent->rb.rb_right = NULL; |
693 | } | 1039 | } |
694 | 1040 | ||
@@ -698,29 +1044,3 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) | |||
698 | cond_resched(); | 1044 | cond_resched(); |
699 | } | 1045 | } |
700 | } | 1046 | } |
701 | |||
702 | void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) | ||
703 | { | ||
704 | struct rb_node *parent = &base->rb; | ||
705 | struct rb_node **link = &parent; | ||
706 | |||
707 | D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag, | ||
708 | newfrag->ofs, newfrag->ofs+newfrag->size, base)); | ||
709 | |||
710 | while (*link) { | ||
711 | parent = *link; | ||
712 | base = rb_entry(parent, struct jffs2_node_frag, rb); | ||
713 | |||
714 | D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs)); | ||
715 | if (newfrag->ofs > base->ofs) | ||
716 | link = &base->rb.rb_right; | ||
717 | else if (newfrag->ofs < base->ofs) | ||
718 | link = &base->rb.rb_left; | ||
719 | else { | ||
720 | printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); | ||
721 | BUG(); | ||
722 | } | ||
723 | } | ||
724 | |||
725 | rb_link_node(&newfrag->rb, &base->rb, link); | ||
726 | } | ||
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index b34c397909ef..23a67bb3052f 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: nodelist.h,v 1.131 2005/07/05 21:03:07 dwmw2 Exp $ | 10 | * $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -20,30 +20,15 @@ | |||
20 | #include <linux/jffs2.h> | 20 | #include <linux/jffs2.h> |
21 | #include <linux/jffs2_fs_sb.h> | 21 | #include <linux/jffs2_fs_sb.h> |
22 | #include <linux/jffs2_fs_i.h> | 22 | #include <linux/jffs2_fs_i.h> |
23 | #include "summary.h" | ||
23 | 24 | ||
24 | #ifdef __ECOS | 25 | #ifdef __ECOS |
25 | #include "os-ecos.h" | 26 | #include "os-ecos.h" |
26 | #else | 27 | #else |
27 | #include <linux/mtd/compatmac.h> /* For min/max in older kernels */ | 28 | #include <linux/mtd/compatmac.h> /* For compatibility with older kernels */ |
28 | #include "os-linux.h" | 29 | #include "os-linux.h" |
29 | #endif | 30 | #endif |
30 | 31 | ||
31 | #ifndef CONFIG_JFFS2_FS_DEBUG | ||
32 | #define CONFIG_JFFS2_FS_DEBUG 1 | ||
33 | #endif | ||
34 | |||
35 | #if CONFIG_JFFS2_FS_DEBUG > 0 | ||
36 | #define D1(x) x | ||
37 | #else | ||
38 | #define D1(x) | ||
39 | #endif | ||
40 | |||
41 | #if CONFIG_JFFS2_FS_DEBUG > 1 | ||
42 | #define D2(x) x | ||
43 | #else | ||
44 | #define D2(x) | ||
45 | #endif | ||
46 | |||
47 | #define JFFS2_NATIVE_ENDIAN | 32 | #define JFFS2_NATIVE_ENDIAN |
48 | 33 | ||
49 | /* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from | 34 | /* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from |
@@ -73,14 +58,17 @@ | |||
73 | #define je16_to_cpu(x) (le16_to_cpu(x.v16)) | 58 | #define je16_to_cpu(x) (le16_to_cpu(x.v16)) |
74 | #define je32_to_cpu(x) (le32_to_cpu(x.v32)) | 59 | #define je32_to_cpu(x) (le32_to_cpu(x.v32)) |
75 | #define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) | 60 | #define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) |
76 | #else | 61 | #else |
77 | #error wibble | 62 | #error wibble |
78 | #endif | 63 | #endif |
79 | 64 | ||
65 | /* The minimal node header size */ | ||
66 | #define JFFS2_MIN_NODE_HEADER sizeof(struct jffs2_raw_dirent) | ||
67 | |||
80 | /* | 68 | /* |
81 | This is all we need to keep in-core for each raw node during normal | 69 | This is all we need to keep in-core for each raw node during normal |
82 | operation. As and when we do read_inode on a particular inode, we can | 70 | operation. As and when we do read_inode on a particular inode, we can |
83 | scan the nodes which are listed for it and build up a proper map of | 71 | scan the nodes which are listed for it and build up a proper map of |
84 | which nodes are currently valid. JFFSv1 always used to keep that whole | 72 | which nodes are currently valid. JFFSv1 always used to keep that whole |
85 | map in core for each inode. | 73 | map in core for each inode. |
86 | */ | 74 | */ |
@@ -97,7 +85,7 @@ struct jffs2_raw_node_ref | |||
97 | 85 | ||
98 | /* flash_offset & 3 always has to be zero, because nodes are | 86 | /* flash_offset & 3 always has to be zero, because nodes are |
99 | always aligned at 4 bytes. So we have a couple of extra bits | 87 | always aligned at 4 bytes. So we have a couple of extra bits |
100 | to play with, which indicate the node's status; see below: */ | 88 | to play with, which indicate the node's status; see below: */ |
101 | #define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ | 89 | #define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ |
102 | #define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */ | 90 | #define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */ |
103 | #define REF_PRISTINE 2 /* Completely clean. GC without looking */ | 91 | #define REF_PRISTINE 2 /* Completely clean. GC without looking */ |
@@ -110,7 +98,7 @@ struct jffs2_raw_node_ref | |||
110 | /* For each inode in the filesystem, we need to keep a record of | 98 | /* For each inode in the filesystem, we need to keep a record of |
111 | nlink, because it would be a PITA to scan the whole directory tree | 99 | nlink, because it would be a PITA to scan the whole directory tree |
112 | at read_inode() time to calculate it, and to keep sufficient information | 100 | at read_inode() time to calculate it, and to keep sufficient information |
113 | in the raw_node_ref (basically both parent and child inode number for | 101 | in the raw_node_ref (basically both parent and child inode number for |
114 | dirent nodes) would take more space than this does. We also keep | 102 | dirent nodes) would take more space than this does. We also keep |
115 | a pointer to the first physical node which is part of this inode, too. | 103 | a pointer to the first physical node which is part of this inode, too. |
116 | */ | 104 | */ |
@@ -140,7 +128,7 @@ struct jffs2_inode_cache { | |||
140 | #define INOCACHE_HASHSIZE 128 | 128 | #define INOCACHE_HASHSIZE 128 |
141 | 129 | ||
142 | /* | 130 | /* |
143 | Larger representation of a raw node, kept in-core only when the | 131 | Larger representation of a raw node, kept in-core only when the |
144 | struct inode for this particular ino is instantiated. | 132 | struct inode for this particular ino is instantiated. |
145 | */ | 133 | */ |
146 | 134 | ||
@@ -150,11 +138,11 @@ struct jffs2_full_dnode | |||
150 | uint32_t ofs; /* The offset to which the data of this node belongs */ | 138 | uint32_t ofs; /* The offset to which the data of this node belongs */ |
151 | uint32_t size; | 139 | uint32_t size; |
152 | uint32_t frags; /* Number of fragments which currently refer | 140 | uint32_t frags; /* Number of fragments which currently refer |
153 | to this node. When this reaches zero, | 141 | to this node. When this reaches zero, |
154 | the node is obsolete. */ | 142 | the node is obsolete. */ |
155 | }; | 143 | }; |
156 | 144 | ||
157 | /* | 145 | /* |
158 | Even larger representation of a raw node, kept in-core only while | 146 | Even larger representation of a raw node, kept in-core only while |
159 | we're actually building up the original map of which nodes go where, | 147 | we're actually building up the original map of which nodes go where, |
160 | in read_inode() | 148 | in read_inode() |
@@ -164,7 +152,10 @@ struct jffs2_tmp_dnode_info | |||
164 | struct rb_node rb; | 152 | struct rb_node rb; |
165 | struct jffs2_full_dnode *fn; | 153 | struct jffs2_full_dnode *fn; |
166 | uint32_t version; | 154 | uint32_t version; |
167 | }; | 155 | uint32_t data_crc; |
156 | uint32_t partial_crc; | ||
157 | uint32_t csize; | ||
158 | }; | ||
168 | 159 | ||
169 | struct jffs2_full_dirent | 160 | struct jffs2_full_dirent |
170 | { | 161 | { |
@@ -178,7 +169,7 @@ struct jffs2_full_dirent | |||
178 | }; | 169 | }; |
179 | 170 | ||
180 | /* | 171 | /* |
181 | Fragments - used to build a map of which raw node to obtain | 172 | Fragments - used to build a map of which raw node to obtain |
182 | data from for each part of the ino | 173 | data from for each part of the ino |
183 | */ | 174 | */ |
184 | struct jffs2_node_frag | 175 | struct jffs2_node_frag |
@@ -207,86 +198,18 @@ struct jffs2_eraseblock | |||
207 | struct jffs2_raw_node_ref *gc_node; /* Next node to be garbage collected */ | 198 | struct jffs2_raw_node_ref *gc_node; /* Next node to be garbage collected */ |
208 | }; | 199 | }; |
209 | 200 | ||
210 | #define ACCT_SANITY_CHECK(c, jeb) do { \ | 201 | static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c) |
211 | struct jffs2_eraseblock *___j = jeb; \ | ||
212 | if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \ | ||
213 | printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \ | ||
214 | printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \ | ||
215 | ___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \ | ||
216 | BUG(); \ | ||
217 | } \ | ||
218 | if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \ | ||
219 | printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \ | ||
220 | printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x + wasted %08x + unchecked %08x != total %08x\n", \ | ||
221 | c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->wasted_size, c->unchecked_size, c->flash_size); \ | ||
222 | BUG(); \ | ||
223 | } \ | ||
224 | } while(0) | ||
225 | |||
226 | static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb) | ||
227 | { | 202 | { |
228 | struct jffs2_raw_node_ref *ref; | 203 | return ((c->flash_size / c->sector_size) * sizeof (struct jffs2_eraseblock)) > (128 * 1024); |
229 | int i=0; | ||
230 | |||
231 | printk(KERN_NOTICE); | ||
232 | for (ref = jeb->first_node; ref; ref = ref->next_phys) { | ||
233 | printk("%08x->", ref_offset(ref)); | ||
234 | if (++i == 8) { | ||
235 | i = 0; | ||
236 | printk("\n" KERN_NOTICE); | ||
237 | } | ||
238 | } | ||
239 | printk("\n"); | ||
240 | } | 204 | } |
241 | 205 | ||
242 | |||
243 | #define ACCT_PARANOIA_CHECK(jeb) do { \ | ||
244 | uint32_t my_used_size = 0; \ | ||
245 | uint32_t my_unchecked_size = 0; \ | ||
246 | struct jffs2_raw_node_ref *ref2 = jeb->first_node; \ | ||
247 | while (ref2) { \ | ||
248 | if (unlikely(ref2->flash_offset < jeb->offset || \ | ||
249 | ref2->flash_offset > jeb->offset + c->sector_size)) { \ | ||
250 | printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \ | ||
251 | ref_offset(ref2), jeb->offset); \ | ||
252 | paranoia_failed_dump(jeb); \ | ||
253 | BUG(); \ | ||
254 | } \ | ||
255 | if (ref_flags(ref2) == REF_UNCHECKED) \ | ||
256 | my_unchecked_size += ref_totlen(c, jeb, ref2); \ | ||
257 | else if (!ref_obsolete(ref2)) \ | ||
258 | my_used_size += ref_totlen(c, jeb, ref2); \ | ||
259 | if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \ | ||
260 | if (!ref2->next_phys) \ | ||
261 | printk("ref for node at %p (phys %08x) has next_phys->%p (----), last_node->%p (phys %08x)\n", \ | ||
262 | ref2, ref_offset(ref2), ref2->next_phys, \ | ||
263 | jeb->last_node, ref_offset(jeb->last_node)); \ | ||
264 | else \ | ||
265 | printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \ | ||
266 | ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \ | ||
267 | jeb->last_node, ref_offset(jeb->last_node)); \ | ||
268 | paranoia_failed_dump(jeb); \ | ||
269 | BUG(); \ | ||
270 | } \ | ||
271 | ref2 = ref2->next_phys; \ | ||
272 | } \ | ||
273 | if (my_used_size != jeb->used_size) { \ | ||
274 | printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \ | ||
275 | BUG(); \ | ||
276 | } \ | ||
277 | if (my_unchecked_size != jeb->unchecked_size) { \ | ||
278 | printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \ | ||
279 | BUG(); \ | ||
280 | } \ | ||
281 | } while(0) | ||
282 | |||
283 | /* Calculate totlen from surrounding nodes or eraseblock */ | 206 | /* Calculate totlen from surrounding nodes or eraseblock */ |
284 | static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, | 207 | static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, |
285 | struct jffs2_eraseblock *jeb, | 208 | struct jffs2_eraseblock *jeb, |
286 | struct jffs2_raw_node_ref *ref) | 209 | struct jffs2_raw_node_ref *ref) |
287 | { | 210 | { |
288 | uint32_t ref_end; | 211 | uint32_t ref_end; |
289 | 212 | ||
290 | if (ref->next_phys) | 213 | if (ref->next_phys) |
291 | ref_end = ref_offset(ref->next_phys); | 214 | ref_end = ref_offset(ref->next_phys); |
292 | else { | 215 | else { |
@@ -306,11 +229,13 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c, | |||
306 | { | 229 | { |
307 | uint32_t ret; | 230 | uint32_t ret; |
308 | 231 | ||
309 | D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { | 232 | #if CONFIG_JFFS2_FS_DEBUG > 0 |
233 | if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { | ||
310 | printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n", | 234 | printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n", |
311 | jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref)); | 235 | jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref)); |
312 | BUG(); | 236 | BUG(); |
313 | }) | 237 | } |
238 | #endif | ||
314 | 239 | ||
315 | #if 1 | 240 | #if 1 |
316 | ret = ref->__totlen; | 241 | ret = ref->__totlen; |
@@ -323,14 +248,13 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c, | |||
323 | ret, ref->__totlen); | 248 | ret, ref->__totlen); |
324 | if (!jeb) | 249 | if (!jeb) |
325 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | 250 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; |
326 | paranoia_failed_dump(jeb); | 251 | jffs2_dbg_dump_node_refs_nolock(c, jeb); |
327 | BUG(); | 252 | BUG(); |
328 | } | 253 | } |
329 | #endif | 254 | #endif |
330 | return ret; | 255 | return ret; |
331 | } | 256 | } |
332 | 257 | ||
333 | |||
334 | #define ALLOC_NORMAL 0 /* Normal allocation */ | 258 | #define ALLOC_NORMAL 0 /* Normal allocation */ |
335 | #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */ | 259 | #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */ |
336 | #define ALLOC_GC 2 /* Space requested for GC. Give it or die */ | 260 | #define ALLOC_GC 2 /* Space requested for GC. Give it or die */ |
@@ -340,7 +264,7 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c, | |||
340 | #define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2)) | 264 | #define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2)) |
341 | 265 | ||
342 | /* check if dirty space is more than 255 Byte */ | 266 | /* check if dirty space is more than 255 Byte */ |
343 | #define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) | 267 | #define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) |
344 | 268 | ||
345 | #define PAD(x) (((x)+3)&~3) | 269 | #define PAD(x) (((x)+3)&~3) |
346 | 270 | ||
@@ -384,12 +308,7 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root) | |||
384 | #define frag_erase(frag, list) rb_erase(&frag->rb, list); | 308 | #define frag_erase(frag, list) rb_erase(&frag->rb, list); |
385 | 309 | ||
386 | /* nodelist.c */ | 310 | /* nodelist.c */ |
387 | D2(void jffs2_print_frag_list(struct jffs2_inode_info *f)); | ||
388 | void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); | 311 | void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); |
389 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | ||
390 | struct rb_root *tnp, struct jffs2_full_dirent **fdp, | ||
391 | uint32_t *highest_version, uint32_t *latest_mctime, | ||
392 | uint32_t *mctime_ver); | ||
393 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); | 312 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); |
394 | struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino); | 313 | struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino); |
395 | void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new); | 314 | void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new); |
@@ -398,19 +317,23 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c); | |||
398 | void jffs2_free_raw_node_refs(struct jffs2_sb_info *c); | 317 | void jffs2_free_raw_node_refs(struct jffs2_sb_info *c); |
399 | struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset); | 318 | struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset); |
400 | void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete); | 319 | void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete); |
401 | void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base); | ||
402 | struct rb_node *rb_next(struct rb_node *); | 320 | struct rb_node *rb_next(struct rb_node *); |
403 | struct rb_node *rb_prev(struct rb_node *); | 321 | struct rb_node *rb_prev(struct rb_node *); |
404 | void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); | 322 | void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); |
323 | void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this); | ||
324 | int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); | ||
325 | void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); | ||
326 | int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn); | ||
405 | 327 | ||
406 | /* nodemgmt.c */ | 328 | /* nodemgmt.c */ |
407 | int jffs2_thread_should_wake(struct jffs2_sb_info *c); | 329 | int jffs2_thread_should_wake(struct jffs2_sb_info *c); |
408 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio); | 330 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, |
409 | int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); | 331 | uint32_t *len, int prio, uint32_t sumsize); |
332 | int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, | ||
333 | uint32_t *len, uint32_t sumsize); | ||
410 | int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new); | 334 | int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new); |
411 | void jffs2_complete_reservation(struct jffs2_sb_info *c); | 335 | void jffs2_complete_reservation(struct jffs2_sb_info *c); |
412 | void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); | 336 | void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); |
413 | void jffs2_dump_block_lists(struct jffs2_sb_info *c); | ||
414 | 337 | ||
415 | /* write.c */ | 338 | /* write.c */ |
416 | int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri); | 339 | int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri); |
@@ -418,17 +341,15 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint | |||
418 | struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode); | 341 | struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode); |
419 | struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode); | 342 | struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode); |
420 | int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 343 | int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
421 | struct jffs2_raw_inode *ri, unsigned char *buf, | 344 | struct jffs2_raw_inode *ri, unsigned char *buf, |
422 | uint32_t offset, uint32_t writelen, uint32_t *retlen); | 345 | uint32_t offset, uint32_t writelen, uint32_t *retlen); |
423 | int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen); | 346 | int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen); |
424 | int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f); | 347 | int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f, uint32_t time); |
425 | int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen); | 348 | int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen, uint32_t time); |
426 | 349 | ||
427 | 350 | ||
428 | /* readinode.c */ | 351 | /* readinode.c */ |
429 | void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); | 352 | int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
430 | int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); | ||
431 | int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | ||
432 | uint32_t ino, struct jffs2_raw_inode *latest_node); | 353 | uint32_t ino, struct jffs2_raw_inode *latest_node); |
433 | int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); | 354 | int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); |
434 | void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); | 355 | void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); |
@@ -468,6 +389,10 @@ char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f); | |||
468 | /* scan.c */ | 389 | /* scan.c */ |
469 | int jffs2_scan_medium(struct jffs2_sb_info *c); | 390 | int jffs2_scan_medium(struct jffs2_sb_info *c); |
470 | void jffs2_rotate_lists(struct jffs2_sb_info *c); | 391 | void jffs2_rotate_lists(struct jffs2_sb_info *c); |
392 | int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf, | ||
393 | uint32_t ofs, uint32_t len); | ||
394 | struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino); | ||
395 | int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); | ||
471 | 396 | ||
472 | /* build.c */ | 397 | /* build.c */ |
473 | int jffs2_do_mount_fs(struct jffs2_sb_info *c); | 398 | int jffs2_do_mount_fs(struct jffs2_sb_info *c); |
@@ -483,4 +408,6 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
483 | int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); | 408 | int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); |
484 | #endif | 409 | #endif |
485 | 410 | ||
411 | #include "debug.h" | ||
412 | |||
486 | #endif /* __JFFS2_NODELIST_H__ */ | 413 | #endif /* __JFFS2_NODELIST_H__ */ |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index c1d8b5ed9ab9..49127a1f0458 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: nodemgmt.c,v 1.122 2005/05/06 09:30:27 dedekind Exp $ | 10 | * $Id: nodemgmt.c,v 1.127 2005/09/20 15:49:12 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/compiler.h> | 17 | #include <linux/compiler.h> |
18 | #include <linux/sched.h> /* For cond_resched() */ | 18 | #include <linux/sched.h> /* For cond_resched() */ |
19 | #include "nodelist.h" | 19 | #include "nodelist.h" |
20 | #include "debug.h" | ||
20 | 21 | ||
21 | /** | 22 | /** |
22 | * jffs2_reserve_space - request physical space to write nodes to flash | 23 | * jffs2_reserve_space - request physical space to write nodes to flash |
@@ -38,9 +39,11 @@ | |||
38 | * for the requested allocation. | 39 | * for the requested allocation. |
39 | */ | 40 | */ |
40 | 41 | ||
41 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); | 42 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, |
43 | uint32_t *ofs, uint32_t *len, uint32_t sumsize); | ||
42 | 44 | ||
43 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio) | 45 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, |
46 | uint32_t *len, int prio, uint32_t sumsize) | ||
44 | { | 47 | { |
45 | int ret = -EAGAIN; | 48 | int ret = -EAGAIN; |
46 | int blocksneeded = c->resv_blocks_write; | 49 | int blocksneeded = c->resv_blocks_write; |
@@ -85,12 +88,12 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs | |||
85 | up(&c->alloc_sem); | 88 | up(&c->alloc_sem); |
86 | return -ENOSPC; | 89 | return -ENOSPC; |
87 | } | 90 | } |
88 | 91 | ||
89 | /* Calc possibly available space. Possibly available means that we | 92 | /* Calc possibly available space. Possibly available means that we |
90 | * don't know, if unchecked size contains obsoleted nodes, which could give us some | 93 | * don't know, if unchecked size contains obsoleted nodes, which could give us some |
91 | * more usable space. This will affect the sum only once, as gc first finishes checking | 94 | * more usable space. This will affect the sum only once, as gc first finishes checking |
92 | * of nodes. | 95 | * of nodes. |
93 | + Return -ENOSPC, if the maximum possibly available space is less or equal than | 96 | + Return -ENOSPC, if the maximum possibly available space is less or equal than |
94 | * blocksneeded * sector_size. | 97 | * blocksneeded * sector_size. |
95 | * This blocks endless gc looping on a filesystem, which is nearly full, even if | 98 | * This blocks endless gc looping on a filesystem, which is nearly full, even if |
96 | * the check above passes. | 99 | * the check above passes. |
@@ -115,7 +118,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs | |||
115 | c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, | 118 | c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, |
116 | c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); | 119 | c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); |
117 | spin_unlock(&c->erase_completion_lock); | 120 | spin_unlock(&c->erase_completion_lock); |
118 | 121 | ||
119 | ret = jffs2_garbage_collect_pass(c); | 122 | ret = jffs2_garbage_collect_pass(c); |
120 | if (ret) | 123 | if (ret) |
121 | return ret; | 124 | return ret; |
@@ -129,7 +132,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs | |||
129 | spin_lock(&c->erase_completion_lock); | 132 | spin_lock(&c->erase_completion_lock); |
130 | } | 133 | } |
131 | 134 | ||
132 | ret = jffs2_do_reserve_space(c, minsize, ofs, len); | 135 | ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize); |
133 | if (ret) { | 136 | if (ret) { |
134 | D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); | 137 | D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); |
135 | } | 138 | } |
@@ -140,7 +143,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs | |||
140 | return ret; | 143 | return ret; |
141 | } | 144 | } |
142 | 145 | ||
143 | int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) | 146 | int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, |
147 | uint32_t *len, uint32_t sumsize) | ||
144 | { | 148 | { |
145 | int ret = -EAGAIN; | 149 | int ret = -EAGAIN; |
146 | minsize = PAD(minsize); | 150 | minsize = PAD(minsize); |
@@ -149,7 +153,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t * | |||
149 | 153 | ||
150 | spin_lock(&c->erase_completion_lock); | 154 | spin_lock(&c->erase_completion_lock); |
151 | while(ret == -EAGAIN) { | 155 | while(ret == -EAGAIN) { |
152 | ret = jffs2_do_reserve_space(c, minsize, ofs, len); | 156 | ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize); |
153 | if (ret) { | 157 | if (ret) { |
154 | D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); | 158 | D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); |
155 | } | 159 | } |
@@ -158,105 +162,185 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t * | |||
158 | return ret; | 162 | return ret; |
159 | } | 163 | } |
160 | 164 | ||
161 | /* Called with alloc sem _and_ erase_completion_lock */ | 165 | |
162 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) | 166 | /* Classify nextblock (clean, dirty of verydirty) and force to select an other one */ |
167 | |||
168 | static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | ||
163 | { | 169 | { |
164 | struct jffs2_eraseblock *jeb = c->nextblock; | 170 | |
165 | 171 | /* Check, if we have a dirty block now, or if it was dirty already */ | |
166 | restart: | 172 | if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { |
167 | if (jeb && minsize > jeb->free_size) { | 173 | c->dirty_size += jeb->wasted_size; |
168 | /* Skip the end of this block and file it as having some dirty space */ | 174 | c->wasted_size -= jeb->wasted_size; |
169 | /* If there's a pending write to it, flush now */ | 175 | jeb->dirty_size += jeb->wasted_size; |
170 | if (jffs2_wbuf_dirty(c)) { | 176 | jeb->wasted_size = 0; |
177 | if (VERYDIRTY(c, jeb->dirty_size)) { | ||
178 | D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", | ||
179 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); | ||
180 | list_add_tail(&jeb->list, &c->very_dirty_list); | ||
181 | } else { | ||
182 | D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", | ||
183 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); | ||
184 | list_add_tail(&jeb->list, &c->dirty_list); | ||
185 | } | ||
186 | } else { | ||
187 | D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", | ||
188 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); | ||
189 | list_add_tail(&jeb->list, &c->clean_list); | ||
190 | } | ||
191 | c->nextblock = NULL; | ||
192 | |||
193 | } | ||
194 | |||
195 | /* Select a new jeb for nextblock */ | ||
196 | |||
197 | static int jffs2_find_nextblock(struct jffs2_sb_info *c) | ||
198 | { | ||
199 | struct list_head *next; | ||
200 | |||
201 | /* Take the next block off the 'free' list */ | ||
202 | |||
203 | if (list_empty(&c->free_list)) { | ||
204 | |||
205 | if (!c->nr_erasing_blocks && | ||
206 | !list_empty(&c->erasable_list)) { | ||
207 | struct jffs2_eraseblock *ejeb; | ||
208 | |||
209 | ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); | ||
210 | list_del(&ejeb->list); | ||
211 | list_add_tail(&ejeb->list, &c->erase_pending_list); | ||
212 | c->nr_erasing_blocks++; | ||
213 | jffs2_erase_pending_trigger(c); | ||
214 | D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n", | ||
215 | ejeb->offset)); | ||
216 | } | ||
217 | |||
218 | if (!c->nr_erasing_blocks && | ||
219 | !list_empty(&c->erasable_pending_wbuf_list)) { | ||
220 | D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n")); | ||
221 | /* c->nextblock is NULL, no update to c->nextblock allowed */ | ||
171 | spin_unlock(&c->erase_completion_lock); | 222 | spin_unlock(&c->erase_completion_lock); |
172 | D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); | ||
173 | jffs2_flush_wbuf_pad(c); | 223 | jffs2_flush_wbuf_pad(c); |
174 | spin_lock(&c->erase_completion_lock); | 224 | spin_lock(&c->erase_completion_lock); |
175 | jeb = c->nextblock; | 225 | /* Have another go. It'll be on the erasable_list now */ |
176 | goto restart; | 226 | return -EAGAIN; |
177 | } | 227 | } |
178 | c->wasted_size += jeb->free_size; | 228 | |
179 | c->free_size -= jeb->free_size; | 229 | if (!c->nr_erasing_blocks) { |
180 | jeb->wasted_size += jeb->free_size; | 230 | /* Ouch. We're in GC, or we wouldn't have got here. |
181 | jeb->free_size = 0; | 231 | And there's no space left. At all. */ |
182 | 232 | printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", | |
183 | /* Check, if we have a dirty block now, or if it was dirty already */ | 233 | c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", |
184 | if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { | 234 | list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); |
185 | c->dirty_size += jeb->wasted_size; | 235 | return -ENOSPC; |
186 | c->wasted_size -= jeb->wasted_size; | ||
187 | jeb->dirty_size += jeb->wasted_size; | ||
188 | jeb->wasted_size = 0; | ||
189 | if (VERYDIRTY(c, jeb->dirty_size)) { | ||
190 | D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", | ||
191 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); | ||
192 | list_add_tail(&jeb->list, &c->very_dirty_list); | ||
193 | } else { | ||
194 | D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", | ||
195 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); | ||
196 | list_add_tail(&jeb->list, &c->dirty_list); | ||
197 | } | ||
198 | } else { | ||
199 | D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", | ||
200 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); | ||
201 | list_add_tail(&jeb->list, &c->clean_list); | ||
202 | } | 236 | } |
203 | c->nextblock = jeb = NULL; | 237 | |
238 | spin_unlock(&c->erase_completion_lock); | ||
239 | /* Don't wait for it; just erase one right now */ | ||
240 | jffs2_erase_pending_blocks(c, 1); | ||
241 | spin_lock(&c->erase_completion_lock); | ||
242 | |||
243 | /* An erase may have failed, decreasing the | ||
244 | amount of free space available. So we must | ||
245 | restart from the beginning */ | ||
246 | return -EAGAIN; | ||
204 | } | 247 | } |
205 | |||
206 | if (!jeb) { | ||
207 | struct list_head *next; | ||
208 | /* Take the next block off the 'free' list */ | ||
209 | 248 | ||
210 | if (list_empty(&c->free_list)) { | 249 | next = c->free_list.next; |
250 | list_del(next); | ||
251 | c->nextblock = list_entry(next, struct jffs2_eraseblock, list); | ||
252 | c->nr_free_blocks--; | ||
211 | 253 | ||
212 | if (!c->nr_erasing_blocks && | 254 | jffs2_sum_reset_collected(c->summary); /* reset collected summary */ |
213 | !list_empty(&c->erasable_list)) { | ||
214 | struct jffs2_eraseblock *ejeb; | ||
215 | 255 | ||
216 | ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); | 256 | D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset)); |
217 | list_del(&ejeb->list); | 257 | |
218 | list_add_tail(&ejeb->list, &c->erase_pending_list); | 258 | return 0; |
219 | c->nr_erasing_blocks++; | 259 | } |
220 | jffs2_erase_pending_trigger(c); | 260 | |
221 | D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n", | 261 | /* Called with alloc sem _and_ erase_completion_lock */ |
222 | ejeb->offset)); | 262 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize) |
263 | { | ||
264 | struct jffs2_eraseblock *jeb = c->nextblock; | ||
265 | uint32_t reserved_size; /* for summary information at the end of the jeb */ | ||
266 | int ret; | ||
267 | |||
268 | restart: | ||
269 | reserved_size = 0; | ||
270 | |||
271 | if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) { | ||
272 | /* NOSUM_SIZE means not to generate summary */ | ||
273 | |||
274 | if (jeb) { | ||
275 | reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); | ||
276 | dbg_summary("minsize=%d , jeb->free=%d ," | ||
277 | "summary->size=%d , sumsize=%d\n", | ||
278 | minsize, jeb->free_size, | ||
279 | c->summary->sum_size, sumsize); | ||
280 | } | ||
281 | |||
282 | /* Is there enough space for writing out the current node, or we have to | ||
283 | write out summary information now, close this jeb and select new nextblock? */ | ||
284 | if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize + | ||
285 | JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) { | ||
286 | |||
287 | /* Has summary been disabled for this jeb? */ | ||
288 | if (jffs2_sum_is_disabled(c->summary)) { | ||
289 | sumsize = JFFS2_SUMMARY_NOSUM_SIZE; | ||
290 | goto restart; | ||
223 | } | 291 | } |
224 | 292 | ||
225 | if (!c->nr_erasing_blocks && | 293 | /* Writing out the collected summary information */ |
226 | !list_empty(&c->erasable_pending_wbuf_list)) { | 294 | dbg_summary("generating summary for 0x%08x.\n", jeb->offset); |
227 | D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); | 295 | ret = jffs2_sum_write_sumnode(c); |
228 | /* c->nextblock is NULL, no update to c->nextblock allowed */ | 296 | |
297 | if (ret) | ||
298 | return ret; | ||
299 | |||
300 | if (jffs2_sum_is_disabled(c->summary)) { | ||
301 | /* jffs2_write_sumnode() couldn't write out the summary information | ||
302 | diabling summary for this jeb and free the collected information | ||
303 | */ | ||
304 | sumsize = JFFS2_SUMMARY_NOSUM_SIZE; | ||
305 | goto restart; | ||
306 | } | ||
307 | |||
308 | jffs2_close_nextblock(c, jeb); | ||
309 | jeb = NULL; | ||
310 | /* keep always valid value in reserved_size */ | ||
311 | reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); | ||
312 | } | ||
313 | } else { | ||
314 | if (jeb && minsize > jeb->free_size) { | ||
315 | /* Skip the end of this block and file it as having some dirty space */ | ||
316 | /* If there's a pending write to it, flush now */ | ||
317 | |||
318 | if (jffs2_wbuf_dirty(c)) { | ||
229 | spin_unlock(&c->erase_completion_lock); | 319 | spin_unlock(&c->erase_completion_lock); |
320 | D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); | ||
230 | jffs2_flush_wbuf_pad(c); | 321 | jffs2_flush_wbuf_pad(c); |
231 | spin_lock(&c->erase_completion_lock); | 322 | spin_lock(&c->erase_completion_lock); |
232 | /* Have another go. It'll be on the erasable_list now */ | 323 | jeb = c->nextblock; |
233 | return -EAGAIN; | 324 | goto restart; |
234 | } | 325 | } |
235 | 326 | ||
236 | if (!c->nr_erasing_blocks) { | 327 | c->wasted_size += jeb->free_size; |
237 | /* Ouch. We're in GC, or we wouldn't have got here. | 328 | c->free_size -= jeb->free_size; |
238 | And there's no space left. At all. */ | 329 | jeb->wasted_size += jeb->free_size; |
239 | printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", | 330 | jeb->free_size = 0; |
240 | c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", | ||
241 | list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); | ||
242 | return -ENOSPC; | ||
243 | } | ||
244 | |||
245 | spin_unlock(&c->erase_completion_lock); | ||
246 | /* Don't wait for it; just erase one right now */ | ||
247 | jffs2_erase_pending_blocks(c, 1); | ||
248 | spin_lock(&c->erase_completion_lock); | ||
249 | 331 | ||
250 | /* An erase may have failed, decreasing the | 332 | jffs2_close_nextblock(c, jeb); |
251 | amount of free space available. So we must | 333 | jeb = NULL; |
252 | restart from the beginning */ | ||
253 | return -EAGAIN; | ||
254 | } | 334 | } |
335 | } | ||
336 | |||
337 | if (!jeb) { | ||
255 | 338 | ||
256 | next = c->free_list.next; | 339 | ret = jffs2_find_nextblock(c); |
257 | list_del(next); | 340 | if (ret) |
258 | c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list); | 341 | return ret; |
259 | c->nr_free_blocks--; | 342 | |
343 | jeb = c->nextblock; | ||
260 | 344 | ||
261 | if (jeb->free_size != c->sector_size - c->cleanmarker_size) { | 345 | if (jeb->free_size != c->sector_size - c->cleanmarker_size) { |
262 | printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size); | 346 | printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size); |
@@ -266,13 +350,13 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui | |||
266 | /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has | 350 | /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has |
267 | enough space */ | 351 | enough space */ |
268 | *ofs = jeb->offset + (c->sector_size - jeb->free_size); | 352 | *ofs = jeb->offset + (c->sector_size - jeb->free_size); |
269 | *len = jeb->free_size; | 353 | *len = jeb->free_size - reserved_size; |
270 | 354 | ||
271 | if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && | 355 | if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && |
272 | !jeb->first_node->next_in_ino) { | 356 | !jeb->first_node->next_in_ino) { |
273 | /* Only node in it beforehand was a CLEANMARKER node (we think). | 357 | /* Only node in it beforehand was a CLEANMARKER node (we think). |
274 | So mark it obsolete now that there's going to be another node | 358 | So mark it obsolete now that there's going to be another node |
275 | in the block. This will reduce used_size to zero but We've | 359 | in the block. This will reduce used_size to zero but We've |
276 | already set c->nextblock so that jffs2_mark_node_obsolete() | 360 | already set c->nextblock so that jffs2_mark_node_obsolete() |
277 | won't try to refile it to the dirty_list. | 361 | won't try to refile it to the dirty_list. |
278 | */ | 362 | */ |
@@ -292,12 +376,12 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui | |||
292 | * @len: length of this physical node | 376 | * @len: length of this physical node |
293 | * @dirty: dirty flag for new node | 377 | * @dirty: dirty flag for new node |
294 | * | 378 | * |
295 | * Should only be used to report nodes for which space has been allocated | 379 | * Should only be used to report nodes for which space has been allocated |
296 | * by jffs2_reserve_space. | 380 | * by jffs2_reserve_space. |
297 | * | 381 | * |
298 | * Must be called with the alloc_sem held. | 382 | * Must be called with the alloc_sem held. |
299 | */ | 383 | */ |
300 | 384 | ||
301 | int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new) | 385 | int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new) |
302 | { | 386 | { |
303 | struct jffs2_eraseblock *jeb; | 387 | struct jffs2_eraseblock *jeb; |
@@ -349,8 +433,8 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
349 | list_add_tail(&jeb->list, &c->clean_list); | 433 | list_add_tail(&jeb->list, &c->clean_list); |
350 | c->nextblock = NULL; | 434 | c->nextblock = NULL; |
351 | } | 435 | } |
352 | ACCT_SANITY_CHECK(c,jeb); | 436 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); |
353 | D1(ACCT_PARANOIA_CHECK(jeb)); | 437 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
354 | 438 | ||
355 | spin_unlock(&c->erase_completion_lock); | 439 | spin_unlock(&c->erase_completion_lock); |
356 | 440 | ||
@@ -404,8 +488,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
404 | 488 | ||
405 | if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && | 489 | if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && |
406 | !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { | 490 | !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { |
407 | /* Hm. This may confuse static lock analysis. If any of the above | 491 | /* Hm. This may confuse static lock analysis. If any of the above |
408 | three conditions is false, we're going to return from this | 492 | three conditions is false, we're going to return from this |
409 | function without actually obliterating any nodes or freeing | 493 | function without actually obliterating any nodes or freeing |
410 | any jffs2_raw_node_refs. So we don't need to stop erases from | 494 | any jffs2_raw_node_refs. So we don't need to stop erases from |
411 | happening, or protect against people holding an obsolete | 495 | happening, or protect against people holding an obsolete |
@@ -430,7 +514,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
430 | ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); | 514 | ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); |
431 | BUG(); | 515 | BUG(); |
432 | }) | 516 | }) |
433 | D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); | 517 | D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); |
434 | jeb->used_size -= ref_totlen(c, jeb, ref); | 518 | jeb->used_size -= ref_totlen(c, jeb, ref); |
435 | c->used_size -= ref_totlen(c, jeb, ref); | 519 | c->used_size -= ref_totlen(c, jeb, ref); |
436 | } | 520 | } |
@@ -462,18 +546,17 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
462 | D1(printk(KERN_DEBUG "Wasting\n")); | 546 | D1(printk(KERN_DEBUG "Wasting\n")); |
463 | addedsize = 0; | 547 | addedsize = 0; |
464 | jeb->wasted_size += ref_totlen(c, jeb, ref); | 548 | jeb->wasted_size += ref_totlen(c, jeb, ref); |
465 | c->wasted_size += ref_totlen(c, jeb, ref); | 549 | c->wasted_size += ref_totlen(c, jeb, ref); |
466 | } | 550 | } |
467 | ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; | 551 | ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; |
468 | |||
469 | ACCT_SANITY_CHECK(c, jeb); | ||
470 | 552 | ||
471 | D1(ACCT_PARANOIA_CHECK(jeb)); | 553 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); |
554 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | ||
472 | 555 | ||
473 | if (c->flags & JFFS2_SB_FLAG_SCANNING) { | 556 | if (c->flags & JFFS2_SB_FLAG_SCANNING) { |
474 | /* Flash scanning is in progress. Don't muck about with the block | 557 | /* Flash scanning is in progress. Don't muck about with the block |
475 | lists because they're not ready yet, and don't actually | 558 | lists because they're not ready yet, and don't actually |
476 | obliterate nodes that look obsolete. If they weren't | 559 | obliterate nodes that look obsolete. If they weren't |
477 | marked obsolete on the flash at the time they _became_ | 560 | marked obsolete on the flash at the time they _became_ |
478 | obsolete, there was probably a reason for that. */ | 561 | obsolete, there was probably a reason for that. */ |
479 | spin_unlock(&c->erase_completion_lock); | 562 | spin_unlock(&c->erase_completion_lock); |
@@ -507,7 +590,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
507 | immediately reused, and we spread the load a bit. */ | 590 | immediately reused, and we spread the load a bit. */ |
508 | D1(printk(KERN_DEBUG "...and adding to erasable_list\n")); | 591 | D1(printk(KERN_DEBUG "...and adding to erasable_list\n")); |
509 | list_add_tail(&jeb->list, &c->erasable_list); | 592 | list_add_tail(&jeb->list, &c->erasable_list); |
510 | } | 593 | } |
511 | } | 594 | } |
512 | D1(printk(KERN_DEBUG "Done OK\n")); | 595 | D1(printk(KERN_DEBUG "Done OK\n")); |
513 | } else if (jeb == c->gcblock) { | 596 | } else if (jeb == c->gcblock) { |
@@ -525,8 +608,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
525 | list_add_tail(&jeb->list, &c->very_dirty_list); | 608 | list_add_tail(&jeb->list, &c->very_dirty_list); |
526 | } else { | 609 | } else { |
527 | D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n", | 610 | D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n", |
528 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); | 611 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); |
529 | } | 612 | } |
530 | 613 | ||
531 | spin_unlock(&c->erase_completion_lock); | 614 | spin_unlock(&c->erase_completion_lock); |
532 | 615 | ||
@@ -573,11 +656,11 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
573 | 656 | ||
574 | /* Nodes which have been marked obsolete no longer need to be | 657 | /* Nodes which have been marked obsolete no longer need to be |
575 | associated with any inode. Remove them from the per-inode list. | 658 | associated with any inode. Remove them from the per-inode list. |
576 | 659 | ||
577 | Note we can't do this for NAND at the moment because we need | 660 | Note we can't do this for NAND at the moment because we need |
578 | obsolete dirent nodes to stay on the lists, because of the | 661 | obsolete dirent nodes to stay on the lists, because of the |
579 | horridness in jffs2_garbage_collect_deletion_dirent(). Also | 662 | horridness in jffs2_garbage_collect_deletion_dirent(). Also |
580 | because we delete the inocache, and on NAND we need that to | 663 | because we delete the inocache, and on NAND we need that to |
581 | stay around until all the nodes are actually erased, in order | 664 | stay around until all the nodes are actually erased, in order |
582 | to stop us from giving the same inode number to another newly | 665 | to stop us from giving the same inode number to another newly |
583 | created inode. */ | 666 | created inode. */ |
@@ -606,7 +689,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
606 | if (ref->next_phys && ref_obsolete(ref->next_phys) && | 689 | if (ref->next_phys && ref_obsolete(ref->next_phys) && |
607 | !ref->next_phys->next_in_ino) { | 690 | !ref->next_phys->next_in_ino) { |
608 | struct jffs2_raw_node_ref *n = ref->next_phys; | 691 | struct jffs2_raw_node_ref *n = ref->next_phys; |
609 | 692 | ||
610 | spin_lock(&c->erase_completion_lock); | 693 | spin_lock(&c->erase_completion_lock); |
611 | 694 | ||
612 | ref->__totlen += n->__totlen; | 695 | ref->__totlen += n->__totlen; |
@@ -620,7 +703,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
620 | 703 | ||
621 | jffs2_free_raw_node_ref(n); | 704 | jffs2_free_raw_node_ref(n); |
622 | } | 705 | } |
623 | 706 | ||
624 | /* Also merge with the previous node in the list, if there is one | 707 | /* Also merge with the previous node in the list, if there is one |
625 | and that one is obsolete */ | 708 | and that one is obsolete */ |
626 | if (ref != jeb->first_node ) { | 709 | if (ref != jeb->first_node ) { |
@@ -630,7 +713,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
630 | 713 | ||
631 | while (p->next_phys != ref) | 714 | while (p->next_phys != ref) |
632 | p = p->next_phys; | 715 | p = p->next_phys; |
633 | 716 | ||
634 | if (ref_obsolete(p) && !ref->next_in_ino) { | 717 | if (ref_obsolete(p) && !ref->next_in_ino) { |
635 | p->__totlen += ref->__totlen; | 718 | p->__totlen += ref->__totlen; |
636 | if (jeb->last_node == ref) { | 719 | if (jeb->last_node == ref) { |
@@ -649,164 +732,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
649 | up(&c->erase_free_sem); | 732 | up(&c->erase_free_sem); |
650 | } | 733 | } |
651 | 734 | ||
652 | #if CONFIG_JFFS2_FS_DEBUG >= 2 | ||
653 | void jffs2_dump_block_lists(struct jffs2_sb_info *c) | ||
654 | { | ||
655 | |||
656 | |||
657 | printk(KERN_DEBUG "jffs2_dump_block_lists:\n"); | ||
658 | printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size); | ||
659 | printk(KERN_DEBUG "used_size: %08x\n", c->used_size); | ||
660 | printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size); | ||
661 | printk(KERN_DEBUG "wasted_size: %08x\n", c->wasted_size); | ||
662 | printk(KERN_DEBUG "unchecked_size: %08x\n", c->unchecked_size); | ||
663 | printk(KERN_DEBUG "free_size: %08x\n", c->free_size); | ||
664 | printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size); | ||
665 | printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size); | ||
666 | printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size); | ||
667 | printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write); | ||
668 | |||
669 | if (c->nextblock) { | ||
670 | printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
671 | c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->unchecked_size, c->nextblock->free_size); | ||
672 | } else { | ||
673 | printk(KERN_DEBUG "nextblock: NULL\n"); | ||
674 | } | ||
675 | if (c->gcblock) { | ||
676 | printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
677 | c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); | ||
678 | } else { | ||
679 | printk(KERN_DEBUG "gcblock: NULL\n"); | ||
680 | } | ||
681 | if (list_empty(&c->clean_list)) { | ||
682 | printk(KERN_DEBUG "clean_list: empty\n"); | ||
683 | } else { | ||
684 | struct list_head *this; | ||
685 | int numblocks = 0; | ||
686 | uint32_t dirty = 0; | ||
687 | |||
688 | list_for_each(this, &c->clean_list) { | ||
689 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
690 | numblocks ++; | ||
691 | dirty += jeb->wasted_size; | ||
692 | printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
693 | } | ||
694 | printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", numblocks, dirty, dirty / numblocks); | ||
695 | } | ||
696 | if (list_empty(&c->very_dirty_list)) { | ||
697 | printk(KERN_DEBUG "very_dirty_list: empty\n"); | ||
698 | } else { | ||
699 | struct list_head *this; | ||
700 | int numblocks = 0; | ||
701 | uint32_t dirty = 0; | ||
702 | |||
703 | list_for_each(this, &c->very_dirty_list) { | ||
704 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
705 | numblocks ++; | ||
706 | dirty += jeb->dirty_size; | ||
707 | printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
708 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
709 | } | ||
710 | printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", | ||
711 | numblocks, dirty, dirty / numblocks); | ||
712 | } | ||
713 | if (list_empty(&c->dirty_list)) { | ||
714 | printk(KERN_DEBUG "dirty_list: empty\n"); | ||
715 | } else { | ||
716 | struct list_head *this; | ||
717 | int numblocks = 0; | ||
718 | uint32_t dirty = 0; | ||
719 | |||
720 | list_for_each(this, &c->dirty_list) { | ||
721 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
722 | numblocks ++; | ||
723 | dirty += jeb->dirty_size; | ||
724 | printk(KERN_DEBUG "dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
725 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
726 | } | ||
727 | printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", | ||
728 | numblocks, dirty, dirty / numblocks); | ||
729 | } | ||
730 | if (list_empty(&c->erasable_list)) { | ||
731 | printk(KERN_DEBUG "erasable_list: empty\n"); | ||
732 | } else { | ||
733 | struct list_head *this; | ||
734 | |||
735 | list_for_each(this, &c->erasable_list) { | ||
736 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
737 | printk(KERN_DEBUG "erasable_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
738 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
739 | } | ||
740 | } | ||
741 | if (list_empty(&c->erasing_list)) { | ||
742 | printk(KERN_DEBUG "erasing_list: empty\n"); | ||
743 | } else { | ||
744 | struct list_head *this; | ||
745 | |||
746 | list_for_each(this, &c->erasing_list) { | ||
747 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
748 | printk(KERN_DEBUG "erasing_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
749 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
750 | } | ||
751 | } | ||
752 | if (list_empty(&c->erase_pending_list)) { | ||
753 | printk(KERN_DEBUG "erase_pending_list: empty\n"); | ||
754 | } else { | ||
755 | struct list_head *this; | ||
756 | |||
757 | list_for_each(this, &c->erase_pending_list) { | ||
758 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
759 | printk(KERN_DEBUG "erase_pending_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
760 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
761 | } | ||
762 | } | ||
763 | if (list_empty(&c->erasable_pending_wbuf_list)) { | ||
764 | printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n"); | ||
765 | } else { | ||
766 | struct list_head *this; | ||
767 | |||
768 | list_for_each(this, &c->erasable_pending_wbuf_list) { | ||
769 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
770 | printk(KERN_DEBUG "erasable_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
771 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
772 | } | ||
773 | } | ||
774 | if (list_empty(&c->free_list)) { | ||
775 | printk(KERN_DEBUG "free_list: empty\n"); | ||
776 | } else { | ||
777 | struct list_head *this; | ||
778 | |||
779 | list_for_each(this, &c->free_list) { | ||
780 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
781 | printk(KERN_DEBUG "free_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
782 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
783 | } | ||
784 | } | ||
785 | if (list_empty(&c->bad_list)) { | ||
786 | printk(KERN_DEBUG "bad_list: empty\n"); | ||
787 | } else { | ||
788 | struct list_head *this; | ||
789 | |||
790 | list_for_each(this, &c->bad_list) { | ||
791 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
792 | printk(KERN_DEBUG "bad_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
793 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
794 | } | ||
795 | } | ||
796 | if (list_empty(&c->bad_used_list)) { | ||
797 | printk(KERN_DEBUG "bad_used_list: empty\n"); | ||
798 | } else { | ||
799 | struct list_head *this; | ||
800 | |||
801 | list_for_each(this, &c->bad_used_list) { | ||
802 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
803 | printk(KERN_DEBUG "bad_used_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", | ||
804 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); | ||
805 | } | ||
806 | } | ||
807 | } | ||
808 | #endif /* CONFIG_JFFS2_FS_DEBUG */ | ||
809 | |||
810 | int jffs2_thread_should_wake(struct jffs2_sb_info *c) | 735 | int jffs2_thread_should_wake(struct jffs2_sb_info *c) |
811 | { | 736 | { |
812 | int ret = 0; | 737 | int ret = 0; |
@@ -828,11 +753,11 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) | |||
828 | */ | 753 | */ |
829 | dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; | 754 | dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; |
830 | 755 | ||
831 | if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && | 756 | if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && |
832 | (dirty > c->nospc_dirty_size)) | 757 | (dirty > c->nospc_dirty_size)) |
833 | ret = 1; | 758 | ret = 1; |
834 | 759 | ||
835 | D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", | 760 | D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", |
836 | c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); | 761 | c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); |
837 | 762 | ||
838 | return ret; | 763 | return ret; |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index d900c8929b09..59e7a393200c 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: os-linux.h,v 1.58 2005/07/12 02:34:35 tpoynor Exp $ | 10 | * $Id: os-linux.h,v 1.64 2005/09/30 13:59:13 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -57,6 +57,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
57 | f->fragtree = RB_ROOT; | 57 | f->fragtree = RB_ROOT; |
58 | f->metadata = NULL; | 58 | f->metadata = NULL; |
59 | f->dents = NULL; | 59 | f->dents = NULL; |
60 | f->target = NULL; | ||
60 | f->flags = 0; | 61 | f->flags = 0; |
61 | f->usercompr = 0; | 62 | f->usercompr = 0; |
62 | } | 63 | } |
@@ -64,17 +65,24 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
64 | 65 | ||
65 | #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) | 66 | #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) |
66 | 67 | ||
68 | #define SECTOR_ADDR(x) ( (((unsigned long)(x) / c->sector_size) * c->sector_size) ) | ||
67 | #ifndef CONFIG_JFFS2_FS_WRITEBUFFER | 69 | #ifndef CONFIG_JFFS2_FS_WRITEBUFFER |
68 | #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) | 70 | |
71 | |||
72 | #ifdef CONFIG_JFFS2_SUMMARY | ||
73 | #define jffs2_can_mark_obsolete(c) (0) | ||
74 | #else | ||
69 | #define jffs2_can_mark_obsolete(c) (1) | 75 | #define jffs2_can_mark_obsolete(c) (1) |
76 | #endif | ||
77 | |||
70 | #define jffs2_is_writebuffered(c) (0) | 78 | #define jffs2_is_writebuffered(c) (0) |
71 | #define jffs2_cleanmarker_oob(c) (0) | 79 | #define jffs2_cleanmarker_oob(c) (0) |
72 | #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) | 80 | #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) |
73 | 81 | ||
74 | #define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf)) | 82 | #define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf) |
75 | #define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf)) | 83 | #define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf)) |
76 | #define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; }) | 84 | #define jffs2_flush_wbuf_pad(c) ({ do{} while(0); (void)(c), 0; }) |
77 | #define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; }) | 85 | #define jffs2_flush_wbuf_gc(c, i) ({ do{} while(0); (void)(c), (void) i, 0; }) |
78 | #define jffs2_write_nand_badblock(c,jeb,bad_offset) (1) | 86 | #define jffs2_write_nand_badblock(c,jeb,bad_offset) (1) |
79 | #define jffs2_nand_flash_setup(c) (0) | 87 | #define jffs2_nand_flash_setup(c) (0) |
80 | #define jffs2_nand_flash_cleanup(c) do {} while(0) | 88 | #define jffs2_nand_flash_cleanup(c) do {} while(0) |
@@ -84,16 +92,26 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
84 | #define jffs2_wbuf_process NULL | 92 | #define jffs2_wbuf_process NULL |
85 | #define jffs2_nor_ecc(c) (0) | 93 | #define jffs2_nor_ecc(c) (0) |
86 | #define jffs2_dataflash(c) (0) | 94 | #define jffs2_dataflash(c) (0) |
95 | #define jffs2_nor_wbuf_flash(c) (0) | ||
87 | #define jffs2_nor_ecc_flash_setup(c) (0) | 96 | #define jffs2_nor_ecc_flash_setup(c) (0) |
88 | #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) | 97 | #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) |
89 | #define jffs2_dataflash_setup(c) (0) | 98 | #define jffs2_dataflash_setup(c) (0) |
90 | #define jffs2_dataflash_cleanup(c) do {} while (0) | 99 | #define jffs2_dataflash_cleanup(c) do {} while (0) |
100 | #define jffs2_nor_wbuf_flash_setup(c) (0) | ||
101 | #define jffs2_nor_wbuf_flash_cleanup(c) do {} while (0) | ||
91 | 102 | ||
92 | #else /* NAND and/or ECC'd NOR support present */ | 103 | #else /* NAND and/or ECC'd NOR support present */ |
93 | 104 | ||
94 | #define jffs2_is_writebuffered(c) (c->wbuf != NULL) | 105 | #define jffs2_is_writebuffered(c) (c->wbuf != NULL) |
95 | #define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) | 106 | |
96 | #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM) | 107 | #ifdef CONFIG_JFFS2_SUMMARY |
108 | #define jffs2_can_mark_obsolete(c) (0) | ||
109 | #else | ||
110 | #define jffs2_can_mark_obsolete(c) \ | ||
111 | ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \ | ||
112 | c->mtd->type == MTD_RAM) | ||
113 | #endif | ||
114 | |||
97 | #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) | 115 | #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) |
98 | 116 | ||
99 | #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf)) | 117 | #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf)) |
@@ -123,6 +141,10 @@ void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); | |||
123 | int jffs2_dataflash_setup(struct jffs2_sb_info *c); | 141 | int jffs2_dataflash_setup(struct jffs2_sb_info *c); |
124 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); | 142 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); |
125 | 143 | ||
144 | #define jffs2_nor_wbuf_flash(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_PROGRAM_REGIONS)) | ||
145 | int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c); | ||
146 | void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c); | ||
147 | |||
126 | #endif /* WRITEBUFFER */ | 148 | #endif /* WRITEBUFFER */ |
127 | 149 | ||
128 | /* erase.c */ | 150 | /* erase.c */ |
@@ -169,20 +191,21 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c, | |||
169 | struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, | 191 | struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, |
170 | int inum, int nlink); | 192 | int inum, int nlink); |
171 | 193 | ||
172 | unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, | 194 | unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, |
173 | struct jffs2_inode_info *f, | 195 | struct jffs2_inode_info *f, |
174 | unsigned long offset, | 196 | unsigned long offset, |
175 | unsigned long *priv); | 197 | unsigned long *priv); |
176 | void jffs2_gc_release_page(struct jffs2_sb_info *c, | 198 | void jffs2_gc_release_page(struct jffs2_sb_info *c, |
177 | unsigned char *pg, | 199 | unsigned char *pg, |
178 | unsigned long *priv); | 200 | unsigned long *priv); |
179 | void jffs2_flash_cleanup(struct jffs2_sb_info *c); | 201 | void jffs2_flash_cleanup(struct jffs2_sb_info *c); |
180 | 202 | ||
181 | 203 | ||
182 | /* writev.c */ | 204 | /* writev.c */ |
183 | int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, | 205 | int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, |
184 | unsigned long count, loff_t to, size_t *retlen); | 206 | unsigned long count, loff_t to, size_t *retlen); |
185 | 207 | int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, | |
208 | size_t *retlen, const u_char *buf); | ||
186 | 209 | ||
187 | #endif /* __JFFS2_OS_LINUX_H__ */ | 210 | #endif /* __JFFS2_OS_LINUX_H__ */ |
188 | 211 | ||
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index c7f9068907cf..f3b86da833ba 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $ | 10 | * $Id: read.c,v 1.42 2005/11/07 11:14:41 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -43,7 +43,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
43 | } | 43 | } |
44 | if (readlen != sizeof(*ri)) { | 44 | if (readlen != sizeof(*ri)) { |
45 | jffs2_free_raw_inode(ri); | 45 | jffs2_free_raw_inode(ri); |
46 | printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", | 46 | printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", |
47 | ref_offset(fd->raw), sizeof(*ri), readlen); | 47 | ref_offset(fd->raw), sizeof(*ri), readlen); |
48 | return -EIO; | 48 | return -EIO; |
49 | } | 49 | } |
@@ -61,7 +61,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
61 | } | 61 | } |
62 | /* There was a bug where we wrote hole nodes out with csize/dsize | 62 | /* There was a bug where we wrote hole nodes out with csize/dsize |
63 | swapped. Deal with it */ | 63 | swapped. Deal with it */ |
64 | if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && | 64 | if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && |
65 | je32_to_cpu(ri->csize)) { | 65 | je32_to_cpu(ri->csize)) { |
66 | ri->dsize = ri->csize; | 66 | ri->dsize = ri->csize; |
67 | ri->csize = cpu_to_je32(0); | 67 | ri->csize = cpu_to_je32(0); |
@@ -74,7 +74,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
74 | goto out_ri; | 74 | goto out_ri; |
75 | }); | 75 | }); |
76 | 76 | ||
77 | 77 | ||
78 | if (ri->compr == JFFS2_COMPR_ZERO) { | 78 | if (ri->compr == JFFS2_COMPR_ZERO) { |
79 | memset(buf, 0, len); | 79 | memset(buf, 0, len); |
80 | goto out_ri; | 80 | goto out_ri; |
@@ -82,8 +82,8 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
82 | 82 | ||
83 | /* Cases: | 83 | /* Cases: |
84 | Reading whole node and it's uncompressed - read directly to buffer provided, check CRC. | 84 | Reading whole node and it's uncompressed - read directly to buffer provided, check CRC. |
85 | Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided | 85 | Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided |
86 | Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy | 86 | Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy |
87 | Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy | 87 | Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy |
88 | */ | 88 | */ |
89 | if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { | 89 | if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { |
@@ -129,7 +129,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
129 | D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc)); | 129 | D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc)); |
130 | if (ri->compr != JFFS2_COMPR_NONE) { | 130 | if (ri->compr != JFFS2_COMPR_NONE) { |
131 | D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", | 131 | D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", |
132 | je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); | 132 | je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); |
133 | ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize)); | 133 | ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize)); |
134 | if (ret) { | 134 | if (ret) { |
135 | printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret); | 135 | printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret); |
@@ -174,7 +174,6 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
174 | if (frag) { | 174 | if (frag) { |
175 | D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); | 175 | D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); |
176 | holesize = min(holesize, frag->ofs - offset); | 176 | holesize = min(holesize, frag->ofs - offset); |
177 | D2(jffs2_print_frag_list(f)); | ||
178 | } | 177 | } |
179 | D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); | 178 | D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); |
180 | memset(buf, 0, holesize); | 179 | memset(buf, 0, holesize); |
@@ -192,7 +191,7 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
192 | } else { | 191 | } else { |
193 | uint32_t readlen; | 192 | uint32_t readlen; |
194 | uint32_t fragofs; /* offset within the frag to start reading */ | 193 | uint32_t fragofs; /* offset within the frag to start reading */ |
195 | 194 | ||
196 | fragofs = offset - frag->ofs; | 195 | fragofs = offset - frag->ofs; |
197 | readlen = min(frag->size - fragofs, end - offset); | 196 | readlen = min(frag->size - fragofs, end - offset); |
198 | D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n", | 197 | D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n", |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 1a96903e3ef3..5f0652df5d47 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -7,11 +7,12 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: readinode.c,v 1.125 2005/07/10 13:13:55 dedekind Exp $ | 10 | * $Id: readinode.c,v 1.143 2005/11/07 11:14:41 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/sched.h> | ||
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
17 | #include <linux/crc32.h> | 18 | #include <linux/crc32.h> |
@@ -20,502 +21,631 @@ | |||
20 | #include <linux/compiler.h> | 21 | #include <linux/compiler.h> |
21 | #include "nodelist.h" | 22 | #include "nodelist.h" |
22 | 23 | ||
23 | static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); | 24 | /* |
24 | 25 | * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in | |
25 | #if CONFIG_JFFS2_FS_DEBUG >= 2 | 26 | * order of increasing version. |
26 | static void jffs2_print_fragtree(struct rb_root *list, int permitbug) | 27 | */ |
28 | static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) | ||
27 | { | 29 | { |
28 | struct jffs2_node_frag *this = frag_first(list); | 30 | struct rb_node **p = &list->rb_node; |
29 | uint32_t lastofs = 0; | 31 | struct rb_node * parent = NULL; |
30 | int buggy = 0; | 32 | struct jffs2_tmp_dnode_info *this; |
31 | 33 | ||
32 | while(this) { | 34 | while (*p) { |
33 | if (this->node) | 35 | parent = *p; |
34 | printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n", | 36 | this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); |
35 | this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw), | 37 | |
36 | this, frag_left(this), frag_right(this), frag_parent(this)); | 38 | /* There may actually be a collision here, but it doesn't |
37 | else | 39 | actually matter. As long as the two nodes with the same |
38 | printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs, | 40 | version are together, it's all fine. */ |
39 | this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this)); | 41 | if (tn->version > this->version) |
40 | if (this->ofs != lastofs) | 42 | p = &(*p)->rb_left; |
41 | buggy = 1; | 43 | else |
42 | lastofs = this->ofs+this->size; | 44 | p = &(*p)->rb_right; |
43 | this = frag_next(this); | ||
44 | } | 45 | } |
45 | if (buggy && !permitbug) { | 46 | |
46 | printk(KERN_CRIT "Frag tree got a hole in it\n"); | 47 | rb_link_node(&tn->rb, parent, p); |
47 | BUG(); | 48 | rb_insert_color(&tn->rb, list); |
49 | } | ||
50 | |||
51 | static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) | ||
52 | { | ||
53 | struct rb_node *this; | ||
54 | struct jffs2_tmp_dnode_info *tn; | ||
55 | |||
56 | this = list->rb_node; | ||
57 | |||
58 | /* Now at bottom of tree */ | ||
59 | while (this) { | ||
60 | if (this->rb_left) | ||
61 | this = this->rb_left; | ||
62 | else if (this->rb_right) | ||
63 | this = this->rb_right; | ||
64 | else { | ||
65 | tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); | ||
66 | jffs2_free_full_dnode(tn->fn); | ||
67 | jffs2_free_tmp_dnode_info(tn); | ||
68 | |||
69 | this = this->rb_parent; | ||
70 | if (!this) | ||
71 | break; | ||
72 | |||
73 | if (this->rb_left == &tn->rb) | ||
74 | this->rb_left = NULL; | ||
75 | else if (this->rb_right == &tn->rb) | ||
76 | this->rb_right = NULL; | ||
77 | else BUG(); | ||
78 | } | ||
48 | } | 79 | } |
80 | list->rb_node = NULL; | ||
49 | } | 81 | } |
50 | 82 | ||
51 | void jffs2_print_frag_list(struct jffs2_inode_info *f) | 83 | static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) |
52 | { | 84 | { |
53 | jffs2_print_fragtree(&f->fragtree, 0); | 85 | struct jffs2_full_dirent *next; |
54 | 86 | ||
55 | if (f->metadata) { | 87 | while (fd) { |
56 | printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); | 88 | next = fd->next; |
89 | jffs2_free_full_dirent(fd); | ||
90 | fd = next; | ||
57 | } | 91 | } |
58 | } | 92 | } |
59 | #endif | ||
60 | 93 | ||
61 | #if CONFIG_JFFS2_FS_DEBUG >= 1 | 94 | /* Returns first valid node after 'ref'. May return 'ref' */ |
62 | static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f) | 95 | static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref) |
63 | { | 96 | { |
64 | struct jffs2_node_frag *frag; | 97 | while (ref && ref->next_in_ino) { |
65 | int bitched = 0; | 98 | if (!ref_obsolete(ref)) |
66 | 99 | return ref; | |
67 | for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { | 100 | dbg_noderef("node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)); |
101 | ref = ref->next_in_ino; | ||
102 | } | ||
103 | return NULL; | ||
104 | } | ||
68 | 105 | ||
69 | struct jffs2_full_dnode *fn = frag->node; | 106 | /* |
70 | if (!fn || !fn->raw) | 107 | * Helper function for jffs2_get_inode_nodes(). |
71 | continue; | 108 | * It is called every time an directory entry node is found. |
109 | * | ||
110 | * Returns: 0 on succes; | ||
111 | * 1 if the node should be marked obsolete; | ||
112 | * negative error code on failure. | ||
113 | */ | ||
114 | static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, | ||
115 | struct jffs2_raw_dirent *rd, uint32_t read, struct jffs2_full_dirent **fdp, | ||
116 | uint32_t *latest_mctime, uint32_t *mctime_ver) | ||
117 | { | ||
118 | struct jffs2_full_dirent *fd; | ||
119 | |||
120 | /* The direntry nodes are checked during the flash scanning */ | ||
121 | BUG_ON(ref_flags(ref) == REF_UNCHECKED); | ||
122 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ | ||
123 | BUG_ON(ref_obsolete(ref)); | ||
124 | |||
125 | /* Sanity check */ | ||
126 | if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { | ||
127 | JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", | ||
128 | ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); | ||
129 | return 1; | ||
130 | } | ||
72 | 131 | ||
73 | if (ref_flags(fn->raw) == REF_PRISTINE) { | 132 | fd = jffs2_alloc_full_dirent(rd->nsize + 1); |
133 | if (unlikely(!fd)) | ||
134 | return -ENOMEM; | ||
74 | 135 | ||
75 | if (fn->frags > 1) { | 136 | fd->raw = ref; |
76 | printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags); | 137 | fd->version = je32_to_cpu(rd->version); |
77 | bitched = 1; | 138 | fd->ino = je32_to_cpu(rd->ino); |
78 | } | 139 | fd->type = rd->type; |
79 | /* A hole node which isn't multi-page should be garbage-collected | ||
80 | and merged anyway, so we just check for the frag size here, | ||
81 | rather than mucking around with actually reading the node | ||
82 | and checking the compression type, which is the real way | ||
83 | to tell a hole node. */ | ||
84 | if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { | ||
85 | printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n", | ||
86 | ref_offset(fn->raw)); | ||
87 | bitched = 1; | ||
88 | } | ||
89 | 140 | ||
90 | if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { | 141 | /* Pick out the mctime of the latest dirent */ |
91 | printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n", | 142 | if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) { |
92 | ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); | 143 | *mctime_ver = fd->version; |
93 | bitched = 1; | 144 | *latest_mctime = je32_to_cpu(rd->mctime); |
94 | } | ||
95 | } | ||
96 | } | 145 | } |
97 | |||
98 | if (bitched) { | ||
99 | struct jffs2_node_frag *thisfrag; | ||
100 | |||
101 | printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino); | ||
102 | thisfrag = frag_first(&f->fragtree); | ||
103 | while (thisfrag) { | ||
104 | if (!thisfrag->node) { | ||
105 | printk("Frag @0x%x-0x%x; node-less hole\n", | ||
106 | thisfrag->ofs, thisfrag->size + thisfrag->ofs); | ||
107 | } else if (!thisfrag->node->raw) { | ||
108 | printk("Frag @0x%x-0x%x; raw-less hole\n", | ||
109 | thisfrag->ofs, thisfrag->size + thisfrag->ofs); | ||
110 | } else { | ||
111 | printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n", | ||
112 | thisfrag->ofs, thisfrag->size + thisfrag->ofs, | ||
113 | ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw), | ||
114 | thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size); | ||
115 | } | ||
116 | thisfrag = frag_next(thisfrag); | ||
117 | } | ||
118 | } | ||
119 | return bitched; | ||
120 | } | ||
121 | #endif /* D1 */ | ||
122 | 146 | ||
123 | static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) | 147 | /* |
124 | { | 148 | * Copy as much of the name as possible from the raw |
125 | if (this->node) { | 149 | * dirent we've already read from the flash. |
126 | this->node->frags--; | 150 | */ |
127 | if (!this->node->frags) { | 151 | if (read > sizeof(*rd)) |
128 | /* The node has no valid frags left. It's totally obsoleted */ | 152 | memcpy(&fd->name[0], &rd->name[0], |
129 | D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", | 153 | min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) )); |
130 | ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size)); | 154 | |
131 | jffs2_mark_node_obsolete(c, this->node->raw); | 155 | /* Do we need to copy any more of the name directly from the flash? */ |
132 | jffs2_free_full_dnode(this->node); | 156 | if (rd->nsize + sizeof(*rd) > read) { |
133 | } else { | 157 | /* FIXME: point() */ |
134 | D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", | 158 | int err; |
135 | ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, | 159 | int already = read - sizeof(*rd); |
136 | this->node->frags)); | 160 | |
137 | mark_ref_normal(this->node->raw); | 161 | err = jffs2_flash_read(c, (ref_offset(ref)) + read, |
162 | rd->nsize - already, &read, &fd->name[already]); | ||
163 | if (unlikely(read != rd->nsize - already) && likely(!err)) | ||
164 | return -EIO; | ||
165 | |||
166 | if (unlikely(err)) { | ||
167 | JFFS2_ERROR("read remainder of name: error %d\n", err); | ||
168 | jffs2_free_full_dirent(fd); | ||
169 | return -EIO; | ||
138 | } | 170 | } |
139 | |||
140 | } | 171 | } |
141 | jffs2_free_node_frag(this); | 172 | |
173 | fd->nhash = full_name_hash(fd->name, rd->nsize); | ||
174 | fd->next = NULL; | ||
175 | fd->name[rd->nsize] = '\0'; | ||
176 | |||
177 | /* | ||
178 | * Wheee. We now have a complete jffs2_full_dirent structure, with | ||
179 | * the name in it and everything. Link it into the list | ||
180 | */ | ||
181 | jffs2_add_fd_to_list(c, fd, fdp); | ||
182 | |||
183 | return 0; | ||
142 | } | 184 | } |
143 | 185 | ||
144 | /* Given an inode, probably with existing list of fragments, add the new node | 186 | /* |
145 | * to the fragment list. | 187 | * Helper function for jffs2_get_inode_nodes(). |
188 | * It is called every time an inode node is found. | ||
189 | * | ||
190 | * Returns: 0 on succes; | ||
191 | * 1 if the node should be marked obsolete; | ||
192 | * negative error code on failure. | ||
146 | */ | 193 | */ |
147 | int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) | 194 | static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, |
195 | struct jffs2_raw_inode *rd, struct rb_root *tnp, int rdlen, | ||
196 | uint32_t *latest_mctime, uint32_t *mctime_ver) | ||
148 | { | 197 | { |
149 | int ret; | 198 | struct jffs2_tmp_dnode_info *tn; |
150 | struct jffs2_node_frag *newfrag; | 199 | uint32_t len, csize; |
151 | 200 | int ret = 1; | |
152 | D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); | ||
153 | 201 | ||
154 | if (unlikely(!fn->size)) | 202 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ |
155 | return 0; | 203 | BUG_ON(ref_obsolete(ref)); |
156 | 204 | ||
157 | newfrag = jffs2_alloc_node_frag(); | 205 | tn = jffs2_alloc_tmp_dnode_info(); |
158 | if (unlikely(!newfrag)) | 206 | if (!tn) { |
207 | JFFS2_ERROR("failed to allocate tn (%d bytes).\n", sizeof(*tn)); | ||
159 | return -ENOMEM; | 208 | return -ENOMEM; |
209 | } | ||
160 | 210 | ||
161 | D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", | 211 | tn->partial_crc = 0; |
162 | fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); | 212 | csize = je32_to_cpu(rd->csize); |
163 | |||
164 | newfrag->ofs = fn->ofs; | ||
165 | newfrag->size = fn->size; | ||
166 | newfrag->node = fn; | ||
167 | newfrag->node->frags = 1; | ||
168 | 213 | ||
169 | ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); | 214 | /* If we've never checked the CRCs on this node, check them now */ |
170 | if (ret) | 215 | if (ref_flags(ref) == REF_UNCHECKED) { |
171 | return ret; | 216 | uint32_t crc; |
172 | 217 | ||
173 | /* If we now share a page with other nodes, mark either previous | 218 | crc = crc32(0, rd, sizeof(*rd) - 8); |
174 | or next node REF_NORMAL, as appropriate. */ | 219 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { |
175 | if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { | 220 | JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n", |
176 | struct jffs2_node_frag *prev = frag_prev(newfrag); | 221 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); |
222 | goto free_out; | ||
223 | } | ||
177 | 224 | ||
178 | mark_ref_normal(fn->raw); | 225 | /* Sanity checks */ |
179 | /* If we don't start at zero there's _always_ a previous */ | 226 | if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) || |
180 | if (prev->node) | 227 | unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) { |
181 | mark_ref_normal(prev->node->raw); | 228 | JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref)); |
182 | } | 229 | jffs2_dbg_dump_node(c, ref_offset(ref)); |
230 | goto free_out; | ||
231 | } | ||
183 | 232 | ||
184 | if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { | 233 | if (jffs2_is_writebuffered(c) && csize != 0) { |
185 | struct jffs2_node_frag *next = frag_next(newfrag); | 234 | /* At this point we are supposed to check the data CRC |
186 | 235 | * of our unchecked node. But thus far, we do not | |
187 | if (next) { | 236 | * know whether the node is valid or obsolete. To |
188 | mark_ref_normal(fn->raw); | 237 | * figure this out, we need to walk all the nodes of |
189 | if (next->node) | 238 | * the inode and build the inode fragtree. We don't |
190 | mark_ref_normal(next->node->raw); | 239 | * want to spend time checking data of nodes which may |
240 | * later be found to be obsolete. So we put off the full | ||
241 | * data CRC checking until we have read all the inode | ||
242 | * nodes and have started building the fragtree. | ||
243 | * | ||
244 | * The fragtree is being built starting with nodes | ||
245 | * having the highest version number, so we'll be able | ||
246 | * to detect whether a node is valid (i.e., it is not | ||
247 | * overlapped by a node with higher version) or not. | ||
248 | * And we'll be able to check only those nodes, which | ||
249 | * are not obsolete. | ||
250 | * | ||
251 | * Of course, this optimization only makes sense in case | ||
252 | * of NAND flashes (or other flashes whith | ||
253 | * !jffs2_can_mark_obsolete()), since on NOR flashes | ||
254 | * nodes are marked obsolete physically. | ||
255 | * | ||
256 | * Since NAND flashes (or other flashes with | ||
257 | * jffs2_is_writebuffered(c)) are anyway read by | ||
258 | * fractions of c->wbuf_pagesize, and we have just read | ||
259 | * the node header, it is likely that the starting part | ||
260 | * of the node data is also read when we read the | ||
261 | * header. So we don't mind to check the CRC of the | ||
262 | * starting part of the data of the node now, and check | ||
263 | * the second part later (in jffs2_check_node_data()). | ||
264 | * Of course, we will not need to re-read and re-check | ||
265 | * the NAND page which we have just read. This is why we | ||
266 | * read the whole NAND page at jffs2_get_inode_nodes(), | ||
267 | * while we needed only the node header. | ||
268 | */ | ||
269 | unsigned char *buf; | ||
270 | |||
271 | /* 'buf' will point to the start of data */ | ||
272 | buf = (unsigned char *)rd + sizeof(*rd); | ||
273 | /* len will be the read data length */ | ||
274 | len = min_t(uint32_t, rdlen - sizeof(*rd), csize); | ||
275 | tn->partial_crc = crc32(0, buf, len); | ||
276 | |||
277 | dbg_readinode("Calculates CRC (%#08x) for %d bytes, csize %d\n", tn->partial_crc, len, csize); | ||
278 | |||
279 | /* If we actually calculated the whole data CRC | ||
280 | * and it is wrong, drop the node. */ | ||
281 | if (len >= csize && unlikely(tn->partial_crc != je32_to_cpu(rd->data_crc))) { | ||
282 | JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", | ||
283 | ref_offset(ref), tn->partial_crc, je32_to_cpu(rd->data_crc)); | ||
284 | goto free_out; | ||
285 | } | ||
286 | |||
287 | } else if (csize == 0) { | ||
288 | /* | ||
289 | * We checked the header CRC. If the node has no data, adjust | ||
290 | * the space accounting now. For other nodes this will be done | ||
291 | * later either when the node is marked obsolete or when its | ||
292 | * data is checked. | ||
293 | */ | ||
294 | struct jffs2_eraseblock *jeb; | ||
295 | |||
296 | dbg_readinode("the node has no data.\n"); | ||
297 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | ||
298 | len = ref_totlen(c, jeb, ref); | ||
299 | |||
300 | spin_lock(&c->erase_completion_lock); | ||
301 | jeb->used_size += len; | ||
302 | jeb->unchecked_size -= len; | ||
303 | c->used_size += len; | ||
304 | c->unchecked_size -= len; | ||
305 | ref->flash_offset = ref_offset(ref) | REF_NORMAL; | ||
306 | spin_unlock(&c->erase_completion_lock); | ||
191 | } | 307 | } |
192 | } | 308 | } |
193 | D2(if (jffs2_sanitycheck_fragtree(f)) { | 309 | |
194 | printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n", | 310 | tn->fn = jffs2_alloc_full_dnode(); |
195 | fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); | 311 | if (!tn->fn) { |
196 | return 0; | 312 | JFFS2_ERROR("alloc fn failed\n"); |
197 | }) | 313 | ret = -ENOMEM; |
198 | D2(jffs2_print_frag_list(f)); | 314 | goto free_out; |
315 | } | ||
316 | |||
317 | tn->version = je32_to_cpu(rd->version); | ||
318 | tn->fn->ofs = je32_to_cpu(rd->offset); | ||
319 | tn->data_crc = je32_to_cpu(rd->data_crc); | ||
320 | tn->csize = csize; | ||
321 | tn->fn->raw = ref; | ||
322 | |||
323 | /* There was a bug where we wrote hole nodes out with | ||
324 | csize/dsize swapped. Deal with it */ | ||
325 | if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && csize) | ||
326 | tn->fn->size = csize; | ||
327 | else // normal case... | ||
328 | tn->fn->size = je32_to_cpu(rd->dsize); | ||
329 | |||
330 | dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", | ||
331 | ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); | ||
332 | |||
333 | jffs2_add_tn_to_tree(tn, tnp); | ||
334 | |||
199 | return 0; | 335 | return 0; |
336 | |||
337 | free_out: | ||
338 | jffs2_free_tmp_dnode_info(tn); | ||
339 | return ret; | ||
200 | } | 340 | } |
201 | 341 | ||
202 | /* Doesn't set inode->i_size */ | 342 | /* |
203 | static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) | 343 | * Helper function for jffs2_get_inode_nodes(). |
344 | * It is called every time an unknown node is found. | ||
345 | * | ||
346 | * Returns: 0 on succes; | ||
347 | * 1 if the node should be marked obsolete; | ||
348 | * negative error code on failure. | ||
349 | */ | ||
350 | static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un) | ||
204 | { | 351 | { |
205 | struct jffs2_node_frag *this; | 352 | /* We don't mark unknown nodes as REF_UNCHECKED */ |
206 | uint32_t lastend; | 353 | BUG_ON(ref_flags(ref) == REF_UNCHECKED); |
207 | 354 | ||
208 | /* Skip all the nodes which are completed before this one starts */ | 355 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); |
209 | this = jffs2_lookup_node_frag(list, newfrag->node->ofs); | ||
210 | 356 | ||
211 | if (this) { | 357 | if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) { |
212 | D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", | 358 | /* Hmmm. This should have been caught at scan time. */ |
213 | this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); | 359 | JFFS2_NOTICE("node header CRC failed at %#08x. But it must have been OK earlier.\n", ref_offset(ref)); |
214 | lastend = this->ofs + this->size; | 360 | jffs2_dbg_dump_node(c, ref_offset(ref)); |
361 | return 1; | ||
215 | } else { | 362 | } else { |
216 | D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n")); | 363 | switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) { |
217 | lastend = 0; | ||
218 | } | ||
219 | |||
220 | /* See if we ran off the end of the list */ | ||
221 | if (lastend <= newfrag->ofs) { | ||
222 | /* We did */ | ||
223 | |||
224 | /* Check if 'this' node was on the same page as the new node. | ||
225 | If so, both 'this' and the new node get marked REF_NORMAL so | ||
226 | the GC can take a look. | ||
227 | */ | ||
228 | if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { | ||
229 | if (this->node) | ||
230 | mark_ref_normal(this->node->raw); | ||
231 | mark_ref_normal(newfrag->node->raw); | ||
232 | } | ||
233 | 364 | ||
234 | if (lastend < newfrag->node->ofs) { | 365 | case JFFS2_FEATURE_INCOMPAT: |
235 | /* ... and we need to put a hole in before the new node */ | 366 | JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n", |
236 | struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); | 367 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
237 | if (!holefrag) { | 368 | /* EEP */ |
238 | jffs2_free_node_frag(newfrag); | 369 | BUG(); |
239 | return -ENOMEM; | 370 | break; |
240 | } | 371 | |
241 | holefrag->ofs = lastend; | 372 | case JFFS2_FEATURE_ROCOMPAT: |
242 | holefrag->size = newfrag->node->ofs - lastend; | 373 | JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n", |
243 | holefrag->node = NULL; | 374 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
244 | if (this) { | 375 | BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO)); |
245 | /* By definition, the 'this' node has no right-hand child, | 376 | break; |
246 | because there are no frags with offset greater than it. | 377 | |
247 | So that's where we want to put the hole */ | 378 | case JFFS2_FEATURE_RWCOMPAT_COPY: |
248 | D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this)); | 379 | JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n", |
249 | rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); | 380 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
250 | } else { | 381 | break; |
251 | D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag)); | 382 | |
252 | rb_link_node(&holefrag->rb, NULL, &list->rb_node); | 383 | case JFFS2_FEATURE_RWCOMPAT_DELETE: |
253 | } | 384 | JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", |
254 | rb_insert_color(&holefrag->rb, list); | 385 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
255 | this = holefrag; | 386 | return 1; |
256 | } | ||
257 | if (this) { | ||
258 | /* By definition, the 'this' node has no right-hand child, | ||
259 | because there are no frags with offset greater than it. | ||
260 | So that's where we want to put the hole */ | ||
261 | D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this)); | ||
262 | rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); | ||
263 | } else { | ||
264 | D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag)); | ||
265 | rb_link_node(&newfrag->rb, NULL, &list->rb_node); | ||
266 | } | 387 | } |
267 | rb_insert_color(&newfrag->rb, list); | ||
268 | return 0; | ||
269 | } | 388 | } |
270 | 389 | ||
271 | D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", | 390 | return 0; |
272 | this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); | 391 | } |
273 | 392 | ||
274 | /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, | 393 | /* |
275 | * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs | 394 | * Helper function for jffs2_get_inode_nodes(). |
276 | */ | 395 | * The function detects whether more data should be read and reads it if yes. |
277 | if (newfrag->ofs > this->ofs) { | 396 | * |
278 | /* This node isn't completely obsoleted. The start of it remains valid */ | 397 | * Returns: 0 on succes; |
279 | 398 | * negative error code on failure. | |
280 | /* Mark the new node and the partially covered node REF_NORMAL -- let | 399 | */ |
281 | the GC take a look at them */ | 400 | static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, |
282 | mark_ref_normal(newfrag->node->raw); | 401 | int right_size, int *rdlen, unsigned char *buf, unsigned char *bufstart) |
283 | if (this->node) | 402 | { |
284 | mark_ref_normal(this->node->raw); | 403 | int right_len, err, len; |
285 | 404 | size_t retlen; | |
286 | if (this->ofs + this->size > newfrag->ofs + newfrag->size) { | 405 | uint32_t offs; |
287 | /* The new node splits 'this' frag into two */ | ||
288 | struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag(); | ||
289 | if (!newfrag2) { | ||
290 | jffs2_free_node_frag(newfrag); | ||
291 | return -ENOMEM; | ||
292 | } | ||
293 | D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); | ||
294 | if (this->node) | ||
295 | printk("phys 0x%08x\n", ref_offset(this->node->raw)); | ||
296 | else | ||
297 | printk("hole\n"); | ||
298 | ) | ||
299 | |||
300 | /* New second frag pointing to this's node */ | ||
301 | newfrag2->ofs = newfrag->ofs + newfrag->size; | ||
302 | newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; | ||
303 | newfrag2->node = this->node; | ||
304 | if (this->node) | ||
305 | this->node->frags++; | ||
306 | |||
307 | /* Adjust size of original 'this' */ | ||
308 | this->size = newfrag->ofs - this->ofs; | ||
309 | |||
310 | /* Now, we know there's no node with offset | ||
311 | greater than this->ofs but smaller than | ||
312 | newfrag2->ofs or newfrag->ofs, for obvious | ||
313 | reasons. So we can do a tree insert from | ||
314 | 'this' to insert newfrag, and a tree insert | ||
315 | from newfrag to insert newfrag2. */ | ||
316 | jffs2_fragtree_insert(newfrag, this); | ||
317 | rb_insert_color(&newfrag->rb, list); | ||
318 | |||
319 | jffs2_fragtree_insert(newfrag2, newfrag); | ||
320 | rb_insert_color(&newfrag2->rb, list); | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | /* New node just reduces 'this' frag in size, doesn't split it */ | ||
325 | this->size = newfrag->ofs - this->ofs; | ||
326 | 406 | ||
327 | /* Again, we know it lives down here in the tree */ | 407 | if (jffs2_is_writebuffered(c)) { |
328 | jffs2_fragtree_insert(newfrag, this); | 408 | right_len = c->wbuf_pagesize - (bufstart - buf); |
329 | rb_insert_color(&newfrag->rb, list); | 409 | if (right_size + (int)(bufstart - buf) > c->wbuf_pagesize) |
330 | } else { | 410 | right_len += c->wbuf_pagesize; |
331 | /* New frag starts at the same point as 'this' used to. Replace | 411 | } else |
332 | it in the tree without doing a delete and insertion */ | 412 | right_len = right_size; |
333 | D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", | ||
334 | newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, | ||
335 | this, this->ofs, this->ofs+this->size)); | ||
336 | |||
337 | rb_replace_node(&this->rb, &newfrag->rb, list); | ||
338 | |||
339 | if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { | ||
340 | D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size)); | ||
341 | jffs2_obsolete_node_frag(c, this); | ||
342 | } else { | ||
343 | this->ofs += newfrag->size; | ||
344 | this->size -= newfrag->size; | ||
345 | 413 | ||
346 | jffs2_fragtree_insert(this, newfrag); | 414 | if (*rdlen == right_len) |
347 | rb_insert_color(&this->rb, list); | 415 | return 0; |
348 | return 0; | 416 | |
349 | } | 417 | /* We need to read more data */ |
418 | offs = ref_offset(ref) + *rdlen; | ||
419 | if (jffs2_is_writebuffered(c)) { | ||
420 | bufstart = buf + c->wbuf_pagesize; | ||
421 | len = c->wbuf_pagesize; | ||
422 | } else { | ||
423 | bufstart = buf + *rdlen; | ||
424 | len = right_size - *rdlen; | ||
350 | } | 425 | } |
351 | /* OK, now we have newfrag added in the correct place in the tree, but | 426 | |
352 | frag_next(newfrag) may be a fragment which is overlapped by it | 427 | dbg_readinode("read more %d bytes\n", len); |
353 | */ | 428 | |
354 | while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { | 429 | err = jffs2_flash_read(c, offs, len, &retlen, bufstart); |
355 | /* 'this' frag is obsoleted completely. */ | 430 | if (err) { |
356 | D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size)); | 431 | JFFS2_ERROR("can not read %d bytes from 0x%08x, " |
357 | rb_erase(&this->rb, list); | 432 | "error code: %d.\n", len, offs, err); |
358 | jffs2_obsolete_node_frag(c, this); | 433 | return err; |
359 | } | 434 | } |
360 | /* Now we're pointing at the first frag which isn't totally obsoleted by | ||
361 | the new frag */ | ||
362 | 435 | ||
363 | if (!this || newfrag->ofs + newfrag->size == this->ofs) { | 436 | if (retlen < len) { |
364 | return 0; | 437 | JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", |
438 | offs, retlen, len); | ||
439 | return -EIO; | ||
365 | } | 440 | } |
366 | /* Still some overlap but we don't need to move it in the tree */ | ||
367 | this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); | ||
368 | this->ofs = newfrag->ofs + newfrag->size; | ||
369 | 441 | ||
370 | /* And mark them REF_NORMAL so the GC takes a look at them */ | 442 | *rdlen = right_len; |
371 | if (this->node) | ||
372 | mark_ref_normal(this->node->raw); | ||
373 | mark_ref_normal(newfrag->node->raw); | ||
374 | 443 | ||
375 | return 0; | 444 | return 0; |
376 | } | 445 | } |
377 | 446 | ||
378 | void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) | 447 | /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated |
448 | with this ino, returning the former in order of version */ | ||
449 | static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | ||
450 | struct rb_root *tnp, struct jffs2_full_dirent **fdp, | ||
451 | uint32_t *highest_version, uint32_t *latest_mctime, | ||
452 | uint32_t *mctime_ver) | ||
379 | { | 453 | { |
380 | struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); | 454 | struct jffs2_raw_node_ref *ref, *valid_ref; |
455 | struct rb_root ret_tn = RB_ROOT; | ||
456 | struct jffs2_full_dirent *ret_fd = NULL; | ||
457 | unsigned char *buf = NULL; | ||
458 | union jffs2_node_union *node; | ||
459 | size_t retlen; | ||
460 | int len, err; | ||
461 | |||
462 | *mctime_ver = 0; | ||
463 | |||
464 | dbg_readinode("ino #%u\n", f->inocache->ino); | ||
465 | |||
466 | if (jffs2_is_writebuffered(c)) { | ||
467 | /* | ||
468 | * If we have the write buffer, we assume the minimal I/O unit | ||
469 | * is c->wbuf_pagesize. We implement some optimizations which in | ||
470 | * this case and we need a temporary buffer of size = | ||
471 | * 2*c->wbuf_pagesize bytes (see comments in read_dnode()). | ||
472 | * Basically, we want to read not only the node header, but the | ||
473 | * whole wbuf (NAND page in case of NAND) or 2, if the node | ||
474 | * header overlaps the border between the 2 wbufs. | ||
475 | */ | ||
476 | len = 2*c->wbuf_pagesize; | ||
477 | } else { | ||
478 | /* | ||
479 | * When there is no write buffer, the size of the temporary | ||
480 | * buffer is the size of the larges node header. | ||
481 | */ | ||
482 | len = sizeof(union jffs2_node_union); | ||
483 | } | ||
381 | 484 | ||
382 | D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size)); | 485 | /* FIXME: in case of NOR and available ->point() this |
486 | * needs to be fixed. */ | ||
487 | buf = kmalloc(len, GFP_KERNEL); | ||
488 | if (!buf) | ||
489 | return -ENOMEM; | ||
383 | 490 | ||
384 | /* We know frag->ofs <= size. That's what lookup does for us */ | 491 | spin_lock(&c->erase_completion_lock); |
385 | if (frag && frag->ofs != size) { | 492 | valid_ref = jffs2_first_valid_node(f->inocache->nodes); |
386 | if (frag->ofs+frag->size >= size) { | 493 | if (!valid_ref && f->inocache->ino != 1) |
387 | D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); | 494 | JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino); |
388 | frag->size = size - frag->ofs; | 495 | while (valid_ref) { |
496 | unsigned char *bufstart; | ||
497 | |||
498 | /* We can hold a pointer to a non-obsolete node without the spinlock, | ||
499 | but _obsolete_ nodes may disappear at any time, if the block | ||
500 | they're in gets erased. So if we mark 'ref' obsolete while we're | ||
501 | not holding the lock, it can go away immediately. For that reason, | ||
502 | we find the next valid node first, before processing 'ref'. | ||
503 | */ | ||
504 | ref = valid_ref; | ||
505 | valid_ref = jffs2_first_valid_node(ref->next_in_ino); | ||
506 | spin_unlock(&c->erase_completion_lock); | ||
507 | |||
508 | cond_resched(); | ||
509 | |||
510 | /* | ||
511 | * At this point we don't know the type of the node we're going | ||
512 | * to read, so we do not know the size of its header. In order | ||
513 | * to minimize the amount of flash IO we assume the node has | ||
514 | * size = JFFS2_MIN_NODE_HEADER. | ||
515 | */ | ||
516 | if (jffs2_is_writebuffered(c)) { | ||
517 | /* | ||
518 | * We treat 'buf' as 2 adjacent wbufs. We want to | ||
519 | * adjust bufstart such as it points to the | ||
520 | * beginning of the node within this wbuf. | ||
521 | */ | ||
522 | bufstart = buf + (ref_offset(ref) % c->wbuf_pagesize); | ||
523 | /* We will read either one wbuf or 2 wbufs. */ | ||
524 | len = c->wbuf_pagesize - (bufstart - buf); | ||
525 | if (JFFS2_MIN_NODE_HEADER + (int)(bufstart - buf) > c->wbuf_pagesize) { | ||
526 | /* The header spans the border of the first wbuf */ | ||
527 | len += c->wbuf_pagesize; | ||
528 | } | ||
529 | } else { | ||
530 | bufstart = buf; | ||
531 | len = JFFS2_MIN_NODE_HEADER; | ||
389 | } | 532 | } |
390 | frag = frag_next(frag); | ||
391 | } | ||
392 | while (frag && frag->ofs >= size) { | ||
393 | struct jffs2_node_frag *next = frag_next(frag); | ||
394 | 533 | ||
395 | D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); | 534 | dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref)); |
396 | frag_erase(frag, list); | ||
397 | jffs2_obsolete_node_frag(c, frag); | ||
398 | frag = next; | ||
399 | } | ||
400 | } | ||
401 | 535 | ||
402 | /* Scan the list of all nodes present for this ino, build map of versions, etc. */ | 536 | /* FIXME: point() */ |
537 | err = jffs2_flash_read(c, ref_offset(ref), len, | ||
538 | &retlen, bufstart); | ||
539 | if (err) { | ||
540 | JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", len, ref_offset(ref), err); | ||
541 | goto free_out; | ||
542 | } | ||
403 | 543 | ||
404 | static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | 544 | if (retlen < len) { |
405 | struct jffs2_inode_info *f, | 545 | JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ref_offset(ref), retlen, len); |
406 | struct jffs2_raw_inode *latest_node); | 546 | err = -EIO; |
547 | goto free_out; | ||
548 | } | ||
407 | 549 | ||
408 | int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 550 | node = (union jffs2_node_union *)bufstart; |
409 | uint32_t ino, struct jffs2_raw_inode *latest_node) | ||
410 | { | ||
411 | D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n")); | ||
412 | 551 | ||
413 | retry_inocache: | 552 | switch (je16_to_cpu(node->u.nodetype)) { |
414 | spin_lock(&c->inocache_lock); | ||
415 | f->inocache = jffs2_get_ino_cache(c, ino); | ||
416 | 553 | ||
417 | D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache)); | 554 | case JFFS2_NODETYPE_DIRENT: |
555 | |||
556 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) { | ||
557 | err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf, bufstart); | ||
558 | if (unlikely(err)) | ||
559 | goto free_out; | ||
560 | } | ||
561 | |||
562 | err = read_direntry(c, ref, &node->d, retlen, &ret_fd, latest_mctime, mctime_ver); | ||
563 | if (err == 1) { | ||
564 | jffs2_mark_node_obsolete(c, ref); | ||
565 | break; | ||
566 | } else if (unlikely(err)) | ||
567 | goto free_out; | ||
568 | |||
569 | if (je32_to_cpu(node->d.version) > *highest_version) | ||
570 | *highest_version = je32_to_cpu(node->d.version); | ||
418 | 571 | ||
419 | if (f->inocache) { | ||
420 | /* Check its state. We may need to wait before we can use it */ | ||
421 | switch(f->inocache->state) { | ||
422 | case INO_STATE_UNCHECKED: | ||
423 | case INO_STATE_CHECKEDABSENT: | ||
424 | f->inocache->state = INO_STATE_READING; | ||
425 | break; | 572 | break; |
426 | |||
427 | case INO_STATE_CHECKING: | ||
428 | case INO_STATE_GC: | ||
429 | /* If it's in either of these states, we need | ||
430 | to wait for whoever's got it to finish and | ||
431 | put it back. */ | ||
432 | D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n", | ||
433 | ino, f->inocache->state)); | ||
434 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); | ||
435 | goto retry_inocache; | ||
436 | 573 | ||
437 | case INO_STATE_READING: | 574 | case JFFS2_NODETYPE_INODE: |
438 | case INO_STATE_PRESENT: | 575 | |
439 | /* Eep. This should never happen. It can | 576 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) { |
440 | happen if Linux calls read_inode() again | 577 | err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf, bufstart); |
441 | before clear_inode() has finished though. */ | 578 | if (unlikely(err)) |
442 | printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); | 579 | goto free_out; |
443 | /* Fail. That's probably better than allowing it to succeed */ | 580 | } |
444 | f->inocache = NULL; | 581 | |
582 | err = read_dnode(c, ref, &node->i, &ret_tn, len, latest_mctime, mctime_ver); | ||
583 | if (err == 1) { | ||
584 | jffs2_mark_node_obsolete(c, ref); | ||
585 | break; | ||
586 | } else if (unlikely(err)) | ||
587 | goto free_out; | ||
588 | |||
589 | if (je32_to_cpu(node->i.version) > *highest_version) | ||
590 | *highest_version = je32_to_cpu(node->i.version); | ||
591 | |||
445 | break; | 592 | break; |
446 | 593 | ||
447 | default: | 594 | default: |
448 | BUG(); | 595 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) { |
449 | } | 596 | err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf, bufstart); |
450 | } | 597 | if (unlikely(err)) |
451 | spin_unlock(&c->inocache_lock); | 598 | goto free_out; |
599 | } | ||
600 | |||
601 | err = read_unknown(c, ref, &node->u); | ||
602 | if (err == 1) { | ||
603 | jffs2_mark_node_obsolete(c, ref); | ||
604 | break; | ||
605 | } else if (unlikely(err)) | ||
606 | goto free_out; | ||
452 | 607 | ||
453 | if (!f->inocache && ino == 1) { | ||
454 | /* Special case - no root inode on medium */ | ||
455 | f->inocache = jffs2_alloc_inode_cache(); | ||
456 | if (!f->inocache) { | ||
457 | printk(KERN_CRIT "jffs2_do_read_inode(): Cannot allocate inocache for root inode\n"); | ||
458 | return -ENOMEM; | ||
459 | } | 608 | } |
460 | D1(printk(KERN_DEBUG "jffs2_do_read_inode(): Creating inocache for root inode\n")); | 609 | spin_lock(&c->erase_completion_lock); |
461 | memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); | ||
462 | f->inocache->ino = f->inocache->nlink = 1; | ||
463 | f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; | ||
464 | f->inocache->state = INO_STATE_READING; | ||
465 | jffs2_add_ino_cache(c, f->inocache); | ||
466 | } | 610 | } |
467 | if (!f->inocache) { | ||
468 | printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino); | ||
469 | return -ENOENT; | ||
470 | } | ||
471 | |||
472 | return jffs2_do_read_inode_internal(c, f, latest_node); | ||
473 | } | ||
474 | 611 | ||
475 | int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) | 612 | spin_unlock(&c->erase_completion_lock); |
476 | { | 613 | *tnp = ret_tn; |
477 | struct jffs2_raw_inode n; | 614 | *fdp = ret_fd; |
478 | struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); | 615 | kfree(buf); |
479 | int ret; | ||
480 | 616 | ||
481 | if (!f) | 617 | dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n", |
482 | return -ENOMEM; | 618 | f->inocache->ino, *highest_version, *latest_mctime, *mctime_ver); |
483 | 619 | return 0; | |
484 | memset(f, 0, sizeof(*f)); | ||
485 | init_MUTEX_LOCKED(&f->sem); | ||
486 | f->inocache = ic; | ||
487 | 620 | ||
488 | ret = jffs2_do_read_inode_internal(c, f, &n); | 621 | free_out: |
489 | if (!ret) { | 622 | jffs2_free_tmp_dnode_info_list(&ret_tn); |
490 | up(&f->sem); | 623 | jffs2_free_full_dirent_list(ret_fd); |
491 | jffs2_do_clear_inode(c, f); | 624 | kfree(buf); |
492 | } | 625 | return err; |
493 | kfree(f); | ||
494 | return ret; | ||
495 | } | 626 | } |
496 | 627 | ||
497 | static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | 628 | static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, |
498 | struct jffs2_inode_info *f, | 629 | struct jffs2_inode_info *f, |
499 | struct jffs2_raw_inode *latest_node) | 630 | struct jffs2_raw_inode *latest_node) |
500 | { | 631 | { |
501 | struct jffs2_tmp_dnode_info *tn = NULL; | 632 | struct jffs2_tmp_dnode_info *tn; |
502 | struct rb_root tn_list; | 633 | struct rb_root tn_list; |
503 | struct rb_node *rb, *repl_rb; | 634 | struct rb_node *rb, *repl_rb; |
504 | struct jffs2_full_dirent *fd_list; | 635 | struct jffs2_full_dirent *fd_list; |
505 | struct jffs2_full_dnode *fn = NULL; | 636 | struct jffs2_full_dnode *fn, *first_fn = NULL; |
506 | uint32_t crc; | 637 | uint32_t crc; |
507 | uint32_t latest_mctime, mctime_ver; | 638 | uint32_t latest_mctime, mctime_ver; |
508 | uint32_t mdata_ver = 0; | ||
509 | size_t retlen; | 639 | size_t retlen; |
510 | int ret; | 640 | int ret; |
511 | 641 | ||
512 | D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink)); | 642 | dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink); |
513 | 643 | ||
514 | /* Grab all nodes relevant to this ino */ | 644 | /* Grab all nodes relevant to this ino */ |
515 | ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); | 645 | ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); |
516 | 646 | ||
517 | if (ret) { | 647 | if (ret) { |
518 | printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret); | 648 | JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret); |
519 | if (f->inocache->state == INO_STATE_READING) | 649 | if (f->inocache->state == INO_STATE_READING) |
520 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); | 650 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
521 | return ret; | 651 | return ret; |
@@ -525,42 +655,33 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
525 | rb = rb_first(&tn_list); | 655 | rb = rb_first(&tn_list); |
526 | 656 | ||
527 | while (rb) { | 657 | while (rb) { |
658 | cond_resched(); | ||
528 | tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); | 659 | tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); |
529 | fn = tn->fn; | 660 | fn = tn->fn; |
530 | 661 | ret = 1; | |
531 | if (f->metadata) { | 662 | dbg_readinode("consider node ver %u, phys offset " |
532 | if (likely(tn->version >= mdata_ver)) { | 663 | "%#08x(%d), range %u-%u.\n", tn->version, |
533 | D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); | 664 | ref_offset(fn->raw), ref_flags(fn->raw), |
534 | jffs2_mark_node_obsolete(c, f->metadata->raw); | 665 | fn->ofs, fn->ofs + fn->size); |
535 | jffs2_free_full_dnode(f->metadata); | ||
536 | f->metadata = NULL; | ||
537 | |||
538 | mdata_ver = 0; | ||
539 | } else { | ||
540 | /* This should never happen. */ | ||
541 | printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n", | ||
542 | ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw)); | ||
543 | jffs2_mark_node_obsolete(c, fn->raw); | ||
544 | jffs2_free_full_dnode(fn); | ||
545 | /* Fill in latest_node from the metadata, not this one we're about to free... */ | ||
546 | fn = f->metadata; | ||
547 | goto next_tn; | ||
548 | } | ||
549 | } | ||
550 | 666 | ||
551 | if (fn->size) { | 667 | if (fn->size) { |
552 | jffs2_add_full_dnode_to_inode(c, f, fn); | 668 | ret = jffs2_add_older_frag_to_fragtree(c, f, tn); |
553 | } else { | 669 | /* TODO: the error code isn't checked, check it */ |
554 | /* Zero-sized node at end of version list. Just a metadata update */ | 670 | jffs2_dbg_fragtree_paranoia_check_nolock(f); |
555 | D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version)); | 671 | BUG_ON(ret < 0); |
672 | if (!first_fn && ret == 0) | ||
673 | first_fn = fn; | ||
674 | } else if (!first_fn) { | ||
675 | first_fn = fn; | ||
556 | f->metadata = fn; | 676 | f->metadata = fn; |
557 | mdata_ver = tn->version; | 677 | ret = 0; /* Prevent freeing the metadata update node */ |
558 | } | 678 | } else |
559 | next_tn: | 679 | jffs2_mark_node_obsolete(c, fn->raw); |
680 | |||
560 | BUG_ON(rb->rb_left); | 681 | BUG_ON(rb->rb_left); |
561 | if (rb->rb_parent && rb->rb_parent->rb_left == rb) { | 682 | if (rb->rb_parent && rb->rb_parent->rb_left == rb) { |
562 | /* We were then left-hand child of our parent. We need | 683 | /* We were then left-hand child of our parent. We need |
563 | to move our own right-hand child into our place. */ | 684 | * to move our own right-hand child into our place. */ |
564 | repl_rb = rb->rb_right; | 685 | repl_rb = rb->rb_right; |
565 | if (repl_rb) | 686 | if (repl_rb) |
566 | repl_rb->rb_parent = rb->rb_parent; | 687 | repl_rb->rb_parent = rb->rb_parent; |
@@ -570,7 +691,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
570 | rb = rb_next(rb); | 691 | rb = rb_next(rb); |
571 | 692 | ||
572 | /* Remove the spent tn from the tree; don't bother rebalancing | 693 | /* Remove the spent tn from the tree; don't bother rebalancing |
573 | but put our right-hand child in our own place. */ | 694 | * but put our right-hand child in our own place. */ |
574 | if (tn->rb.rb_parent) { | 695 | if (tn->rb.rb_parent) { |
575 | if (tn->rb.rb_parent->rb_left == &tn->rb) | 696 | if (tn->rb.rb_parent->rb_left == &tn->rb) |
576 | tn->rb.rb_parent->rb_left = repl_rb; | 697 | tn->rb.rb_parent->rb_left = repl_rb; |
@@ -581,19 +702,27 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
581 | tn->rb.rb_right->rb_parent = NULL; | 702 | tn->rb.rb_right->rb_parent = NULL; |
582 | 703 | ||
583 | jffs2_free_tmp_dnode_info(tn); | 704 | jffs2_free_tmp_dnode_info(tn); |
705 | if (ret) { | ||
706 | dbg_readinode("delete dnode %u-%u.\n", | ||
707 | fn->ofs, fn->ofs + fn->size); | ||
708 | jffs2_free_full_dnode(fn); | ||
709 | } | ||
584 | } | 710 | } |
585 | D1(jffs2_sanitycheck_fragtree(f)); | 711 | jffs2_dbg_fragtree_paranoia_check_nolock(f); |
586 | 712 | ||
587 | if (!fn) { | 713 | BUG_ON(first_fn && ref_obsolete(first_fn->raw)); |
714 | |||
715 | fn = first_fn; | ||
716 | if (unlikely(!first_fn)) { | ||
588 | /* No data nodes for this inode. */ | 717 | /* No data nodes for this inode. */ |
589 | if (f->inocache->ino != 1) { | 718 | if (f->inocache->ino != 1) { |
590 | printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino); | 719 | JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino); |
591 | if (!fd_list) { | 720 | if (!fd_list) { |
592 | if (f->inocache->state == INO_STATE_READING) | 721 | if (f->inocache->state == INO_STATE_READING) |
593 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); | 722 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
594 | return -EIO; | 723 | return -EIO; |
595 | } | 724 | } |
596 | printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n"); | 725 | JFFS2_NOTICE("but it has children so we fake some modes for it\n"); |
597 | } | 726 | } |
598 | latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); | 727 | latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); |
599 | latest_node->version = cpu_to_je32(0); | 728 | latest_node->version = cpu_to_je32(0); |
@@ -608,8 +737,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
608 | 737 | ||
609 | ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); | 738 | ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); |
610 | if (ret || retlen != sizeof(*latest_node)) { | 739 | if (ret || retlen != sizeof(*latest_node)) { |
611 | printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n", | 740 | JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", |
612 | ret, retlen, sizeof(*latest_node)); | 741 | ret, retlen, sizeof(*latest_node)); |
613 | /* FIXME: If this fails, there seems to be a memory leak. Find it. */ | 742 | /* FIXME: If this fails, there seems to be a memory leak. Find it. */ |
614 | up(&f->sem); | 743 | up(&f->sem); |
615 | jffs2_do_clear_inode(c, f); | 744 | jffs2_do_clear_inode(c, f); |
@@ -618,7 +747,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
618 | 747 | ||
619 | crc = crc32(0, latest_node, sizeof(*latest_node)-8); | 748 | crc = crc32(0, latest_node, sizeof(*latest_node)-8); |
620 | if (crc != je32_to_cpu(latest_node->node_crc)) { | 749 | if (crc != je32_to_cpu(latest_node->node_crc)) { |
621 | printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw)); | 750 | JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", |
751 | f->inocache->ino, ref_offset(fn->raw)); | ||
622 | up(&f->sem); | 752 | up(&f->sem); |
623 | jffs2_do_clear_inode(c, f); | 753 | jffs2_do_clear_inode(c, f); |
624 | return -EIO; | 754 | return -EIO; |
@@ -633,10 +763,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
633 | } | 763 | } |
634 | break; | 764 | break; |
635 | 765 | ||
636 | 766 | ||
637 | case S_IFREG: | 767 | case S_IFREG: |
638 | /* If it was a regular file, truncate it to the latest node's isize */ | 768 | /* If it was a regular file, truncate it to the latest node's isize */ |
639 | jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize)); | 769 | jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); |
640 | break; | 770 | break; |
641 | 771 | ||
642 | case S_IFLNK: | 772 | case S_IFLNK: |
@@ -649,37 +779,33 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
649 | 779 | ||
650 | if (f->inocache->state != INO_STATE_CHECKING) { | 780 | if (f->inocache->state != INO_STATE_CHECKING) { |
651 | /* Symlink's inode data is the target path. Read it and | 781 | /* Symlink's inode data is the target path. Read it and |
652 | * keep in RAM to facilitate quick follow symlink operation. | 782 | * keep in RAM to facilitate quick follow symlink |
653 | * We use f->dents field to store the target path, which | 783 | * operation. */ |
654 | * is somewhat ugly. */ | 784 | f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); |
655 | f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); | 785 | if (!f->target) { |
656 | if (!f->dents) { | 786 | JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); |
657 | printk(KERN_WARNING "Can't allocate %d bytes of memory " | ||
658 | "for the symlink target path cache\n", | ||
659 | je32_to_cpu(latest_node->csize)); | ||
660 | up(&f->sem); | 787 | up(&f->sem); |
661 | jffs2_do_clear_inode(c, f); | 788 | jffs2_do_clear_inode(c, f); |
662 | return -ENOMEM; | 789 | return -ENOMEM; |
663 | } | 790 | } |
664 | 791 | ||
665 | ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), | 792 | ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), |
666 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); | 793 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->target); |
667 | 794 | ||
668 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { | 795 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { |
669 | if (retlen != je32_to_cpu(latest_node->csize)) | 796 | if (retlen != je32_to_cpu(latest_node->csize)) |
670 | ret = -EIO; | 797 | ret = -EIO; |
671 | kfree(f->dents); | 798 | kfree(f->target); |
672 | f->dents = NULL; | 799 | f->target = NULL; |
673 | up(&f->sem); | 800 | up(&f->sem); |
674 | jffs2_do_clear_inode(c, f); | 801 | jffs2_do_clear_inode(c, f); |
675 | return -ret; | 802 | return -ret; |
676 | } | 803 | } |
677 | 804 | ||
678 | ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; | 805 | f->target[je32_to_cpu(latest_node->csize)] = '\0'; |
679 | D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", | 806 | dbg_readinode("symlink's target '%s' cached\n", f->target); |
680 | (char *)f->dents)); | ||
681 | } | 807 | } |
682 | 808 | ||
683 | /* fall through... */ | 809 | /* fall through... */ |
684 | 810 | ||
685 | case S_IFBLK: | 811 | case S_IFBLK: |
@@ -687,14 +813,14 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
687 | /* Certain inode types should have only one data node, and it's | 813 | /* Certain inode types should have only one data node, and it's |
688 | kept as the metadata node */ | 814 | kept as the metadata node */ |
689 | if (f->metadata) { | 815 | if (f->metadata) { |
690 | printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", | 816 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n", |
691 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 817 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
692 | up(&f->sem); | 818 | up(&f->sem); |
693 | jffs2_do_clear_inode(c, f); | 819 | jffs2_do_clear_inode(c, f); |
694 | return -EIO; | 820 | return -EIO; |
695 | } | 821 | } |
696 | if (!frag_first(&f->fragtree)) { | 822 | if (!frag_first(&f->fragtree)) { |
697 | printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", | 823 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n", |
698 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 824 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
699 | up(&f->sem); | 825 | up(&f->sem); |
700 | jffs2_do_clear_inode(c, f); | 826 | jffs2_do_clear_inode(c, f); |
@@ -702,7 +828,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
702 | } | 828 | } |
703 | /* ASSERT: f->fraglist != NULL */ | 829 | /* ASSERT: f->fraglist != NULL */ |
704 | if (frag_next(frag_first(&f->fragtree))) { | 830 | if (frag_next(frag_first(&f->fragtree))) { |
705 | printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n", | 831 | JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n", |
706 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 832 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
707 | /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ | 833 | /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ |
708 | up(&f->sem); | 834 | up(&f->sem); |
@@ -721,6 +847,93 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
721 | return 0; | 847 | return 0; |
722 | } | 848 | } |
723 | 849 | ||
850 | /* Scan the list of all nodes present for this ino, build map of versions, etc. */ | ||
851 | int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | ||
852 | uint32_t ino, struct jffs2_raw_inode *latest_node) | ||
853 | { | ||
854 | dbg_readinode("read inode #%u\n", ino); | ||
855 | |||
856 | retry_inocache: | ||
857 | spin_lock(&c->inocache_lock); | ||
858 | f->inocache = jffs2_get_ino_cache(c, ino); | ||
859 | |||
860 | if (f->inocache) { | ||
861 | /* Check its state. We may need to wait before we can use it */ | ||
862 | switch(f->inocache->state) { | ||
863 | case INO_STATE_UNCHECKED: | ||
864 | case INO_STATE_CHECKEDABSENT: | ||
865 | f->inocache->state = INO_STATE_READING; | ||
866 | break; | ||
867 | |||
868 | case INO_STATE_CHECKING: | ||
869 | case INO_STATE_GC: | ||
870 | /* If it's in either of these states, we need | ||
871 | to wait for whoever's got it to finish and | ||
872 | put it back. */ | ||
873 | dbg_readinode("waiting for ino #%u in state %d\n", ino, f->inocache->state); | ||
874 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); | ||
875 | goto retry_inocache; | ||
876 | |||
877 | case INO_STATE_READING: | ||
878 | case INO_STATE_PRESENT: | ||
879 | /* Eep. This should never happen. It can | ||
880 | happen if Linux calls read_inode() again | ||
881 | before clear_inode() has finished though. */ | ||
882 | JFFS2_ERROR("Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); | ||
883 | /* Fail. That's probably better than allowing it to succeed */ | ||
884 | f->inocache = NULL; | ||
885 | break; | ||
886 | |||
887 | default: | ||
888 | BUG(); | ||
889 | } | ||
890 | } | ||
891 | spin_unlock(&c->inocache_lock); | ||
892 | |||
893 | if (!f->inocache && ino == 1) { | ||
894 | /* Special case - no root inode on medium */ | ||
895 | f->inocache = jffs2_alloc_inode_cache(); | ||
896 | if (!f->inocache) { | ||
897 | JFFS2_ERROR("cannot allocate inocache for root inode\n"); | ||
898 | return -ENOMEM; | ||
899 | } | ||
900 | dbg_readinode("creating inocache for root inode\n"); | ||
901 | memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); | ||
902 | f->inocache->ino = f->inocache->nlink = 1; | ||
903 | f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; | ||
904 | f->inocache->state = INO_STATE_READING; | ||
905 | jffs2_add_ino_cache(c, f->inocache); | ||
906 | } | ||
907 | if (!f->inocache) { | ||
908 | JFFS2_ERROR("requestied to read an nonexistent ino %u\n", ino); | ||
909 | return -ENOENT; | ||
910 | } | ||
911 | |||
912 | return jffs2_do_read_inode_internal(c, f, latest_node); | ||
913 | } | ||
914 | |||
915 | int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) | ||
916 | { | ||
917 | struct jffs2_raw_inode n; | ||
918 | struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); | ||
919 | int ret; | ||
920 | |||
921 | if (!f) | ||
922 | return -ENOMEM; | ||
923 | |||
924 | memset(f, 0, sizeof(*f)); | ||
925 | init_MUTEX_LOCKED(&f->sem); | ||
926 | f->inocache = ic; | ||
927 | |||
928 | ret = jffs2_do_read_inode_internal(c, f, &n); | ||
929 | if (!ret) { | ||
930 | up(&f->sem); | ||
931 | jffs2_do_clear_inode(c, f); | ||
932 | } | ||
933 | kfree (f); | ||
934 | return ret; | ||
935 | } | ||
936 | |||
724 | void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | 937 | void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) |
725 | { | 938 | { |
726 | struct jffs2_full_dirent *fd, *fds; | 939 | struct jffs2_full_dirent *fd, *fds; |
@@ -740,18 +953,16 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
740 | 953 | ||
741 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); | 954 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); |
742 | 955 | ||
743 | /* For symlink inodes we us f->dents to store the target path name */ | 956 | if (f->target) { |
744 | if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { | 957 | kfree(f->target); |
745 | kfree(f->dents); | 958 | f->target = NULL; |
746 | f->dents = NULL; | 959 | } |
747 | } else { | ||
748 | fds = f->dents; | ||
749 | 960 | ||
750 | while(fds) { | 961 | fds = f->dents; |
751 | fd = fds; | 962 | while(fds) { |
752 | fds = fd->next; | 963 | fd = fds; |
753 | jffs2_free_full_dirent(fd); | 964 | fds = fd->next; |
754 | } | 965 | jffs2_free_full_dirent(fd); |
755 | } | 966 | } |
756 | 967 | ||
757 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { | 968 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index b63160f83bab..0e7456ec99fd 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $ | 10 | * $Id: scan.c,v 1.125 2005/09/30 13:59:13 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
@@ -18,22 +18,11 @@ | |||
18 | #include <linux/crc32.h> | 18 | #include <linux/crc32.h> |
19 | #include <linux/compiler.h> | 19 | #include <linux/compiler.h> |
20 | #include "nodelist.h" | 20 | #include "nodelist.h" |
21 | #include "summary.h" | ||
22 | #include "debug.h" | ||
21 | 23 | ||
22 | #define DEFAULT_EMPTY_SCAN_SIZE 1024 | 24 | #define DEFAULT_EMPTY_SCAN_SIZE 1024 |
23 | 25 | ||
24 | #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ | ||
25 | c->free_size -= _x; c->dirty_size += _x; \ | ||
26 | jeb->free_size -= _x ; jeb->dirty_size += _x; \ | ||
27 | }while(0) | ||
28 | #define USED_SPACE(x) do { typeof(x) _x = (x); \ | ||
29 | c->free_size -= _x; c->used_size += _x; \ | ||
30 | jeb->free_size -= _x ; jeb->used_size += _x; \ | ||
31 | }while(0) | ||
32 | #define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ | ||
33 | c->free_size -= _x; c->unchecked_size += _x; \ | ||
34 | jeb->free_size -= _x ; jeb->unchecked_size += _x; \ | ||
35 | }while(0) | ||
36 | |||
37 | #define noisy_printk(noise, args...) do { \ | 26 | #define noisy_printk(noise, args...) do { \ |
38 | if (*(noise)) { \ | 27 | if (*(noise)) { \ |
39 | printk(KERN_NOTICE args); \ | 28 | printk(KERN_NOTICE args); \ |
@@ -47,23 +36,16 @@ | |||
47 | static uint32_t pseudo_random; | 36 | static uint32_t pseudo_random; |
48 | 37 | ||
49 | static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 38 | static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
50 | unsigned char *buf, uint32_t buf_size); | 39 | unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s); |
51 | 40 | ||
52 | /* These helper functions _must_ increase ofs and also do the dirty/used space accounting. | 41 | /* These helper functions _must_ increase ofs and also do the dirty/used space accounting. |
53 | * Returning an error will abort the mount - bad checksums etc. should just mark the space | 42 | * Returning an error will abort the mount - bad checksums etc. should just mark the space |
54 | * as dirty. | 43 | * as dirty. |
55 | */ | 44 | */ |
56 | static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 45 | static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
57 | struct jffs2_raw_inode *ri, uint32_t ofs); | 46 | struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s); |
58 | static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 47 | static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
59 | struct jffs2_raw_dirent *rd, uint32_t ofs); | 48 | struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s); |
60 | |||
61 | #define BLK_STATE_ALLFF 0 | ||
62 | #define BLK_STATE_CLEAN 1 | ||
63 | #define BLK_STATE_PARTDIRTY 2 | ||
64 | #define BLK_STATE_CLEANMARKER 3 | ||
65 | #define BLK_STATE_ALLDIRTY 4 | ||
66 | #define BLK_STATE_BADBLOCK 5 | ||
67 | 49 | ||
68 | static inline int min_free(struct jffs2_sb_info *c) | 50 | static inline int min_free(struct jffs2_sb_info *c) |
69 | { | 51 | { |
@@ -89,6 +71,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
89 | uint32_t empty_blocks = 0, bad_blocks = 0; | 71 | uint32_t empty_blocks = 0, bad_blocks = 0; |
90 | unsigned char *flashbuf = NULL; | 72 | unsigned char *flashbuf = NULL; |
91 | uint32_t buf_size = 0; | 73 | uint32_t buf_size = 0; |
74 | struct jffs2_summary *s = NULL; /* summary info collected by the scan process */ | ||
92 | #ifndef __ECOS | 75 | #ifndef __ECOS |
93 | size_t pointlen; | 76 | size_t pointlen; |
94 | 77 | ||
@@ -122,21 +105,34 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
122 | return -ENOMEM; | 105 | return -ENOMEM; |
123 | } | 106 | } |
124 | 107 | ||
108 | if (jffs2_sum_active()) { | ||
109 | s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL); | ||
110 | if (!s) { | ||
111 | JFFS2_WARNING("Can't allocate memory for summary\n"); | ||
112 | return -ENOMEM; | ||
113 | } | ||
114 | memset(s, 0, sizeof(struct jffs2_summary)); | ||
115 | } | ||
116 | |||
125 | for (i=0; i<c->nr_blocks; i++) { | 117 | for (i=0; i<c->nr_blocks; i++) { |
126 | struct jffs2_eraseblock *jeb = &c->blocks[i]; | 118 | struct jffs2_eraseblock *jeb = &c->blocks[i]; |
127 | 119 | ||
128 | ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size); | 120 | /* reset summary info for next eraseblock scan */ |
121 | jffs2_sum_reset_collected(s); | ||
122 | |||
123 | ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), | ||
124 | buf_size, s); | ||
129 | 125 | ||
130 | if (ret < 0) | 126 | if (ret < 0) |
131 | goto out; | 127 | goto out; |
132 | 128 | ||
133 | ACCT_PARANOIA_CHECK(jeb); | 129 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
134 | 130 | ||
135 | /* Now decide which list to put it on */ | 131 | /* Now decide which list to put it on */ |
136 | switch(ret) { | 132 | switch(ret) { |
137 | case BLK_STATE_ALLFF: | 133 | case BLK_STATE_ALLFF: |
138 | /* | 134 | /* |
139 | * Empty block. Since we can't be sure it | 135 | * Empty block. Since we can't be sure it |
140 | * was entirely erased, we just queue it for erase | 136 | * was entirely erased, we just queue it for erase |
141 | * again. It will be marked as such when the erase | 137 | * again. It will be marked as such when the erase |
142 | * is complete. Meanwhile we still count it as empty | 138 | * is complete. Meanwhile we still count it as empty |
@@ -162,18 +158,18 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
162 | break; | 158 | break; |
163 | 159 | ||
164 | case BLK_STATE_CLEAN: | 160 | case BLK_STATE_CLEAN: |
165 | /* Full (or almost full) of clean data. Clean list */ | 161 | /* Full (or almost full) of clean data. Clean list */ |
166 | list_add(&jeb->list, &c->clean_list); | 162 | list_add(&jeb->list, &c->clean_list); |
167 | break; | 163 | break; |
168 | 164 | ||
169 | case BLK_STATE_PARTDIRTY: | 165 | case BLK_STATE_PARTDIRTY: |
170 | /* Some data, but not full. Dirty list. */ | 166 | /* Some data, but not full. Dirty list. */ |
171 | /* We want to remember the block with most free space | 167 | /* We want to remember the block with most free space |
172 | and stick it in the 'nextblock' position to start writing to it. */ | 168 | and stick it in the 'nextblock' position to start writing to it. */ |
173 | if (jeb->free_size > min_free(c) && | 169 | if (jeb->free_size > min_free(c) && |
174 | (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { | 170 | (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { |
175 | /* Better candidate for the next writes to go to */ | 171 | /* Better candidate for the next writes to go to */ |
176 | if (c->nextblock) { | 172 | if (c->nextblock) { |
177 | c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; | 173 | c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; |
178 | c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; | 174 | c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; |
179 | c->free_size -= c->nextblock->free_size; | 175 | c->free_size -= c->nextblock->free_size; |
@@ -184,9 +180,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
184 | } else { | 180 | } else { |
185 | list_add(&c->nextblock->list, &c->dirty_list); | 181 | list_add(&c->nextblock->list, &c->dirty_list); |
186 | } | 182 | } |
183 | /* deleting summary information of the old nextblock */ | ||
184 | jffs2_sum_reset_collected(c->summary); | ||
187 | } | 185 | } |
188 | c->nextblock = jeb; | 186 | /* update collected summary infromation for the current nextblock */ |
189 | } else { | 187 | jffs2_sum_move_collected(c, s); |
188 | D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset)); | ||
189 | c->nextblock = jeb; | ||
190 | } else { | ||
190 | jeb->dirty_size += jeb->free_size + jeb->wasted_size; | 191 | jeb->dirty_size += jeb->free_size + jeb->wasted_size; |
191 | c->dirty_size += jeb->free_size + jeb->wasted_size; | 192 | c->dirty_size += jeb->free_size + jeb->wasted_size; |
192 | c->free_size -= jeb->free_size; | 193 | c->free_size -= jeb->free_size; |
@@ -197,30 +198,33 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
197 | } else { | 198 | } else { |
198 | list_add(&jeb->list, &c->dirty_list); | 199 | list_add(&jeb->list, &c->dirty_list); |
199 | } | 200 | } |
200 | } | 201 | } |
201 | break; | 202 | break; |
202 | 203 | ||
203 | case BLK_STATE_ALLDIRTY: | 204 | case BLK_STATE_ALLDIRTY: |
204 | /* Nothing valid - not even a clean marker. Needs erasing. */ | 205 | /* Nothing valid - not even a clean marker. Needs erasing. */ |
205 | /* For now we just put it on the erasing list. We'll start the erases later */ | 206 | /* For now we just put it on the erasing list. We'll start the erases later */ |
206 | D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset)); | 207 | D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset)); |
207 | list_add(&jeb->list, &c->erase_pending_list); | 208 | list_add(&jeb->list, &c->erase_pending_list); |
208 | c->nr_erasing_blocks++; | 209 | c->nr_erasing_blocks++; |
209 | break; | 210 | break; |
210 | 211 | ||
211 | case BLK_STATE_BADBLOCK: | 212 | case BLK_STATE_BADBLOCK: |
212 | D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset)); | 213 | D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset)); |
213 | list_add(&jeb->list, &c->bad_list); | 214 | list_add(&jeb->list, &c->bad_list); |
214 | c->bad_size += c->sector_size; | 215 | c->bad_size += c->sector_size; |
215 | c->free_size -= c->sector_size; | 216 | c->free_size -= c->sector_size; |
216 | bad_blocks++; | 217 | bad_blocks++; |
217 | break; | 218 | break; |
218 | default: | 219 | default: |
219 | printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n"); | 220 | printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n"); |
220 | BUG(); | 221 | BUG(); |
221 | } | 222 | } |
222 | } | 223 | } |
223 | 224 | ||
225 | if (jffs2_sum_active() && s) | ||
226 | kfree(s); | ||
227 | |||
224 | /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ | 228 | /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ |
225 | if (c->nextblock && (c->nextblock->dirty_size)) { | 229 | if (c->nextblock && (c->nextblock->dirty_size)) { |
226 | c->nextblock->wasted_size += c->nextblock->dirty_size; | 230 | c->nextblock->wasted_size += c->nextblock->dirty_size; |
@@ -229,12 +233,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
229 | c->nextblock->dirty_size = 0; | 233 | c->nextblock->dirty_size = 0; |
230 | } | 234 | } |
231 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | 235 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
232 | if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { | 236 | if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size % c->wbuf_pagesize)) { |
233 | /* If we're going to start writing into a block which already | 237 | /* If we're going to start writing into a block which already |
234 | contains data, and the end of the data isn't page-aligned, | 238 | contains data, and the end of the data isn't page-aligned, |
235 | skip a little and align it. */ | 239 | skip a little and align it. */ |
236 | 240 | ||
237 | uint32_t skip = c->nextblock->free_size & (c->wbuf_pagesize-1); | 241 | uint32_t skip = c->nextblock->free_size % c->wbuf_pagesize; |
238 | 242 | ||
239 | D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", | 243 | D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", |
240 | skip)); | 244 | skip)); |
@@ -246,7 +250,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
246 | } | 250 | } |
247 | #endif | 251 | #endif |
248 | if (c->nr_erasing_blocks) { | 252 | if (c->nr_erasing_blocks) { |
249 | if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { | 253 | if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { |
250 | printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); | 254 | printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); |
251 | printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks); | 255 | printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks); |
252 | ret = -EIO; | 256 | ret = -EIO; |
@@ -259,13 +263,13 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
259 | if (buf_size) | 263 | if (buf_size) |
260 | kfree(flashbuf); | 264 | kfree(flashbuf); |
261 | #ifndef __ECOS | 265 | #ifndef __ECOS |
262 | else | 266 | else |
263 | c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); | 267 | c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); |
264 | #endif | 268 | #endif |
265 | return ret; | 269 | return ret; |
266 | } | 270 | } |
267 | 271 | ||
268 | static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, | 272 | int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf, |
269 | uint32_t ofs, uint32_t len) | 273 | uint32_t ofs, uint32_t len) |
270 | { | 274 | { |
271 | int ret; | 275 | int ret; |
@@ -286,14 +290,36 @@ static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, | |||
286 | return 0; | 290 | return 0; |
287 | } | 291 | } |
288 | 292 | ||
293 | int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | ||
294 | { | ||
295 | if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size | ||
296 | && (!jeb->first_node || !jeb->first_node->next_phys) ) | ||
297 | return BLK_STATE_CLEANMARKER; | ||
298 | |||
299 | /* move blocks with max 4 byte dirty space to cleanlist */ | ||
300 | else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) { | ||
301 | c->dirty_size -= jeb->dirty_size; | ||
302 | c->wasted_size += jeb->dirty_size; | ||
303 | jeb->wasted_size += jeb->dirty_size; | ||
304 | jeb->dirty_size = 0; | ||
305 | return BLK_STATE_CLEAN; | ||
306 | } else if (jeb->used_size || jeb->unchecked_size) | ||
307 | return BLK_STATE_PARTDIRTY; | ||
308 | else | ||
309 | return BLK_STATE_ALLDIRTY; | ||
310 | } | ||
311 | |||
289 | static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 312 | static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
290 | unsigned char *buf, uint32_t buf_size) { | 313 | unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { |
291 | struct jffs2_unknown_node *node; | 314 | struct jffs2_unknown_node *node; |
292 | struct jffs2_unknown_node crcnode; | 315 | struct jffs2_unknown_node crcnode; |
316 | struct jffs2_sum_marker *sm; | ||
293 | uint32_t ofs, prevofs; | 317 | uint32_t ofs, prevofs; |
294 | uint32_t hdr_crc, buf_ofs, buf_len; | 318 | uint32_t hdr_crc, buf_ofs, buf_len; |
295 | int err; | 319 | int err; |
296 | int noise = 0; | 320 | int noise = 0; |
321 | |||
322 | |||
297 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | 323 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
298 | int cleanmarkerfound = 0; | 324 | int cleanmarkerfound = 0; |
299 | #endif | 325 | #endif |
@@ -319,17 +345,53 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
319 | } | 345 | } |
320 | } | 346 | } |
321 | #endif | 347 | #endif |
348 | |||
349 | if (jffs2_sum_active()) { | ||
350 | sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL); | ||
351 | if (!sm) { | ||
352 | return -ENOMEM; | ||
353 | } | ||
354 | |||
355 | err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size - | ||
356 | sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker)); | ||
357 | if (err) { | ||
358 | kfree(sm); | ||
359 | return err; | ||
360 | } | ||
361 | |||
362 | if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) { | ||
363 | err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random); | ||
364 | if (err) { | ||
365 | kfree(sm); | ||
366 | return err; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | kfree(sm); | ||
371 | |||
372 | ofs = jeb->offset; | ||
373 | prevofs = jeb->offset - 1; | ||
374 | } | ||
375 | |||
322 | buf_ofs = jeb->offset; | 376 | buf_ofs = jeb->offset; |
323 | 377 | ||
324 | if (!buf_size) { | 378 | if (!buf_size) { |
325 | buf_len = c->sector_size; | 379 | buf_len = c->sector_size; |
380 | |||
381 | if (jffs2_sum_active()) { | ||
382 | /* must reread because of summary test */ | ||
383 | err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); | ||
384 | if (err) | ||
385 | return err; | ||
386 | } | ||
387 | |||
326 | } else { | 388 | } else { |
327 | buf_len = EMPTY_SCAN_SIZE(c->sector_size); | 389 | buf_len = EMPTY_SCAN_SIZE(c->sector_size); |
328 | err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); | 390 | err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); |
329 | if (err) | 391 | if (err) |
330 | return err; | 392 | return err; |
331 | } | 393 | } |
332 | 394 | ||
333 | /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ | 395 | /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ |
334 | ofs = 0; | 396 | ofs = 0; |
335 | 397 | ||
@@ -367,10 +429,12 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
367 | 429 | ||
368 | noise = 10; | 430 | noise = 10; |
369 | 431 | ||
370 | scan_more: | 432 | dbg_summary("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset); |
433 | |||
434 | scan_more: | ||
371 | while(ofs < jeb->offset + c->sector_size) { | 435 | while(ofs < jeb->offset + c->sector_size) { |
372 | 436 | ||
373 | D1(ACCT_PARANOIA_CHECK(jeb)); | 437 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
374 | 438 | ||
375 | cond_resched(); | 439 | cond_resched(); |
376 | 440 | ||
@@ -432,7 +496,7 @@ scan_more: | |||
432 | 496 | ||
433 | /* If we're only checking the beginning of a block with a cleanmarker, | 497 | /* If we're only checking the beginning of a block with a cleanmarker, |
434 | bail now */ | 498 | bail now */ |
435 | if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && | 499 | if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && |
436 | c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) { | 500 | c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) { |
437 | D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); | 501 | D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); |
438 | return BLK_STATE_CLEANMARKER; | 502 | return BLK_STATE_CLEANMARKER; |
@@ -441,7 +505,7 @@ scan_more: | |||
441 | /* See how much more there is to read in this eraseblock... */ | 505 | /* See how much more there is to read in this eraseblock... */ |
442 | buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); | 506 | buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); |
443 | if (!buf_len) { | 507 | if (!buf_len) { |
444 | /* No more to read. Break out of main loop without marking | 508 | /* No more to read. Break out of main loop without marking |
445 | this range of empty space as dirty (because it's not) */ | 509 | this range of empty space as dirty (because it's not) */ |
446 | D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n", | 510 | D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n", |
447 | empty_start)); | 511 | empty_start)); |
@@ -476,8 +540,8 @@ scan_more: | |||
476 | } | 540 | } |
477 | if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) { | 541 | if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) { |
478 | /* OK. We're out of possibilities. Whinge and move on */ | 542 | /* OK. We're out of possibilities. Whinge and move on */ |
479 | noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", | 543 | noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", |
480 | JFFS2_MAGIC_BITMASK, ofs, | 544 | JFFS2_MAGIC_BITMASK, ofs, |
481 | je16_to_cpu(node->magic)); | 545 | je16_to_cpu(node->magic)); |
482 | DIRTY_SPACE(4); | 546 | DIRTY_SPACE(4); |
483 | ofs += 4; | 547 | ofs += 4; |
@@ -492,7 +556,7 @@ scan_more: | |||
492 | if (hdr_crc != je32_to_cpu(node->hdr_crc)) { | 556 | if (hdr_crc != je32_to_cpu(node->hdr_crc)) { |
493 | noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n", | 557 | noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n", |
494 | ofs, je16_to_cpu(node->magic), | 558 | ofs, je16_to_cpu(node->magic), |
495 | je16_to_cpu(node->nodetype), | 559 | je16_to_cpu(node->nodetype), |
496 | je32_to_cpu(node->totlen), | 560 | je32_to_cpu(node->totlen), |
497 | je32_to_cpu(node->hdr_crc), | 561 | je32_to_cpu(node->hdr_crc), |
498 | hdr_crc); | 562 | hdr_crc); |
@@ -501,7 +565,7 @@ scan_more: | |||
501 | continue; | 565 | continue; |
502 | } | 566 | } |
503 | 567 | ||
504 | if (ofs + je32_to_cpu(node->totlen) > | 568 | if (ofs + je32_to_cpu(node->totlen) > |
505 | jeb->offset + c->sector_size) { | 569 | jeb->offset + c->sector_size) { |
506 | /* Eep. Node goes over the end of the erase block. */ | 570 | /* Eep. Node goes over the end of the erase block. */ |
507 | printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", | 571 | printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", |
@@ -532,11 +596,11 @@ scan_more: | |||
532 | buf_ofs = ofs; | 596 | buf_ofs = ofs; |
533 | node = (void *)buf; | 597 | node = (void *)buf; |
534 | } | 598 | } |
535 | err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs); | 599 | err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s); |
536 | if (err) return err; | 600 | if (err) return err; |
537 | ofs += PAD(je32_to_cpu(node->totlen)); | 601 | ofs += PAD(je32_to_cpu(node->totlen)); |
538 | break; | 602 | break; |
539 | 603 | ||
540 | case JFFS2_NODETYPE_DIRENT: | 604 | case JFFS2_NODETYPE_DIRENT: |
541 | if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { | 605 | if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { |
542 | buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); | 606 | buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); |
@@ -548,7 +612,7 @@ scan_more: | |||
548 | buf_ofs = ofs; | 612 | buf_ofs = ofs; |
549 | node = (void *)buf; | 613 | node = (void *)buf; |
550 | } | 614 | } |
551 | err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs); | 615 | err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s); |
552 | if (err) return err; | 616 | if (err) return err; |
553 | ofs += PAD(je32_to_cpu(node->totlen)); | 617 | ofs += PAD(je32_to_cpu(node->totlen)); |
554 | break; | 618 | break; |
@@ -556,7 +620,7 @@ scan_more: | |||
556 | case JFFS2_NODETYPE_CLEANMARKER: | 620 | case JFFS2_NODETYPE_CLEANMARKER: |
557 | D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); | 621 | D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); |
558 | if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { | 622 | if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { |
559 | printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", | 623 | printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", |
560 | ofs, je32_to_cpu(node->totlen), c->cleanmarker_size); | 624 | ofs, je32_to_cpu(node->totlen), c->cleanmarker_size); |
561 | DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); | 625 | DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); |
562 | ofs += PAD(sizeof(struct jffs2_unknown_node)); | 626 | ofs += PAD(sizeof(struct jffs2_unknown_node)); |
@@ -575,13 +639,15 @@ scan_more: | |||
575 | marker_ref->flash_offset = ofs | REF_NORMAL; | 639 | marker_ref->flash_offset = ofs | REF_NORMAL; |
576 | marker_ref->__totlen = c->cleanmarker_size; | 640 | marker_ref->__totlen = c->cleanmarker_size; |
577 | jeb->first_node = jeb->last_node = marker_ref; | 641 | jeb->first_node = jeb->last_node = marker_ref; |
578 | 642 | ||
579 | USED_SPACE(PAD(c->cleanmarker_size)); | 643 | USED_SPACE(PAD(c->cleanmarker_size)); |
580 | ofs += PAD(c->cleanmarker_size); | 644 | ofs += PAD(c->cleanmarker_size); |
581 | } | 645 | } |
582 | break; | 646 | break; |
583 | 647 | ||
584 | case JFFS2_NODETYPE_PADDING: | 648 | case JFFS2_NODETYPE_PADDING: |
649 | if (jffs2_sum_active()) | ||
650 | jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen)); | ||
585 | DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); | 651 | DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); |
586 | ofs += PAD(je32_to_cpu(node->totlen)); | 652 | ofs += PAD(je32_to_cpu(node->totlen)); |
587 | break; | 653 | break; |
@@ -616,8 +682,15 @@ scan_more: | |||
616 | } | 682 | } |
617 | } | 683 | } |
618 | 684 | ||
685 | if (jffs2_sum_active()) { | ||
686 | if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) { | ||
687 | dbg_summary("There is not enough space for " | ||
688 | "summary information, disabling for this jeb!\n"); | ||
689 | jffs2_sum_disable_collecting(s); | ||
690 | } | ||
691 | } | ||
619 | 692 | ||
620 | D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, | 693 | D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, |
621 | jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); | 694 | jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); |
622 | 695 | ||
623 | /* mark_node_obsolete can add to wasted !! */ | 696 | /* mark_node_obsolete can add to wasted !! */ |
@@ -628,24 +701,10 @@ scan_more: | |||
628 | jeb->wasted_size = 0; | 701 | jeb->wasted_size = 0; |
629 | } | 702 | } |
630 | 703 | ||
631 | if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size | 704 | return jffs2_scan_classify_jeb(c, jeb); |
632 | && (!jeb->first_node || !jeb->first_node->next_phys) ) | ||
633 | return BLK_STATE_CLEANMARKER; | ||
634 | |||
635 | /* move blocks with max 4 byte dirty space to cleanlist */ | ||
636 | else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) { | ||
637 | c->dirty_size -= jeb->dirty_size; | ||
638 | c->wasted_size += jeb->dirty_size; | ||
639 | jeb->wasted_size += jeb->dirty_size; | ||
640 | jeb->dirty_size = 0; | ||
641 | return BLK_STATE_CLEAN; | ||
642 | } else if (jeb->used_size || jeb->unchecked_size) | ||
643 | return BLK_STATE_PARTDIRTY; | ||
644 | else | ||
645 | return BLK_STATE_ALLDIRTY; | ||
646 | } | 705 | } |
647 | 706 | ||
648 | static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) | 707 | struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) |
649 | { | 708 | { |
650 | struct jffs2_inode_cache *ic; | 709 | struct jffs2_inode_cache *ic; |
651 | 710 | ||
@@ -671,8 +730,8 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info | |||
671 | return ic; | 730 | return ic; |
672 | } | 731 | } |
673 | 732 | ||
674 | static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 733 | static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
675 | struct jffs2_raw_inode *ri, uint32_t ofs) | 734 | struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s) |
676 | { | 735 | { |
677 | struct jffs2_raw_node_ref *raw; | 736 | struct jffs2_raw_node_ref *raw; |
678 | struct jffs2_inode_cache *ic; | 737 | struct jffs2_inode_cache *ic; |
@@ -681,11 +740,11 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
681 | D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); | 740 | D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); |
682 | 741 | ||
683 | /* We do very little here now. Just check the ino# to which we should attribute | 742 | /* We do very little here now. Just check the ino# to which we should attribute |
684 | this node; we can do all the CRC checking etc. later. There's a tradeoff here -- | 743 | this node; we can do all the CRC checking etc. later. There's a tradeoff here -- |
685 | we used to scan the flash once only, reading everything we want from it into | 744 | we used to scan the flash once only, reading everything we want from it into |
686 | memory, then building all our in-core data structures and freeing the extra | 745 | memory, then building all our in-core data structures and freeing the extra |
687 | information. Now we allow the first part of the mount to complete a lot quicker, | 746 | information. Now we allow the first part of the mount to complete a lot quicker, |
688 | but we have to go _back_ to the flash in order to finish the CRC checking, etc. | 747 | but we have to go _back_ to the flash in order to finish the CRC checking, etc. |
689 | Which means that the _full_ amount of time to get to proper write mode with GC | 748 | Which means that the _full_ amount of time to get to proper write mode with GC |
690 | operational may actually be _longer_ than before. Sucks to be me. */ | 749 | operational may actually be _longer_ than before. Sucks to be me. */ |
691 | 750 | ||
@@ -731,7 +790,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
731 | jeb->last_node->next_phys = raw; | 790 | jeb->last_node->next_phys = raw; |
732 | jeb->last_node = raw; | 791 | jeb->last_node = raw; |
733 | 792 | ||
734 | D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", | 793 | D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", |
735 | je32_to_cpu(ri->ino), je32_to_cpu(ri->version), | 794 | je32_to_cpu(ri->ino), je32_to_cpu(ri->version), |
736 | je32_to_cpu(ri->offset), | 795 | je32_to_cpu(ri->offset), |
737 | je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize))); | 796 | je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize))); |
@@ -739,11 +798,16 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
739 | pseudo_random += je32_to_cpu(ri->version); | 798 | pseudo_random += je32_to_cpu(ri->version); |
740 | 799 | ||
741 | UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen))); | 800 | UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen))); |
801 | |||
802 | if (jffs2_sum_active()) { | ||
803 | jffs2_sum_add_inode_mem(s, ri, ofs - jeb->offset); | ||
804 | } | ||
805 | |||
742 | return 0; | 806 | return 0; |
743 | } | 807 | } |
744 | 808 | ||
745 | static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 809 | static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
746 | struct jffs2_raw_dirent *rd, uint32_t ofs) | 810 | struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s) |
747 | { | 811 | { |
748 | struct jffs2_raw_node_ref *raw; | 812 | struct jffs2_raw_node_ref *raw; |
749 | struct jffs2_full_dirent *fd; | 813 | struct jffs2_full_dirent *fd; |
@@ -776,7 +840,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
776 | crc = crc32(0, fd->name, rd->nsize); | 840 | crc = crc32(0, fd->name, rd->nsize); |
777 | if (crc != je32_to_cpu(rd->name_crc)) { | 841 | if (crc != je32_to_cpu(rd->name_crc)) { |
778 | printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", | 842 | printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", |
779 | ofs, je32_to_cpu(rd->name_crc), crc); | 843 | ofs, je32_to_cpu(rd->name_crc), crc); |
780 | D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino))); | 844 | D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino))); |
781 | jffs2_free_full_dirent(fd); | 845 | jffs2_free_full_dirent(fd); |
782 | /* FIXME: Why do we believe totlen? */ | 846 | /* FIXME: Why do we believe totlen? */ |
@@ -796,7 +860,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
796 | jffs2_free_raw_node_ref(raw); | 860 | jffs2_free_raw_node_ref(raw); |
797 | return -ENOMEM; | 861 | return -ENOMEM; |
798 | } | 862 | } |
799 | 863 | ||
800 | raw->__totlen = PAD(je32_to_cpu(rd->totlen)); | 864 | raw->__totlen = PAD(je32_to_cpu(rd->totlen)); |
801 | raw->flash_offset = ofs | REF_PRISTINE; | 865 | raw->flash_offset = ofs | REF_PRISTINE; |
802 | raw->next_phys = NULL; | 866 | raw->next_phys = NULL; |
@@ -817,6 +881,10 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
817 | USED_SPACE(PAD(je32_to_cpu(rd->totlen))); | 881 | USED_SPACE(PAD(je32_to_cpu(rd->totlen))); |
818 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); | 882 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); |
819 | 883 | ||
884 | if (jffs2_sum_active()) { | ||
885 | jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset); | ||
886 | } | ||
887 | |||
820 | return 0; | 888 | return 0; |
821 | } | 889 | } |
822 | 890 | ||
@@ -852,76 +920,34 @@ void jffs2_rotate_lists(struct jffs2_sb_info *c) | |||
852 | x = count_list(&c->clean_list); | 920 | x = count_list(&c->clean_list); |
853 | if (x) { | 921 | if (x) { |
854 | rotateby = pseudo_random % x; | 922 | rotateby = pseudo_random % x; |
855 | D1(printk(KERN_DEBUG "Rotating clean_list by %d\n", rotateby)); | ||
856 | |||
857 | rotate_list((&c->clean_list), rotateby); | 923 | rotate_list((&c->clean_list), rotateby); |
858 | |||
859 | D1(printk(KERN_DEBUG "Erase block at front of clean_list is at %08x\n", | ||
860 | list_entry(c->clean_list.next, struct jffs2_eraseblock, list)->offset)); | ||
861 | } else { | ||
862 | D1(printk(KERN_DEBUG "Not rotating empty clean_list\n")); | ||
863 | } | 924 | } |
864 | 925 | ||
865 | x = count_list(&c->very_dirty_list); | 926 | x = count_list(&c->very_dirty_list); |
866 | if (x) { | 927 | if (x) { |
867 | rotateby = pseudo_random % x; | 928 | rotateby = pseudo_random % x; |
868 | D1(printk(KERN_DEBUG "Rotating very_dirty_list by %d\n", rotateby)); | ||
869 | |||
870 | rotate_list((&c->very_dirty_list), rotateby); | 929 | rotate_list((&c->very_dirty_list), rotateby); |
871 | |||
872 | D1(printk(KERN_DEBUG "Erase block at front of very_dirty_list is at %08x\n", | ||
873 | list_entry(c->very_dirty_list.next, struct jffs2_eraseblock, list)->offset)); | ||
874 | } else { | ||
875 | D1(printk(KERN_DEBUG "Not rotating empty very_dirty_list\n")); | ||
876 | } | 930 | } |
877 | 931 | ||
878 | x = count_list(&c->dirty_list); | 932 | x = count_list(&c->dirty_list); |
879 | if (x) { | 933 | if (x) { |
880 | rotateby = pseudo_random % x; | 934 | rotateby = pseudo_random % x; |
881 | D1(printk(KERN_DEBUG "Rotating dirty_list by %d\n", rotateby)); | ||
882 | |||
883 | rotate_list((&c->dirty_list), rotateby); | 935 | rotate_list((&c->dirty_list), rotateby); |
884 | |||
885 | D1(printk(KERN_DEBUG "Erase block at front of dirty_list is at %08x\n", | ||
886 | list_entry(c->dirty_list.next, struct jffs2_eraseblock, list)->offset)); | ||
887 | } else { | ||
888 | D1(printk(KERN_DEBUG "Not rotating empty dirty_list\n")); | ||
889 | } | 936 | } |
890 | 937 | ||
891 | x = count_list(&c->erasable_list); | 938 | x = count_list(&c->erasable_list); |
892 | if (x) { | 939 | if (x) { |
893 | rotateby = pseudo_random % x; | 940 | rotateby = pseudo_random % x; |
894 | D1(printk(KERN_DEBUG "Rotating erasable_list by %d\n", rotateby)); | ||
895 | |||
896 | rotate_list((&c->erasable_list), rotateby); | 941 | rotate_list((&c->erasable_list), rotateby); |
897 | |||
898 | D1(printk(KERN_DEBUG "Erase block at front of erasable_list is at %08x\n", | ||
899 | list_entry(c->erasable_list.next, struct jffs2_eraseblock, list)->offset)); | ||
900 | } else { | ||
901 | D1(printk(KERN_DEBUG "Not rotating empty erasable_list\n")); | ||
902 | } | 942 | } |
903 | 943 | ||
904 | if (c->nr_erasing_blocks) { | 944 | if (c->nr_erasing_blocks) { |
905 | rotateby = pseudo_random % c->nr_erasing_blocks; | 945 | rotateby = pseudo_random % c->nr_erasing_blocks; |
906 | D1(printk(KERN_DEBUG "Rotating erase_pending_list by %d\n", rotateby)); | ||
907 | |||
908 | rotate_list((&c->erase_pending_list), rotateby); | 946 | rotate_list((&c->erase_pending_list), rotateby); |
909 | |||
910 | D1(printk(KERN_DEBUG "Erase block at front of erase_pending_list is at %08x\n", | ||
911 | list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list)->offset)); | ||
912 | } else { | ||
913 | D1(printk(KERN_DEBUG "Not rotating empty erase_pending_list\n")); | ||
914 | } | 947 | } |
915 | 948 | ||
916 | if (c->nr_free_blocks) { | 949 | if (c->nr_free_blocks) { |
917 | rotateby = pseudo_random % c->nr_free_blocks; | 950 | rotateby = pseudo_random % c->nr_free_blocks; |
918 | D1(printk(KERN_DEBUG "Rotating free_list by %d\n", rotateby)); | ||
919 | |||
920 | rotate_list((&c->free_list), rotateby); | 951 | rotate_list((&c->free_list), rotateby); |
921 | |||
922 | D1(printk(KERN_DEBUG "Erase block at front of free_list is at %08x\n", | ||
923 | list_entry(c->free_list.next, struct jffs2_eraseblock, list)->offset)); | ||
924 | } else { | ||
925 | D1(printk(KERN_DEBUG "Not rotating empty free_list\n")); | ||
926 | } | 952 | } |
927 | } | 953 | } |
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c new file mode 100644 index 000000000000..fb9cec61fcf2 --- /dev/null +++ b/fs/jffs2/summary.c | |||
@@ -0,0 +1,730 @@ | |||
1 | /* | ||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
3 | * | ||
4 | * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | ||
5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, | ||
6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, | ||
7 | * University of Szeged, Hungary | ||
8 | * | ||
9 | * For licensing information, see the file 'LICENCE' in this directory. | ||
10 | * | ||
11 | * $Id: summary.c,v 1.4 2005/09/26 11:37:21 havasi Exp $ | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include <linux/pagemap.h> | ||
20 | #include <linux/crc32.h> | ||
21 | #include <linux/compiler.h> | ||
22 | #include <linux/vmalloc.h> | ||
23 | #include "nodelist.h" | ||
24 | #include "debug.h" | ||
25 | |||
26 | int jffs2_sum_init(struct jffs2_sb_info *c) | ||
27 | { | ||
28 | c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL); | ||
29 | |||
30 | if (!c->summary) { | ||
31 | JFFS2_WARNING("Can't allocate memory for summary information!\n"); | ||
32 | return -ENOMEM; | ||
33 | } | ||
34 | |||
35 | memset(c->summary, 0, sizeof(struct jffs2_summary)); | ||
36 | |||
37 | c->summary->sum_buf = vmalloc(c->sector_size); | ||
38 | |||
39 | if (!c->summary->sum_buf) { | ||
40 | JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n"); | ||
41 | kfree(c->summary); | ||
42 | return -ENOMEM; | ||
43 | } | ||
44 | |||
45 | dbg_summary("returned succesfully\n"); | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | void jffs2_sum_exit(struct jffs2_sb_info *c) | ||
51 | { | ||
52 | dbg_summary("called\n"); | ||
53 | |||
54 | jffs2_sum_disable_collecting(c->summary); | ||
55 | |||
56 | vfree(c->summary->sum_buf); | ||
57 | c->summary->sum_buf = NULL; | ||
58 | |||
59 | kfree(c->summary); | ||
60 | c->summary = NULL; | ||
61 | } | ||
62 | |||
63 | static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item) | ||
64 | { | ||
65 | if (!s->sum_list_head) | ||
66 | s->sum_list_head = (union jffs2_sum_mem *) item; | ||
67 | if (s->sum_list_tail) | ||
68 | s->sum_list_tail->u.next = (union jffs2_sum_mem *) item; | ||
69 | s->sum_list_tail = (union jffs2_sum_mem *) item; | ||
70 | |||
71 | switch (je16_to_cpu(item->u.nodetype)) { | ||
72 | case JFFS2_NODETYPE_INODE: | ||
73 | s->sum_size += JFFS2_SUMMARY_INODE_SIZE; | ||
74 | s->sum_num++; | ||
75 | dbg_summary("inode (%u) added to summary\n", | ||
76 | je32_to_cpu(item->i.inode)); | ||
77 | break; | ||
78 | case JFFS2_NODETYPE_DIRENT: | ||
79 | s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize); | ||
80 | s->sum_num++; | ||
81 | dbg_summary("dirent (%u) added to summary\n", | ||
82 | je32_to_cpu(item->d.ino)); | ||
83 | break; | ||
84 | default: | ||
85 | JFFS2_WARNING("UNKNOWN node type %u\n", | ||
86 | je16_to_cpu(item->u.nodetype)); | ||
87 | return 1; | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | |||
93 | /* The following 3 functions are called from scan.c to collect summary info for not closed jeb */ | ||
94 | |||
95 | int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size) | ||
96 | { | ||
97 | dbg_summary("called with %u\n", size); | ||
98 | s->sum_padded += size; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, | ||
103 | uint32_t ofs) | ||
104 | { | ||
105 | struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL); | ||
106 | |||
107 | if (!temp) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | temp->nodetype = ri->nodetype; | ||
111 | temp->inode = ri->ino; | ||
112 | temp->version = ri->version; | ||
113 | temp->offset = cpu_to_je32(ofs); /* relative offset from the begining of the jeb */ | ||
114 | temp->totlen = ri->totlen; | ||
115 | temp->next = NULL; | ||
116 | |||
117 | return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); | ||
118 | } | ||
119 | |||
120 | int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, | ||
121 | uint32_t ofs) | ||
122 | { | ||
123 | struct jffs2_sum_dirent_mem *temp = | ||
124 | kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL); | ||
125 | |||
126 | if (!temp) | ||
127 | return -ENOMEM; | ||
128 | |||
129 | temp->nodetype = rd->nodetype; | ||
130 | temp->totlen = rd->totlen; | ||
131 | temp->offset = cpu_to_je32(ofs); /* relative from the begining of the jeb */ | ||
132 | temp->pino = rd->pino; | ||
133 | temp->version = rd->version; | ||
134 | temp->ino = rd->ino; | ||
135 | temp->nsize = rd->nsize; | ||
136 | temp->type = rd->type; | ||
137 | temp->next = NULL; | ||
138 | |||
139 | memcpy(temp->name, rd->name, rd->nsize); | ||
140 | |||
141 | return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); | ||
142 | } | ||
143 | |||
144 | /* Cleanup every collected summary information */ | ||
145 | |||
146 | static void jffs2_sum_clean_collected(struct jffs2_summary *s) | ||
147 | { | ||
148 | union jffs2_sum_mem *temp; | ||
149 | |||
150 | if (!s->sum_list_head) { | ||
151 | dbg_summary("already empty\n"); | ||
152 | } | ||
153 | while (s->sum_list_head) { | ||
154 | temp = s->sum_list_head; | ||
155 | s->sum_list_head = s->sum_list_head->u.next; | ||
156 | kfree(temp); | ||
157 | } | ||
158 | s->sum_list_tail = NULL; | ||
159 | s->sum_padded = 0; | ||
160 | s->sum_num = 0; | ||
161 | } | ||
162 | |||
163 | void jffs2_sum_reset_collected(struct jffs2_summary *s) | ||
164 | { | ||
165 | dbg_summary("called\n"); | ||
166 | jffs2_sum_clean_collected(s); | ||
167 | s->sum_size = 0; | ||
168 | } | ||
169 | |||
170 | void jffs2_sum_disable_collecting(struct jffs2_summary *s) | ||
171 | { | ||
172 | dbg_summary("called\n"); | ||
173 | jffs2_sum_clean_collected(s); | ||
174 | s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; | ||
175 | } | ||
176 | |||
177 | int jffs2_sum_is_disabled(struct jffs2_summary *s) | ||
178 | { | ||
179 | return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE); | ||
180 | } | ||
181 | |||
182 | /* Move the collected summary information into sb (called from scan.c) */ | ||
183 | |||
184 | void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s) | ||
185 | { | ||
186 | dbg_summary("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n", | ||
187 | c->summary->sum_size, c->summary->sum_num, | ||
188 | s->sum_size, s->sum_num); | ||
189 | |||
190 | c->summary->sum_size = s->sum_size; | ||
191 | c->summary->sum_num = s->sum_num; | ||
192 | c->summary->sum_padded = s->sum_padded; | ||
193 | c->summary->sum_list_head = s->sum_list_head; | ||
194 | c->summary->sum_list_tail = s->sum_list_tail; | ||
195 | |||
196 | s->sum_list_head = s->sum_list_tail = NULL; | ||
197 | } | ||
198 | |||
199 | /* Called from wbuf.c to collect writed node info */ | ||
200 | |||
201 | int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, | ||
202 | unsigned long count, uint32_t ofs) | ||
203 | { | ||
204 | union jffs2_node_union *node; | ||
205 | struct jffs2_eraseblock *jeb; | ||
206 | |||
207 | node = invecs[0].iov_base; | ||
208 | jeb = &c->blocks[ofs / c->sector_size]; | ||
209 | ofs -= jeb->offset; | ||
210 | |||
211 | switch (je16_to_cpu(node->u.nodetype)) { | ||
212 | case JFFS2_NODETYPE_INODE: { | ||
213 | struct jffs2_sum_inode_mem *temp = | ||
214 | kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL); | ||
215 | |||
216 | if (!temp) | ||
217 | goto no_mem; | ||
218 | |||
219 | temp->nodetype = node->i.nodetype; | ||
220 | temp->inode = node->i.ino; | ||
221 | temp->version = node->i.version; | ||
222 | temp->offset = cpu_to_je32(ofs); | ||
223 | temp->totlen = node->i.totlen; | ||
224 | temp->next = NULL; | ||
225 | |||
226 | return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); | ||
227 | } | ||
228 | |||
229 | case JFFS2_NODETYPE_DIRENT: { | ||
230 | struct jffs2_sum_dirent_mem *temp = | ||
231 | kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL); | ||
232 | |||
233 | if (!temp) | ||
234 | goto no_mem; | ||
235 | |||
236 | temp->nodetype = node->d.nodetype; | ||
237 | temp->totlen = node->d.totlen; | ||
238 | temp->offset = cpu_to_je32(ofs); | ||
239 | temp->pino = node->d.pino; | ||
240 | temp->version = node->d.version; | ||
241 | temp->ino = node->d.ino; | ||
242 | temp->nsize = node->d.nsize; | ||
243 | temp->type = node->d.type; | ||
244 | temp->next = NULL; | ||
245 | |||
246 | switch (count) { | ||
247 | case 1: | ||
248 | memcpy(temp->name,node->d.name,node->d.nsize); | ||
249 | break; | ||
250 | |||
251 | case 2: | ||
252 | memcpy(temp->name,invecs[1].iov_base,node->d.nsize); | ||
253 | break; | ||
254 | |||
255 | default: | ||
256 | BUG(); /* impossible count value */ | ||
257 | break; | ||
258 | } | ||
259 | |||
260 | return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); | ||
261 | } | ||
262 | |||
263 | case JFFS2_NODETYPE_PADDING: | ||
264 | dbg_summary("node PADDING\n"); | ||
265 | c->summary->sum_padded += je32_to_cpu(node->u.totlen); | ||
266 | break; | ||
267 | |||
268 | case JFFS2_NODETYPE_CLEANMARKER: | ||
269 | dbg_summary("node CLEANMARKER\n"); | ||
270 | break; | ||
271 | |||
272 | case JFFS2_NODETYPE_SUMMARY: | ||
273 | dbg_summary("node SUMMARY\n"); | ||
274 | break; | ||
275 | |||
276 | default: | ||
277 | /* If you implement a new node type you should also implement | ||
278 | summary support for it or disable summary. | ||
279 | */ | ||
280 | BUG(); | ||
281 | break; | ||
282 | } | ||
283 | |||
284 | return 0; | ||
285 | |||
286 | no_mem: | ||
287 | JFFS2_WARNING("MEMORY ALLOCATION ERROR!"); | ||
288 | return -ENOMEM; | ||
289 | } | ||
290 | |||
291 | |||
292 | /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ | ||
293 | |||
294 | static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | ||
295 | struct jffs2_raw_summary *summary, uint32_t *pseudo_random) | ||
296 | { | ||
297 | struct jffs2_raw_node_ref *raw; | ||
298 | struct jffs2_inode_cache *ic; | ||
299 | struct jffs2_full_dirent *fd; | ||
300 | void *sp; | ||
301 | int i, ino; | ||
302 | |||
303 | sp = summary->sum; | ||
304 | |||
305 | for (i=0; i<je32_to_cpu(summary->sum_num); i++) { | ||
306 | dbg_summary("processing summary index %d\n", i); | ||
307 | |||
308 | switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { | ||
309 | case JFFS2_NODETYPE_INODE: { | ||
310 | struct jffs2_sum_inode_flash *spi; | ||
311 | spi = sp; | ||
312 | |||
313 | ino = je32_to_cpu(spi->inode); | ||
314 | |||
315 | dbg_summary("Inode at 0x%08x\n", | ||
316 | jeb->offset + je32_to_cpu(spi->offset)); | ||
317 | |||
318 | raw = jffs2_alloc_raw_node_ref(); | ||
319 | if (!raw) { | ||
320 | JFFS2_NOTICE("allocation of node reference failed\n"); | ||
321 | kfree(summary); | ||
322 | return -ENOMEM; | ||
323 | } | ||
324 | |||
325 | ic = jffs2_scan_make_ino_cache(c, ino); | ||
326 | if (!ic) { | ||
327 | JFFS2_NOTICE("scan_make_ino_cache failed\n"); | ||
328 | jffs2_free_raw_node_ref(raw); | ||
329 | kfree(summary); | ||
330 | return -ENOMEM; | ||
331 | } | ||
332 | |||
333 | raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED; | ||
334 | raw->__totlen = PAD(je32_to_cpu(spi->totlen)); | ||
335 | raw->next_phys = NULL; | ||
336 | raw->next_in_ino = ic->nodes; | ||
337 | |||
338 | ic->nodes = raw; | ||
339 | if (!jeb->first_node) | ||
340 | jeb->first_node = raw; | ||
341 | if (jeb->last_node) | ||
342 | jeb->last_node->next_phys = raw; | ||
343 | jeb->last_node = raw; | ||
344 | *pseudo_random += je32_to_cpu(spi->version); | ||
345 | |||
346 | UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen))); | ||
347 | |||
348 | sp += JFFS2_SUMMARY_INODE_SIZE; | ||
349 | |||
350 | break; | ||
351 | } | ||
352 | |||
353 | case JFFS2_NODETYPE_DIRENT: { | ||
354 | struct jffs2_sum_dirent_flash *spd; | ||
355 | spd = sp; | ||
356 | |||
357 | dbg_summary("Dirent at 0x%08x\n", | ||
358 | jeb->offset + je32_to_cpu(spd->offset)); | ||
359 | |||
360 | fd = jffs2_alloc_full_dirent(spd->nsize+1); | ||
361 | if (!fd) { | ||
362 | kfree(summary); | ||
363 | return -ENOMEM; | ||
364 | } | ||
365 | |||
366 | memcpy(&fd->name, spd->name, spd->nsize); | ||
367 | fd->name[spd->nsize] = 0; | ||
368 | |||
369 | raw = jffs2_alloc_raw_node_ref(); | ||
370 | if (!raw) { | ||
371 | jffs2_free_full_dirent(fd); | ||
372 | JFFS2_NOTICE("allocation of node reference failed\n"); | ||
373 | kfree(summary); | ||
374 | return -ENOMEM; | ||
375 | } | ||
376 | |||
377 | ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); | ||
378 | if (!ic) { | ||
379 | jffs2_free_full_dirent(fd); | ||
380 | jffs2_free_raw_node_ref(raw); | ||
381 | kfree(summary); | ||
382 | return -ENOMEM; | ||
383 | } | ||
384 | |||
385 | raw->__totlen = PAD(je32_to_cpu(spd->totlen)); | ||
386 | raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE; | ||
387 | raw->next_phys = NULL; | ||
388 | raw->next_in_ino = ic->nodes; | ||
389 | ic->nodes = raw; | ||
390 | if (!jeb->first_node) | ||
391 | jeb->first_node = raw; | ||
392 | if (jeb->last_node) | ||
393 | jeb->last_node->next_phys = raw; | ||
394 | jeb->last_node = raw; | ||
395 | |||
396 | fd->raw = raw; | ||
397 | fd->next = NULL; | ||
398 | fd->version = je32_to_cpu(spd->version); | ||
399 | fd->ino = je32_to_cpu(spd->ino); | ||
400 | fd->nhash = full_name_hash(fd->name, spd->nsize); | ||
401 | fd->type = spd->type; | ||
402 | USED_SPACE(PAD(je32_to_cpu(spd->totlen))); | ||
403 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); | ||
404 | |||
405 | *pseudo_random += je32_to_cpu(spd->version); | ||
406 | |||
407 | sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); | ||
408 | |||
409 | break; | ||
410 | } | ||
411 | |||
412 | default : { | ||
413 | JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); | ||
414 | kfree(summary); | ||
415 | return -EIO; | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | |||
420 | kfree(summary); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | /* Process the summary node - called from jffs2_scan_eraseblock() */ | ||
425 | |||
426 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | ||
427 | uint32_t ofs, uint32_t *pseudo_random) | ||
428 | { | ||
429 | struct jffs2_unknown_node crcnode; | ||
430 | struct jffs2_raw_node_ref *cache_ref; | ||
431 | struct jffs2_raw_summary *summary; | ||
432 | int ret, sumsize; | ||
433 | uint32_t crc; | ||
434 | |||
435 | sumsize = c->sector_size - ofs; | ||
436 | ofs += jeb->offset; | ||
437 | |||
438 | dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", | ||
439 | jeb->offset, ofs, sumsize); | ||
440 | |||
441 | summary = kmalloc(sumsize, GFP_KERNEL); | ||
442 | |||
443 | if (!summary) { | ||
444 | return -ENOMEM; | ||
445 | } | ||
446 | |||
447 | ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize); | ||
448 | |||
449 | if (ret) { | ||
450 | kfree(summary); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | /* OK, now check for node validity and CRC */ | ||
455 | crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | ||
456 | crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); | ||
457 | crcnode.totlen = summary->totlen; | ||
458 | crc = crc32(0, &crcnode, sizeof(crcnode)-4); | ||
459 | |||
460 | if (je32_to_cpu(summary->hdr_crc) != crc) { | ||
461 | dbg_summary("Summary node header is corrupt (bad CRC or " | ||
462 | "no summary at all)\n"); | ||
463 | goto crc_err; | ||
464 | } | ||
465 | |||
466 | if (je32_to_cpu(summary->totlen) != sumsize) { | ||
467 | dbg_summary("Summary node is corrupt (wrong erasesize?)\n"); | ||
468 | goto crc_err; | ||
469 | } | ||
470 | |||
471 | crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8); | ||
472 | |||
473 | if (je32_to_cpu(summary->node_crc) != crc) { | ||
474 | dbg_summary("Summary node is corrupt (bad CRC)\n"); | ||
475 | goto crc_err; | ||
476 | } | ||
477 | |||
478 | crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary)); | ||
479 | |||
480 | if (je32_to_cpu(summary->sum_crc) != crc) { | ||
481 | dbg_summary("Summary node data is corrupt (bad CRC)\n"); | ||
482 | goto crc_err; | ||
483 | } | ||
484 | |||
485 | if ( je32_to_cpu(summary->cln_mkr) ) { | ||
486 | |||
487 | dbg_summary("Summary : CLEANMARKER node \n"); | ||
488 | |||
489 | if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { | ||
490 | dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n", | ||
491 | je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); | ||
492 | UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); | ||
493 | } else if (jeb->first_node) { | ||
494 | dbg_summary("CLEANMARKER node not first node in block " | ||
495 | "(0x%08x)\n", jeb->offset); | ||
496 | UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); | ||
497 | } else { | ||
498 | struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); | ||
499 | |||
500 | if (!marker_ref) { | ||
501 | JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); | ||
502 | kfree(summary); | ||
503 | return -ENOMEM; | ||
504 | } | ||
505 | |||
506 | marker_ref->next_in_ino = NULL; | ||
507 | marker_ref->next_phys = NULL; | ||
508 | marker_ref->flash_offset = jeb->offset | REF_NORMAL; | ||
509 | marker_ref->__totlen = je32_to_cpu(summary->cln_mkr); | ||
510 | jeb->first_node = jeb->last_node = marker_ref; | ||
511 | |||
512 | USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) ); | ||
513 | } | ||
514 | } | ||
515 | |||
516 | if (je32_to_cpu(summary->padded)) { | ||
517 | DIRTY_SPACE(je32_to_cpu(summary->padded)); | ||
518 | } | ||
519 | |||
520 | ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); | ||
521 | if (ret) | ||
522 | return ret; | ||
523 | |||
524 | /* for PARANOIA_CHECK */ | ||
525 | cache_ref = jffs2_alloc_raw_node_ref(); | ||
526 | |||
527 | if (!cache_ref) { | ||
528 | JFFS2_NOTICE("Failed to allocate node ref for cache\n"); | ||
529 | return -ENOMEM; | ||
530 | } | ||
531 | |||
532 | cache_ref->next_in_ino = NULL; | ||
533 | cache_ref->next_phys = NULL; | ||
534 | cache_ref->flash_offset = ofs | REF_NORMAL; | ||
535 | cache_ref->__totlen = sumsize; | ||
536 | |||
537 | if (!jeb->first_node) | ||
538 | jeb->first_node = cache_ref; | ||
539 | if (jeb->last_node) | ||
540 | jeb->last_node->next_phys = cache_ref; | ||
541 | jeb->last_node = cache_ref; | ||
542 | |||
543 | USED_SPACE(sumsize); | ||
544 | |||
545 | jeb->wasted_size += jeb->free_size; | ||
546 | c->wasted_size += jeb->free_size; | ||
547 | c->free_size -= jeb->free_size; | ||
548 | jeb->free_size = 0; | ||
549 | |||
550 | return jffs2_scan_classify_jeb(c, jeb); | ||
551 | |||
552 | crc_err: | ||
553 | JFFS2_WARNING("Summary node crc error, skipping summary information.\n"); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */ | ||
559 | |||
560 | static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | ||
561 | uint32_t infosize, uint32_t datasize, int padsize) | ||
562 | { | ||
563 | struct jffs2_raw_summary isum; | ||
564 | union jffs2_sum_mem *temp; | ||
565 | struct jffs2_sum_marker *sm; | ||
566 | struct kvec vecs[2]; | ||
567 | void *wpage; | ||
568 | int ret; | ||
569 | size_t retlen; | ||
570 | |||
571 | memset(c->summary->sum_buf, 0xff, datasize); | ||
572 | memset(&isum, 0, sizeof(isum)); | ||
573 | |||
574 | isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | ||
575 | isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); | ||
576 | isum.totlen = cpu_to_je32(infosize); | ||
577 | isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4)); | ||
578 | isum.padded = cpu_to_je32(c->summary->sum_padded); | ||
579 | isum.cln_mkr = cpu_to_je32(c->cleanmarker_size); | ||
580 | isum.sum_num = cpu_to_je32(c->summary->sum_num); | ||
581 | wpage = c->summary->sum_buf; | ||
582 | |||
583 | while (c->summary->sum_num) { | ||
584 | |||
585 | switch (je16_to_cpu(c->summary->sum_list_head->u.nodetype)) { | ||
586 | case JFFS2_NODETYPE_INODE: { | ||
587 | struct jffs2_sum_inode_flash *sino_ptr = wpage; | ||
588 | |||
589 | sino_ptr->nodetype = c->summary->sum_list_head->i.nodetype; | ||
590 | sino_ptr->inode = c->summary->sum_list_head->i.inode; | ||
591 | sino_ptr->version = c->summary->sum_list_head->i.version; | ||
592 | sino_ptr->offset = c->summary->sum_list_head->i.offset; | ||
593 | sino_ptr->totlen = c->summary->sum_list_head->i.totlen; | ||
594 | |||
595 | wpage += JFFS2_SUMMARY_INODE_SIZE; | ||
596 | |||
597 | break; | ||
598 | } | ||
599 | |||
600 | case JFFS2_NODETYPE_DIRENT: { | ||
601 | struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; | ||
602 | |||
603 | sdrnt_ptr->nodetype = c->summary->sum_list_head->d.nodetype; | ||
604 | sdrnt_ptr->totlen = c->summary->sum_list_head->d.totlen; | ||
605 | sdrnt_ptr->offset = c->summary->sum_list_head->d.offset; | ||
606 | sdrnt_ptr->pino = c->summary->sum_list_head->d.pino; | ||
607 | sdrnt_ptr->version = c->summary->sum_list_head->d.version; | ||
608 | sdrnt_ptr->ino = c->summary->sum_list_head->d.ino; | ||
609 | sdrnt_ptr->nsize = c->summary->sum_list_head->d.nsize; | ||
610 | sdrnt_ptr->type = c->summary->sum_list_head->d.type; | ||
611 | |||
612 | memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name, | ||
613 | c->summary->sum_list_head->d.nsize); | ||
614 | |||
615 | wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize); | ||
616 | |||
617 | break; | ||
618 | } | ||
619 | |||
620 | default : { | ||
621 | BUG(); /* unknown node in summary information */ | ||
622 | } | ||
623 | } | ||
624 | |||
625 | temp = c->summary->sum_list_head; | ||
626 | c->summary->sum_list_head = c->summary->sum_list_head->u.next; | ||
627 | kfree(temp); | ||
628 | |||
629 | c->summary->sum_num--; | ||
630 | } | ||
631 | |||
632 | jffs2_sum_reset_collected(c->summary); | ||
633 | |||
634 | wpage += padsize; | ||
635 | |||
636 | sm = wpage; | ||
637 | sm->offset = cpu_to_je32(c->sector_size - jeb->free_size); | ||
638 | sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC); | ||
639 | |||
640 | isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize)); | ||
641 | isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8)); | ||
642 | |||
643 | vecs[0].iov_base = &isum; | ||
644 | vecs[0].iov_len = sizeof(isum); | ||
645 | vecs[1].iov_base = c->summary->sum_buf; | ||
646 | vecs[1].iov_len = datasize; | ||
647 | |||
648 | dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n", | ||
649 | jeb->offset + c->sector_size - jeb->free_size); | ||
650 | |||
651 | spin_unlock(&c->erase_completion_lock); | ||
652 | ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size - | ||
653 | jeb->free_size, &retlen, 0); | ||
654 | spin_lock(&c->erase_completion_lock); | ||
655 | |||
656 | |||
657 | if (ret || (retlen != infosize)) { | ||
658 | JFFS2_WARNING("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", | ||
659 | infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); | ||
660 | |||
661 | c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; | ||
662 | WASTED_SPACE(infosize); | ||
663 | |||
664 | return 1; | ||
665 | } | ||
666 | |||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | /* Write out summary information - called from jffs2_do_reserve_space */ | ||
671 | |||
672 | int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) | ||
673 | { | ||
674 | struct jffs2_raw_node_ref *summary_ref; | ||
675 | int datasize, infosize, padsize, ret; | ||
676 | struct jffs2_eraseblock *jeb; | ||
677 | |||
678 | dbg_summary("called\n"); | ||
679 | |||
680 | jeb = c->nextblock; | ||
681 | |||
682 | if (!c->summary->sum_num || !c->summary->sum_list_head) { | ||
683 | JFFS2_WARNING("Empty summary info!!!\n"); | ||
684 | BUG(); | ||
685 | } | ||
686 | |||
687 | datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker); | ||
688 | infosize = sizeof(struct jffs2_raw_summary) + datasize; | ||
689 | padsize = jeb->free_size - infosize; | ||
690 | infosize += padsize; | ||
691 | datasize += padsize; | ||
692 | |||
693 | /* Is there enough space for summary? */ | ||
694 | if (padsize < 0) { | ||
695 | /* don't try to write out summary for this jeb */ | ||
696 | jffs2_sum_disable_collecting(c->summary); | ||
697 | |||
698 | JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); | ||
703 | if (ret) | ||
704 | return 0; /* can't write out summary, block is marked as NOSUM_SIZE */ | ||
705 | |||
706 | /* for ACCT_PARANOIA_CHECK */ | ||
707 | spin_unlock(&c->erase_completion_lock); | ||
708 | summary_ref = jffs2_alloc_raw_node_ref(); | ||
709 | spin_lock(&c->erase_completion_lock); | ||
710 | |||
711 | if (!summary_ref) { | ||
712 | JFFS2_NOTICE("Failed to allocate node ref for summary\n"); | ||
713 | return -ENOMEM; | ||
714 | } | ||
715 | |||
716 | summary_ref->next_in_ino = NULL; | ||
717 | summary_ref->next_phys = NULL; | ||
718 | summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; | ||
719 | summary_ref->__totlen = infosize; | ||
720 | |||
721 | if (!jeb->first_node) | ||
722 | jeb->first_node = summary_ref; | ||
723 | if (jeb->last_node) | ||
724 | jeb->last_node->next_phys = summary_ref; | ||
725 | jeb->last_node = summary_ref; | ||
726 | |||
727 | USED_SPACE(infosize); | ||
728 | |||
729 | return 0; | ||
730 | } | ||
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h new file mode 100644 index 000000000000..b7a678be1709 --- /dev/null +++ b/fs/jffs2/summary.h | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
3 | * | ||
4 | * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | ||
5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, | ||
6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, | ||
7 | * University of Szeged, Hungary | ||
8 | * | ||
9 | * For licensing information, see the file 'LICENCE' in this directory. | ||
10 | * | ||
11 | * $Id: summary.h,v 1.2 2005/09/26 11:37:21 havasi Exp $ | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef JFFS2_SUMMARY_H | ||
16 | #define JFFS2_SUMMARY_H | ||
17 | |||
18 | #include <linux/uio.h> | ||
19 | #include <linux/jffs2.h> | ||
20 | |||
21 | #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ | ||
22 | c->free_size -= _x; c->dirty_size += _x; \ | ||
23 | jeb->free_size -= _x ; jeb->dirty_size += _x; \ | ||
24 | }while(0) | ||
25 | #define USED_SPACE(x) do { typeof(x) _x = (x); \ | ||
26 | c->free_size -= _x; c->used_size += _x; \ | ||
27 | jeb->free_size -= _x ; jeb->used_size += _x; \ | ||
28 | }while(0) | ||
29 | #define WASTED_SPACE(x) do { typeof(x) _x = (x); \ | ||
30 | c->free_size -= _x; c->wasted_size += _x; \ | ||
31 | jeb->free_size -= _x ; jeb->wasted_size += _x; \ | ||
32 | }while(0) | ||
33 | #define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ | ||
34 | c->free_size -= _x; c->unchecked_size += _x; \ | ||
35 | jeb->free_size -= _x ; jeb->unchecked_size += _x; \ | ||
36 | }while(0) | ||
37 | |||
38 | #define BLK_STATE_ALLFF 0 | ||
39 | #define BLK_STATE_CLEAN 1 | ||
40 | #define BLK_STATE_PARTDIRTY 2 | ||
41 | #define BLK_STATE_CLEANMARKER 3 | ||
42 | #define BLK_STATE_ALLDIRTY 4 | ||
43 | #define BLK_STATE_BADBLOCK 5 | ||
44 | |||
45 | #define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff | ||
46 | #define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) | ||
47 | #define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) | ||
48 | |||
49 | /* Summary structures used on flash */ | ||
50 | |||
51 | struct jffs2_sum_unknown_flash | ||
52 | { | ||
53 | jint16_t nodetype; /* node type */ | ||
54 | }; | ||
55 | |||
56 | struct jffs2_sum_inode_flash | ||
57 | { | ||
58 | jint16_t nodetype; /* node type */ | ||
59 | jint32_t inode; /* inode number */ | ||
60 | jint32_t version; /* inode version */ | ||
61 | jint32_t offset; /* offset on jeb */ | ||
62 | jint32_t totlen; /* record length */ | ||
63 | } __attribute__((packed)); | ||
64 | |||
65 | struct jffs2_sum_dirent_flash | ||
66 | { | ||
67 | jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ | ||
68 | jint32_t totlen; /* record length */ | ||
69 | jint32_t offset; /* offset on jeb */ | ||
70 | jint32_t pino; /* parent inode */ | ||
71 | jint32_t version; /* dirent version */ | ||
72 | jint32_t ino; /* == zero for unlink */ | ||
73 | uint8_t nsize; /* dirent name size */ | ||
74 | uint8_t type; /* dirent type */ | ||
75 | uint8_t name[0]; /* dirent name */ | ||
76 | } __attribute__((packed)); | ||
77 | |||
78 | union jffs2_sum_flash | ||
79 | { | ||
80 | struct jffs2_sum_unknown_flash u; | ||
81 | struct jffs2_sum_inode_flash i; | ||
82 | struct jffs2_sum_dirent_flash d; | ||
83 | }; | ||
84 | |||
85 | /* Summary structures used in the memory */ | ||
86 | |||
87 | struct jffs2_sum_unknown_mem | ||
88 | { | ||
89 | union jffs2_sum_mem *next; | ||
90 | jint16_t nodetype; /* node type */ | ||
91 | }; | ||
92 | |||
93 | struct jffs2_sum_inode_mem | ||
94 | { | ||
95 | union jffs2_sum_mem *next; | ||
96 | jint16_t nodetype; /* node type */ | ||
97 | jint32_t inode; /* inode number */ | ||
98 | jint32_t version; /* inode version */ | ||
99 | jint32_t offset; /* offset on jeb */ | ||
100 | jint32_t totlen; /* record length */ | ||
101 | } __attribute__((packed)); | ||
102 | |||
103 | struct jffs2_sum_dirent_mem | ||
104 | { | ||
105 | union jffs2_sum_mem *next; | ||
106 | jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ | ||
107 | jint32_t totlen; /* record length */ | ||
108 | jint32_t offset; /* ofset on jeb */ | ||
109 | jint32_t pino; /* parent inode */ | ||
110 | jint32_t version; /* dirent version */ | ||
111 | jint32_t ino; /* == zero for unlink */ | ||
112 | uint8_t nsize; /* dirent name size */ | ||
113 | uint8_t type; /* dirent type */ | ||
114 | uint8_t name[0]; /* dirent name */ | ||
115 | } __attribute__((packed)); | ||
116 | |||
117 | union jffs2_sum_mem | ||
118 | { | ||
119 | struct jffs2_sum_unknown_mem u; | ||
120 | struct jffs2_sum_inode_mem i; | ||
121 | struct jffs2_sum_dirent_mem d; | ||
122 | }; | ||
123 | |||
124 | /* Summary related information stored in superblock */ | ||
125 | |||
126 | struct jffs2_summary | ||
127 | { | ||
128 | uint32_t sum_size; /* collected summary information for nextblock */ | ||
129 | uint32_t sum_num; | ||
130 | uint32_t sum_padded; | ||
131 | union jffs2_sum_mem *sum_list_head; | ||
132 | union jffs2_sum_mem *sum_list_tail; | ||
133 | |||
134 | jint32_t *sum_buf; /* buffer for writing out summary */ | ||
135 | }; | ||
136 | |||
137 | /* Summary marker is stored at the end of every sumarized erase block */ | ||
138 | |||
139 | struct jffs2_sum_marker | ||
140 | { | ||
141 | jint32_t offset; /* offset of the summary node in the jeb */ | ||
142 | jint32_t magic; /* == JFFS2_SUM_MAGIC */ | ||
143 | }; | ||
144 | |||
145 | #define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) | ||
146 | |||
147 | #ifdef CONFIG_JFFS2_SUMMARY /* SUMMARY SUPPORT ENABLED */ | ||
148 | |||
149 | #define jffs2_sum_active() (1) | ||
150 | int jffs2_sum_init(struct jffs2_sb_info *c); | ||
151 | void jffs2_sum_exit(struct jffs2_sb_info *c); | ||
152 | void jffs2_sum_disable_collecting(struct jffs2_summary *s); | ||
153 | int jffs2_sum_is_disabled(struct jffs2_summary *s); | ||
154 | void jffs2_sum_reset_collected(struct jffs2_summary *s); | ||
155 | void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s); | ||
156 | int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, | ||
157 | unsigned long count, uint32_t to); | ||
158 | int jffs2_sum_write_sumnode(struct jffs2_sb_info *c); | ||
159 | int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); | ||
160 | int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); | ||
161 | int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); | ||
162 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | ||
163 | uint32_t ofs, uint32_t *pseudo_random); | ||
164 | |||
165 | #else /* SUMMARY DISABLED */ | ||
166 | |||
167 | #define jffs2_sum_active() (0) | ||
168 | #define jffs2_sum_init(a) (0) | ||
169 | #define jffs2_sum_exit(a) | ||
170 | #define jffs2_sum_disable_collecting(a) | ||
171 | #define jffs2_sum_is_disabled(a) (0) | ||
172 | #define jffs2_sum_reset_collected(a) | ||
173 | #define jffs2_sum_add_kvec(a,b,c,d) (0) | ||
174 | #define jffs2_sum_move_collected(a,b) | ||
175 | #define jffs2_sum_write_sumnode(a) (0) | ||
176 | #define jffs2_sum_add_padding_mem(a,b) | ||
177 | #define jffs2_sum_add_inode_mem(a,b,c) | ||
178 | #define jffs2_sum_add_dirent_mem(a,b,c) | ||
179 | #define jffs2_sum_scan_sumnode(a,b,c,d) (0) | ||
180 | |||
181 | #endif /* CONFIG_JFFS2_SUMMARY */ | ||
182 | |||
183 | #endif /* JFFS2_SUMMARY_H */ | ||
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index aaf9475cfb6a..9e0b5458d9c0 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: super.c,v 1.107 2005/07/12 16:37:08 dedekind Exp $ | 10 | * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -62,7 +62,7 @@ static int jffs2_sync_fs(struct super_block *sb, int wait) | |||
62 | 62 | ||
63 | down(&c->alloc_sem); | 63 | down(&c->alloc_sem); |
64 | jffs2_flush_wbuf_pad(c); | 64 | jffs2_flush_wbuf_pad(c); |
65 | up(&c->alloc_sem); | 65 | up(&c->alloc_sem); |
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
@@ -112,7 +112,7 @@ static int jffs2_sb_set(struct super_block *sb, void *data) | |||
112 | } | 112 | } |
113 | 113 | ||
114 | static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, | 114 | static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, |
115 | int flags, const char *dev_name, | 115 | int flags, const char *dev_name, |
116 | void *data, struct mtd_info *mtd) | 116 | void *data, struct mtd_info *mtd) |
117 | { | 117 | { |
118 | struct super_block *sb; | 118 | struct super_block *sb; |
@@ -172,7 +172,7 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, | |||
172 | } | 172 | } |
173 | 173 | ||
174 | static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, | 174 | static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, |
175 | int flags, const char *dev_name, | 175 | int flags, const char *dev_name, |
176 | void *data, int mtdnr) | 176 | void *data, int mtdnr) |
177 | { | 177 | { |
178 | struct mtd_info *mtd; | 178 | struct mtd_info *mtd; |
@@ -201,7 +201,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, | |||
201 | 201 | ||
202 | /* The preferred way of mounting in future; especially when | 202 | /* The preferred way of mounting in future; especially when |
203 | CONFIG_BLK_DEV is implemented - we specify the underlying | 203 | CONFIG_BLK_DEV is implemented - we specify the underlying |
204 | MTD device by number or by name, so that we don't require | 204 | MTD device by number or by name, so that we don't require |
205 | block device support to be present in the kernel. */ | 205 | block device support to be present in the kernel. */ |
206 | 206 | ||
207 | /* FIXME: How to do the root fs this way? */ | 207 | /* FIXME: How to do the root fs this way? */ |
@@ -225,7 +225,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, | |||
225 | } else if (isdigit(dev_name[3])) { | 225 | } else if (isdigit(dev_name[3])) { |
226 | /* Mount by MTD device number name */ | 226 | /* Mount by MTD device number name */ |
227 | char *endptr; | 227 | char *endptr; |
228 | 228 | ||
229 | mtdnr = simple_strtoul(dev_name+3, &endptr, 0); | 229 | mtdnr = simple_strtoul(dev_name+3, &endptr, 0); |
230 | if (!*endptr) { | 230 | if (!*endptr) { |
231 | /* It was a valid number */ | 231 | /* It was a valid number */ |
@@ -235,7 +235,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, | |||
235 | } | 235 | } |
236 | } | 236 | } |
237 | 237 | ||
238 | /* Try the old way - the hack where we allowed users to mount | 238 | /* Try the old way - the hack where we allowed users to mount |
239 | /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ | 239 | /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ |
240 | 240 | ||
241 | err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); | 241 | err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); |
@@ -282,9 +282,12 @@ static void jffs2_put_super (struct super_block *sb) | |||
282 | down(&c->alloc_sem); | 282 | down(&c->alloc_sem); |
283 | jffs2_flush_wbuf_pad(c); | 283 | jffs2_flush_wbuf_pad(c); |
284 | up(&c->alloc_sem); | 284 | up(&c->alloc_sem); |
285 | |||
286 | jffs2_sum_exit(c); | ||
287 | |||
285 | jffs2_free_ino_caches(c); | 288 | jffs2_free_ino_caches(c); |
286 | jffs2_free_raw_node_refs(c); | 289 | jffs2_free_raw_node_refs(c); |
287 | if (c->mtd->flags & MTD_NO_VIRTBLOCKS) | 290 | if (jffs2_blocks_use_vmalloc(c)) |
288 | vfree(c->blocks); | 291 | vfree(c->blocks); |
289 | else | 292 | else |
290 | kfree(c->blocks); | 293 | kfree(c->blocks); |
@@ -321,6 +324,9 @@ static int __init init_jffs2_fs(void) | |||
321 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | 324 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
322 | " (NAND)" | 325 | " (NAND)" |
323 | #endif | 326 | #endif |
327 | #ifdef CONFIG_JFFS2_SUMMARY | ||
328 | " (SUMMARY) " | ||
329 | #endif | ||
324 | " (C) 2001-2003 Red Hat, Inc.\n"); | 330 | " (C) 2001-2003 Red Hat, Inc.\n"); |
325 | 331 | ||
326 | jffs2_inode_cachep = kmem_cache_create("jffs2_i", | 332 | jffs2_inode_cachep = kmem_cache_create("jffs2_i", |
@@ -370,5 +376,5 @@ module_exit(exit_jffs2_fs); | |||
370 | 376 | ||
371 | MODULE_DESCRIPTION("The Journalling Flash File System, v2"); | 377 | MODULE_DESCRIPTION("The Journalling Flash File System, v2"); |
372 | MODULE_AUTHOR("Red Hat, Inc."); | 378 | MODULE_AUTHOR("Red Hat, Inc."); |
373 | MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for | 379 | MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for |
374 | // the sake of this tag. It's Free Software. | 380 | // the sake of this tag. It's Free Software. |
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 82ef484f5e12..d55754fe8925 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $ | 10 | * $Id: symlink.c,v 1.19 2005/11/07 11:14:42 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -21,7 +21,7 @@ | |||
21 | static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); | 21 | static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); |
22 | 22 | ||
23 | struct inode_operations jffs2_symlink_inode_operations = | 23 | struct inode_operations jffs2_symlink_inode_operations = |
24 | { | 24 | { |
25 | .readlink = generic_readlink, | 25 | .readlink = generic_readlink, |
26 | .follow_link = jffs2_follow_link, | 26 | .follow_link = jffs2_follow_link, |
27 | .setattr = jffs2_setattr | 27 | .setattr = jffs2_setattr |
@@ -30,35 +30,33 @@ struct inode_operations jffs2_symlink_inode_operations = | |||
30 | static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) | 30 | static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) |
31 | { | 31 | { |
32 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); | 32 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); |
33 | char *p = (char *)f->dents; | 33 | char *p = (char *)f->target; |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * We don't acquire the f->sem mutex here since the only data we | 36 | * We don't acquire the f->sem mutex here since the only data we |
37 | * use is f->dents which in case of the symlink inode points to the | 37 | * use is f->target. |
38 | * symlink's target path. | ||
39 | * | 38 | * |
40 | * 1. If we are here the inode has already built and f->dents has | 39 | * 1. If we are here the inode has already built and f->target has |
41 | * to point to the target path. | 40 | * to point to the target path. |
42 | * 2. Nobody uses f->dents (if the inode is symlink's inode). The | 41 | * 2. Nobody uses f->target (if the inode is symlink's inode). The |
43 | * exception is inode freeing function which frees f->dents. But | 42 | * exception is inode freeing function which frees f->target. But |
44 | * it can't be called while we are here and before VFS has | 43 | * it can't be called while we are here and before VFS has |
45 | * stopped using our f->dents string which we provide by means of | 44 | * stopped using our f->target string which we provide by means of |
46 | * nd_set_link() call. | 45 | * nd_set_link() call. |
47 | */ | 46 | */ |
48 | 47 | ||
49 | if (!p) { | 48 | if (!p) { |
50 | printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); | 49 | printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); |
51 | p = ERR_PTR(-EIO); | 50 | p = ERR_PTR(-EIO); |
52 | } else { | ||
53 | D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); | ||
54 | } | 51 | } |
52 | D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target)); | ||
55 | 53 | ||
56 | nd_set_link(nd, p); | 54 | nd_set_link(nd, p); |
57 | 55 | ||
58 | /* | 56 | /* |
59 | * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe | 57 | * We will unlock the f->sem mutex but VFS will use the f->target string. This is safe |
60 | * since the only way that may cause f->dents to be changed is iput() operation. | 58 | * since the only way that may cause f->target to be changed is iput() operation. |
61 | * But VFS will not use f->dents after iput() has been called. | 59 | * But VFS will not use f->target after iput() has been called. |
62 | */ | 60 | */ |
63 | return NULL; | 61 | return NULL; |
64 | } | 62 | } |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 7bc7f2d571f6..4cebf0e57c46 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * | 9 | * |
10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
11 | * | 11 | * |
12 | * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $ | 12 | * $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $ |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
@@ -30,12 +30,12 @@ | |||
30 | static unsigned char *brokenbuf; | 30 | static unsigned char *brokenbuf; |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | #define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) | ||
34 | #define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) | ||
35 | |||
33 | /* max. erase failures before we mark a block bad */ | 36 | /* max. erase failures before we mark a block bad */ |
34 | #define MAX_ERASE_FAILURES 2 | 37 | #define MAX_ERASE_FAILURES 2 |
35 | 38 | ||
36 | /* two seconds timeout for timed wbuf-flushing */ | ||
37 | #define WBUF_FLUSH_TIMEOUT 2 * HZ | ||
38 | |||
39 | struct jffs2_inodirty { | 39 | struct jffs2_inodirty { |
40 | uint32_t ino; | 40 | uint32_t ino; |
41 | struct jffs2_inodirty *next; | 41 | struct jffs2_inodirty *next; |
@@ -139,7 +139,6 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
139 | { | 139 | { |
140 | D1(printk("About to refile bad block at %08x\n", jeb->offset)); | 140 | D1(printk("About to refile bad block at %08x\n", jeb->offset)); |
141 | 141 | ||
142 | D2(jffs2_dump_block_lists(c)); | ||
143 | /* File the existing block on the bad_used_list.... */ | 142 | /* File the existing block on the bad_used_list.... */ |
144 | if (c->nextblock == jeb) | 143 | if (c->nextblock == jeb) |
145 | c->nextblock = NULL; | 144 | c->nextblock = NULL; |
@@ -156,7 +155,6 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
156 | c->nr_erasing_blocks++; | 155 | c->nr_erasing_blocks++; |
157 | jffs2_erase_pending_trigger(c); | 156 | jffs2_erase_pending_trigger(c); |
158 | } | 157 | } |
159 | D2(jffs2_dump_block_lists(c)); | ||
160 | 158 | ||
161 | /* Adjust its size counts accordingly */ | 159 | /* Adjust its size counts accordingly */ |
162 | c->wasted_size += jeb->free_size; | 160 | c->wasted_size += jeb->free_size; |
@@ -164,8 +162,9 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
164 | jeb->wasted_size += jeb->free_size; | 162 | jeb->wasted_size += jeb->free_size; |
165 | jeb->free_size = 0; | 163 | jeb->free_size = 0; |
166 | 164 | ||
167 | ACCT_SANITY_CHECK(c,jeb); | 165 | jffs2_dbg_dump_block_lists_nolock(c); |
168 | D1(ACCT_PARANOIA_CHECK(jeb)); | 166 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); |
167 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | ||
169 | } | 168 | } |
170 | 169 | ||
171 | /* Recover from failure to write wbuf. Recover the nodes up to the | 170 | /* Recover from failure to write wbuf. Recover the nodes up to the |
@@ -189,7 +188,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
189 | /* Find the first node to be recovered, by skipping over every | 188 | /* Find the first node to be recovered, by skipping over every |
190 | node which ends before the wbuf starts, or which is obsolete. */ | 189 | node which ends before the wbuf starts, or which is obsolete. */ |
191 | first_raw = &jeb->first_node; | 190 | first_raw = &jeb->first_node; |
192 | while (*first_raw && | 191 | while (*first_raw && |
193 | (ref_obsolete(*first_raw) || | 192 | (ref_obsolete(*first_raw) || |
194 | (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { | 193 | (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { |
195 | D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", | 194 | D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", |
@@ -238,7 +237,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
238 | ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); | 237 | ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); |
239 | else | 238 | else |
240 | ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); | 239 | ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); |
241 | 240 | ||
242 | if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { | 241 | if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { |
243 | /* ECC recovered */ | 242 | /* ECC recovered */ |
244 | ret = 0; | 243 | ret = 0; |
@@ -266,7 +265,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
266 | 265 | ||
267 | 266 | ||
268 | /* ... and get an allocation of space from a shiny new block instead */ | 267 | /* ... and get an allocation of space from a shiny new block instead */ |
269 | ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); | 268 | ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE); |
270 | if (ret) { | 269 | if (ret) { |
271 | printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); | 270 | printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); |
272 | kfree(buf); | 271 | kfree(buf); |
@@ -275,15 +274,15 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
275 | if (end-start >= c->wbuf_pagesize) { | 274 | if (end-start >= c->wbuf_pagesize) { |
276 | /* Need to do another write immediately, but it's possible | 275 | /* Need to do another write immediately, but it's possible |
277 | that this is just because the wbuf itself is completely | 276 | that this is just because the wbuf itself is completely |
278 | full, and there's nothing earlier read back from the | 277 | full, and there's nothing earlier read back from the |
279 | flash. Hence 'buf' isn't necessarily what we're writing | 278 | flash. Hence 'buf' isn't necessarily what we're writing |
280 | from. */ | 279 | from. */ |
281 | unsigned char *rewrite_buf = buf?:c->wbuf; | 280 | unsigned char *rewrite_buf = buf?:c->wbuf; |
282 | uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); | 281 | uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); |
283 | 282 | ||
284 | D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", | 283 | D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", |
285 | towrite, ofs)); | 284 | towrite, ofs)); |
286 | 285 | ||
287 | #ifdef BREAKMEHEADER | 286 | #ifdef BREAKMEHEADER |
288 | static int breakme; | 287 | static int breakme; |
289 | if (breakme++ == 20) { | 288 | if (breakme++ == 20) { |
@@ -391,11 +390,11 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
391 | else | 390 | else |
392 | jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys); | 391 | jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys); |
393 | 392 | ||
394 | ACCT_SANITY_CHECK(c,jeb); | 393 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); |
395 | D1(ACCT_PARANOIA_CHECK(jeb)); | 394 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
396 | 395 | ||
397 | ACCT_SANITY_CHECK(c,new_jeb); | 396 | jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); |
398 | D1(ACCT_PARANOIA_CHECK(new_jeb)); | 397 | jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); |
399 | 398 | ||
400 | spin_unlock(&c->erase_completion_lock); | 399 | spin_unlock(&c->erase_completion_lock); |
401 | 400 | ||
@@ -434,15 +433,15 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
434 | this happens, if we have a change to a new block, | 433 | this happens, if we have a change to a new block, |
435 | or if fsync forces us to flush the writebuffer. | 434 | or if fsync forces us to flush the writebuffer. |
436 | if we have a switch to next page, we will not have | 435 | if we have a switch to next page, we will not have |
437 | enough remaining space for this. | 436 | enough remaining space for this. |
438 | */ | 437 | */ |
439 | if (pad && !jffs2_dataflash(c)) { | 438 | if (pad ) { |
440 | c->wbuf_len = PAD(c->wbuf_len); | 439 | c->wbuf_len = PAD(c->wbuf_len); |
441 | 440 | ||
442 | /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR | 441 | /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR |
443 | with 8 byte page size */ | 442 | with 8 byte page size */ |
444 | memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); | 443 | memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); |
445 | 444 | ||
446 | if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { | 445 | if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { |
447 | struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); | 446 | struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); |
448 | padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 447 | padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -453,7 +452,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
453 | } | 452 | } |
454 | /* else jffs2_flash_writev has actually filled in the rest of the | 453 | /* else jffs2_flash_writev has actually filled in the rest of the |
455 | buffer for us, and will deal with the node refs etc. later. */ | 454 | buffer for us, and will deal with the node refs etc. later. */ |
456 | 455 | ||
457 | #ifdef BREAKME | 456 | #ifdef BREAKME |
458 | static int breakme; | 457 | static int breakme; |
459 | if (breakme++ == 20) { | 458 | if (breakme++ == 20) { |
@@ -462,9 +461,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
462 | c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, | 461 | c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, |
463 | &retlen, brokenbuf, NULL, c->oobinfo); | 462 | &retlen, brokenbuf, NULL, c->oobinfo); |
464 | ret = -EIO; | 463 | ret = -EIO; |
465 | } else | 464 | } else |
466 | #endif | 465 | #endif |
467 | 466 | ||
468 | if (jffs2_cleanmarker_oob(c)) | 467 | if (jffs2_cleanmarker_oob(c)) |
469 | ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); | 468 | ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); |
470 | else | 469 | else |
@@ -487,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
487 | spin_lock(&c->erase_completion_lock); | 486 | spin_lock(&c->erase_completion_lock); |
488 | 487 | ||
489 | /* Adjust free size of the block if we padded. */ | 488 | /* Adjust free size of the block if we padded. */ |
490 | if (pad && !jffs2_dataflash(c)) { | 489 | if (pad) { |
491 | struct jffs2_eraseblock *jeb; | 490 | struct jffs2_eraseblock *jeb; |
492 | 491 | ||
493 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | 492 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
@@ -495,7 +494,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
495 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", | 494 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", |
496 | (jeb==c->nextblock)?"next":"", jeb->offset)); | 495 | (jeb==c->nextblock)?"next":"", jeb->offset)); |
497 | 496 | ||
498 | /* wbuf_pagesize - wbuf_len is the amount of space that's to be | 497 | /* wbuf_pagesize - wbuf_len is the amount of space that's to be |
499 | padded. If there is less free space in the block than that, | 498 | padded. If there is less free space in the block than that, |
500 | something screwed up */ | 499 | something screwed up */ |
501 | if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) { | 500 | if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) { |
@@ -523,9 +522,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
523 | return 0; | 522 | return 0; |
524 | } | 523 | } |
525 | 524 | ||
526 | /* Trigger garbage collection to flush the write-buffer. | 525 | /* Trigger garbage collection to flush the write-buffer. |
527 | If ino arg is zero, do it if _any_ real (i.e. not GC) writes are | 526 | If ino arg is zero, do it if _any_ real (i.e. not GC) writes are |
528 | outstanding. If ino arg non-zero, do it only if a write for the | 527 | outstanding. If ino arg non-zero, do it only if a write for the |
529 | given inode is outstanding. */ | 528 | given inode is outstanding. */ |
530 | int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | 529 | int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) |
531 | { | 530 | { |
@@ -604,15 +603,6 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) | |||
604 | 603 | ||
605 | return ret; | 604 | return ret; |
606 | } | 605 | } |
607 | |||
608 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | ||
609 | #define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) | ||
610 | #define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) | ||
611 | #else | ||
612 | #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) | ||
613 | #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) | ||
614 | #endif | ||
615 | |||
616 | 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) | 606 | 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) |
617 | { | 607 | { |
618 | struct kvec outvecs[3]; | 608 | struct kvec outvecs[3]; |
@@ -629,13 +619,13 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
629 | /* If not NAND flash, don't bother */ | 619 | /* If not NAND flash, don't bother */ |
630 | if (!jffs2_is_writebuffered(c)) | 620 | if (!jffs2_is_writebuffered(c)) |
631 | return jffs2_flash_direct_writev(c, invecs, count, to, retlen); | 621 | return jffs2_flash_direct_writev(c, invecs, count, to, retlen); |
632 | 622 | ||
633 | down_write(&c->wbuf_sem); | 623 | down_write(&c->wbuf_sem); |
634 | 624 | ||
635 | /* If wbuf_ofs is not initialized, set it to target address */ | 625 | /* If wbuf_ofs is not initialized, set it to target address */ |
636 | if (c->wbuf_ofs == 0xFFFFFFFF) { | 626 | if (c->wbuf_ofs == 0xFFFFFFFF) { |
637 | c->wbuf_ofs = PAGE_DIV(to); | 627 | c->wbuf_ofs = PAGE_DIV(to); |
638 | c->wbuf_len = PAGE_MOD(to); | 628 | c->wbuf_len = PAGE_MOD(to); |
639 | memset(c->wbuf,0xff,c->wbuf_pagesize); | 629 | memset(c->wbuf,0xff,c->wbuf_pagesize); |
640 | } | 630 | } |
641 | 631 | ||
@@ -649,10 +639,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
649 | memset(c->wbuf,0xff,c->wbuf_pagesize); | 639 | memset(c->wbuf,0xff,c->wbuf_pagesize); |
650 | } | 640 | } |
651 | } | 641 | } |
652 | 642 | ||
653 | /* Sanity checks on target address. | 643 | /* Sanity checks on target address. |
654 | It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), | 644 | It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), |
655 | and it's permitted to write at the beginning of a new | 645 | and it's permitted to write at the beginning of a new |
656 | erase block. Anything else, and you die. | 646 | erase block. Anything else, and you die. |
657 | New block starts at xxx000c (0-b = block header) | 647 | New block starts at xxx000c (0-b = block header) |
658 | */ | 648 | */ |
@@ -670,8 +660,8 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
670 | } | 660 | } |
671 | /* set pointer to new block */ | 661 | /* set pointer to new block */ |
672 | c->wbuf_ofs = PAGE_DIV(to); | 662 | c->wbuf_ofs = PAGE_DIV(to); |
673 | c->wbuf_len = PAGE_MOD(to); | 663 | c->wbuf_len = PAGE_MOD(to); |
674 | } | 664 | } |
675 | 665 | ||
676 | if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { | 666 | if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { |
677 | /* We're not writing immediately after the writebuffer. Bad. */ | 667 | /* We're not writing immediately after the writebuffer. Bad. */ |
@@ -691,21 +681,21 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
691 | invec = 0; | 681 | invec = 0; |
692 | outvec = 0; | 682 | outvec = 0; |
693 | 683 | ||
694 | /* Fill writebuffer first, if already in use */ | 684 | /* Fill writebuffer first, if already in use */ |
695 | if (c->wbuf_len) { | 685 | if (c->wbuf_len) { |
696 | uint32_t invec_ofs = 0; | 686 | uint32_t invec_ofs = 0; |
697 | 687 | ||
698 | /* adjust alignment offset */ | 688 | /* adjust alignment offset */ |
699 | if (c->wbuf_len != PAGE_MOD(to)) { | 689 | if (c->wbuf_len != PAGE_MOD(to)) { |
700 | c->wbuf_len = PAGE_MOD(to); | 690 | c->wbuf_len = PAGE_MOD(to); |
701 | /* take care of alignment to next page */ | 691 | /* take care of alignment to next page */ |
702 | if (!c->wbuf_len) | 692 | if (!c->wbuf_len) |
703 | c->wbuf_len = c->wbuf_pagesize; | 693 | c->wbuf_len = c->wbuf_pagesize; |
704 | } | 694 | } |
705 | 695 | ||
706 | while(c->wbuf_len < c->wbuf_pagesize) { | 696 | while(c->wbuf_len < c->wbuf_pagesize) { |
707 | uint32_t thislen; | 697 | uint32_t thislen; |
708 | 698 | ||
709 | if (invec == count) | 699 | if (invec == count) |
710 | goto alldone; | 700 | goto alldone; |
711 | 701 | ||
@@ -713,17 +703,17 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
713 | 703 | ||
714 | if (thislen >= invecs[invec].iov_len) | 704 | if (thislen >= invecs[invec].iov_len) |
715 | thislen = invecs[invec].iov_len; | 705 | thislen = invecs[invec].iov_len; |
716 | 706 | ||
717 | invec_ofs = thislen; | 707 | invec_ofs = thislen; |
718 | 708 | ||
719 | memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen); | 709 | memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen); |
720 | c->wbuf_len += thislen; | 710 | c->wbuf_len += thislen; |
721 | donelen += thislen; | 711 | donelen += thislen; |
722 | /* Get next invec, if actual did not fill the buffer */ | 712 | /* Get next invec, if actual did not fill the buffer */ |
723 | if (c->wbuf_len < c->wbuf_pagesize) | 713 | if (c->wbuf_len < c->wbuf_pagesize) |
724 | invec++; | 714 | invec++; |
725 | } | 715 | } |
726 | 716 | ||
727 | /* write buffer is full, flush buffer */ | 717 | /* write buffer is full, flush buffer */ |
728 | ret = __jffs2_flush_wbuf(c, NOPAD); | 718 | ret = __jffs2_flush_wbuf(c, NOPAD); |
729 | if (ret) { | 719 | if (ret) { |
@@ -782,10 +772,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
782 | 772 | ||
783 | /* We did cross a page boundary, so we write some now */ | 773 | /* We did cross a page boundary, so we write some now */ |
784 | if (jffs2_cleanmarker_oob(c)) | 774 | if (jffs2_cleanmarker_oob(c)) |
785 | ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); | 775 | ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); |
786 | else | 776 | else |
787 | ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); | 777 | ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); |
788 | 778 | ||
789 | if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { | 779 | if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { |
790 | /* At this point we have no problem, | 780 | /* At this point we have no problem, |
791 | c->wbuf is empty. However refile nextblock to avoid | 781 | c->wbuf is empty. However refile nextblock to avoid |
@@ -802,7 +792,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
802 | spin_unlock(&c->erase_completion_lock); | 792 | spin_unlock(&c->erase_completion_lock); |
803 | goto exit; | 793 | goto exit; |
804 | } | 794 | } |
805 | 795 | ||
806 | donelen += wbuf_retlen; | 796 | donelen += wbuf_retlen; |
807 | c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); | 797 | c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); |
808 | 798 | ||
@@ -836,11 +826,17 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
836 | alldone: | 826 | alldone: |
837 | *retlen = donelen; | 827 | *retlen = donelen; |
838 | 828 | ||
829 | if (jffs2_sum_active()) { | ||
830 | int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to); | ||
831 | if (res) | ||
832 | return res; | ||
833 | } | ||
834 | |||
839 | if (c->wbuf_len && ino) | 835 | if (c->wbuf_len && ino) |
840 | jffs2_wbuf_dirties_inode(c, ino); | 836 | jffs2_wbuf_dirties_inode(c, ino); |
841 | 837 | ||
842 | ret = 0; | 838 | ret = 0; |
843 | 839 | ||
844 | exit: | 840 | exit: |
845 | up_write(&c->wbuf_sem); | 841 | up_write(&c->wbuf_sem); |
846 | return ret; | 842 | return ret; |
@@ -855,7 +851,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r | |||
855 | struct kvec vecs[1]; | 851 | struct kvec vecs[1]; |
856 | 852 | ||
857 | if (!jffs2_is_writebuffered(c)) | 853 | if (!jffs2_is_writebuffered(c)) |
858 | return c->mtd->write(c->mtd, ofs, len, retlen, buf); | 854 | return jffs2_flash_direct_write(c, ofs, len, retlen, buf); |
859 | 855 | ||
860 | vecs[0].iov_base = (unsigned char *) buf; | 856 | vecs[0].iov_base = (unsigned char *) buf; |
861 | vecs[0].iov_len = len; | 857 | vecs[0].iov_len = len; |
@@ -883,18 +879,18 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re | |||
883 | if ( (ret == -EBADMSG) && (*retlen == len) ) { | 879 | if ( (ret == -EBADMSG) && (*retlen == len) ) { |
884 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", | 880 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", |
885 | len, ofs); | 881 | len, ofs); |
886 | /* | 882 | /* |
887 | * We have the raw data without ECC correction in the buffer, maybe | 883 | * We have the raw data without ECC correction in the buffer, maybe |
888 | * we are lucky and all data or parts are correct. We check the node. | 884 | * we are lucky and all data or parts are correct. We check the node. |
889 | * If data are corrupted node check will sort it out. | 885 | * If data are corrupted node check will sort it out. |
890 | * We keep this block, it will fail on write or erase and the we | 886 | * We keep this block, it will fail on write or erase and the we |
891 | * mark it bad. Or should we do that now? But we should give him a chance. | 887 | * mark it bad. Or should we do that now? But we should give him a chance. |
892 | * Maybe we had a system crash or power loss before the ecc write or | 888 | * Maybe we had a system crash or power loss before the ecc write or |
893 | * a erase was completed. | 889 | * a erase was completed. |
894 | * So we return success. :) | 890 | * So we return success. :) |
895 | */ | 891 | */ |
896 | ret = 0; | 892 | ret = 0; |
897 | } | 893 | } |
898 | 894 | ||
899 | /* if no writebuffer available or write buffer empty, return */ | 895 | /* if no writebuffer available or write buffer empty, return */ |
900 | if (!c->wbuf_pagesize || !c->wbuf_len) | 896 | if (!c->wbuf_pagesize || !c->wbuf_len) |
@@ -909,16 +905,16 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re | |||
909 | if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ | 905 | if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ |
910 | goto exit; | 906 | goto exit; |
911 | lwbf = c->wbuf_len - owbf; /* number of bytes to copy */ | 907 | lwbf = c->wbuf_len - owbf; /* number of bytes to copy */ |
912 | if (lwbf > len) | 908 | if (lwbf > len) |
913 | lwbf = len; | 909 | lwbf = len; |
914 | } else { | 910 | } else { |
915 | orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ | 911 | orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ |
916 | if (orbf > len) /* is write beyond write buffer ? */ | 912 | if (orbf > len) /* is write beyond write buffer ? */ |
917 | goto exit; | 913 | goto exit; |
918 | lwbf = len - orbf; /* number of bytes to copy */ | 914 | lwbf = len - orbf; /* number of bytes to copy */ |
919 | if (lwbf > c->wbuf_len) | 915 | if (lwbf > c->wbuf_len) |
920 | lwbf = c->wbuf_len; | 916 | lwbf = c->wbuf_len; |
921 | } | 917 | } |
922 | if (lwbf > 0) | 918 | if (lwbf > 0) |
923 | memcpy(buf+orbf,c->wbuf+owbf,lwbf); | 919 | memcpy(buf+orbf,c->wbuf+owbf,lwbf); |
924 | 920 | ||
@@ -946,7 +942,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb | |||
946 | printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n"); | 942 | printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n"); |
947 | return -ENOMEM; | 943 | return -ENOMEM; |
948 | } | 944 | } |
949 | /* | 945 | /* |
950 | * if mode = 0, we scan for a total empty oob area, else we have | 946 | * if mode = 0, we scan for a total empty oob area, else we have |
951 | * to take care of the cleanmarker in the first page of the block | 947 | * to take care of the cleanmarker in the first page of the block |
952 | */ | 948 | */ |
@@ -955,41 +951,41 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb | |||
955 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); | 951 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); |
956 | goto out; | 952 | goto out; |
957 | } | 953 | } |
958 | 954 | ||
959 | if (retlen < len) { | 955 | if (retlen < len) { |
960 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " | 956 | D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " |
961 | "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); | 957 | "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); |
962 | ret = -EIO; | 958 | ret = -EIO; |
963 | goto out; | 959 | goto out; |
964 | } | 960 | } |
965 | 961 | ||
966 | /* Special check for first page */ | 962 | /* Special check for first page */ |
967 | for(i = 0; i < oob_size ; i++) { | 963 | for(i = 0; i < oob_size ; i++) { |
968 | /* Yeah, we know about the cleanmarker. */ | 964 | /* Yeah, we know about the cleanmarker. */ |
969 | if (mode && i >= c->fsdata_pos && | 965 | if (mode && i >= c->fsdata_pos && |
970 | i < c->fsdata_pos + c->fsdata_len) | 966 | i < c->fsdata_pos + c->fsdata_len) |
971 | continue; | 967 | continue; |
972 | 968 | ||
973 | if (buf[i] != 0xFF) { | 969 | if (buf[i] != 0xFF) { |
974 | D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n", | 970 | D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n", |
975 | buf[page+i], page+i, jeb->offset)); | 971 | buf[i], i, jeb->offset)); |
976 | ret = 1; | 972 | ret = 1; |
977 | goto out; | 973 | goto out; |
978 | } | 974 | } |
979 | } | 975 | } |
980 | 976 | ||
981 | /* we know, we are aligned :) */ | 977 | /* we know, we are aligned :) */ |
982 | for (page = oob_size; page < len; page += sizeof(long)) { | 978 | for (page = oob_size; page < len; page += sizeof(long)) { |
983 | unsigned long dat = *(unsigned long *)(&buf[page]); | 979 | unsigned long dat = *(unsigned long *)(&buf[page]); |
984 | if(dat != -1) { | 980 | if(dat != -1) { |
985 | ret = 1; | 981 | ret = 1; |
986 | goto out; | 982 | goto out; |
987 | } | 983 | } |
988 | } | 984 | } |
989 | 985 | ||
990 | out: | 986 | out: |
991 | kfree(buf); | 987 | kfree(buf); |
992 | 988 | ||
993 | return ret; | 989 | return ret; |
994 | } | 990 | } |
995 | 991 | ||
@@ -1071,7 +1067,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
1071 | n.totlen = cpu_to_je32(8); | 1067 | n.totlen = cpu_to_je32(8); |
1072 | 1068 | ||
1073 | ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n); | 1069 | ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n); |
1074 | 1070 | ||
1075 | if (ret) { | 1071 | if (ret) { |
1076 | D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); | 1072 | D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); |
1077 | return ret; | 1073 | return ret; |
@@ -1083,7 +1079,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
1083 | return 0; | 1079 | return 0; |
1084 | } | 1080 | } |
1085 | 1081 | ||
1086 | /* | 1082 | /* |
1087 | * On NAND we try to mark this block bad. If the block was erased more | 1083 | * On NAND we try to mark this block bad. If the block was erased more |
1088 | * than MAX_ERASE_FAILURES we mark it finaly bad. | 1084 | * than MAX_ERASE_FAILURES we mark it finaly bad. |
1089 | * Don't care about failures. This block remains on the erase-pending | 1085 | * Don't care about failures. This block remains on the erase-pending |
@@ -1104,7 +1100,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock * | |||
1104 | 1100 | ||
1105 | D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset)); | 1101 | D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset)); |
1106 | ret = c->mtd->block_markbad(c->mtd, bad_offset); | 1102 | ret = c->mtd->block_markbad(c->mtd, bad_offset); |
1107 | 1103 | ||
1108 | if (ret) { | 1104 | if (ret) { |
1109 | D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); | 1105 | D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); |
1110 | return ret; | 1106 | return ret; |
@@ -1128,7 +1124,7 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) | |||
1128 | /* Do this only, if we have an oob buffer */ | 1124 | /* Do this only, if we have an oob buffer */ |
1129 | if (!c->mtd->oobsize) | 1125 | if (!c->mtd->oobsize) |
1130 | return 0; | 1126 | return 0; |
1131 | 1127 | ||
1132 | /* Cleanmarker is out-of-band, so inline size zero */ | 1128 | /* Cleanmarker is out-of-band, so inline size zero */ |
1133 | c->cleanmarker_size = 0; | 1129 | c->cleanmarker_size = 0; |
1134 | 1130 | ||
@@ -1154,7 +1150,7 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) | |||
1154 | c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN; | 1150 | c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN; |
1155 | c->badblock_pos = 15; | 1151 | c->badblock_pos = 15; |
1156 | break; | 1152 | break; |
1157 | 1153 | ||
1158 | default: | 1154 | default: |
1159 | D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n")); | 1155 | D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n")); |
1160 | return -EINVAL; | 1156 | return -EINVAL; |
@@ -1171,7 +1167,7 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) | |||
1171 | init_rwsem(&c->wbuf_sem); | 1167 | init_rwsem(&c->wbuf_sem); |
1172 | c->wbuf_pagesize = c->mtd->oobblock; | 1168 | c->wbuf_pagesize = c->mtd->oobblock; |
1173 | c->wbuf_ofs = 0xFFFFFFFF; | 1169 | c->wbuf_ofs = 0xFFFFFFFF; |
1174 | 1170 | ||
1175 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | 1171 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); |
1176 | if (!c->wbuf) | 1172 | if (!c->wbuf) |
1177 | return -ENOMEM; | 1173 | return -ENOMEM; |
@@ -1197,17 +1193,41 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) | |||
1197 | 1193 | ||
1198 | int jffs2_dataflash_setup(struct jffs2_sb_info *c) { | 1194 | int jffs2_dataflash_setup(struct jffs2_sb_info *c) { |
1199 | c->cleanmarker_size = 0; /* No cleanmarkers needed */ | 1195 | c->cleanmarker_size = 0; /* No cleanmarkers needed */ |
1200 | 1196 | ||
1201 | /* Initialize write buffer */ | 1197 | /* Initialize write buffer */ |
1202 | init_rwsem(&c->wbuf_sem); | 1198 | init_rwsem(&c->wbuf_sem); |
1203 | c->wbuf_pagesize = c->sector_size; | ||
1204 | c->wbuf_ofs = 0xFFFFFFFF; | ||
1205 | 1199 | ||
1200 | |||
1201 | c->wbuf_pagesize = c->mtd->erasesize; | ||
1202 | |||
1203 | /* Find a suitable c->sector_size | ||
1204 | * - Not too much sectors | ||
1205 | * - Sectors have to be at least 4 K + some bytes | ||
1206 | * - All known dataflashes have erase sizes of 528 or 1056 | ||
1207 | * - we take at least 8 eraseblocks and want to have at least 8K size | ||
1208 | * - The concatenation should be a power of 2 | ||
1209 | */ | ||
1210 | |||
1211 | c->sector_size = 8 * c->mtd->erasesize; | ||
1212 | |||
1213 | while (c->sector_size < 8192) { | ||
1214 | c->sector_size *= 2; | ||
1215 | } | ||
1216 | |||
1217 | /* It may be necessary to adjust the flash size */ | ||
1218 | c->flash_size = c->mtd->size; | ||
1219 | |||
1220 | if ((c->flash_size % c->sector_size) != 0) { | ||
1221 | c->flash_size = (c->flash_size / c->sector_size) * c->sector_size; | ||
1222 | printk(KERN_WARNING "JFFS2 flash size adjusted to %dKiB\n", c->flash_size); | ||
1223 | }; | ||
1224 | |||
1225 | c->wbuf_ofs = 0xFFFFFFFF; | ||
1206 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | 1226 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); |
1207 | if (!c->wbuf) | 1227 | if (!c->wbuf) |
1208 | return -ENOMEM; | 1228 | return -ENOMEM; |
1209 | 1229 | ||
1210 | printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize); | 1230 | printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size); |
1211 | 1231 | ||
1212 | return 0; | 1232 | return 0; |
1213 | } | 1233 | } |
@@ -1235,3 +1255,23 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { | |||
1235 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { | 1255 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { |
1236 | kfree(c->wbuf); | 1256 | kfree(c->wbuf); |
1237 | } | 1257 | } |
1258 | |||
1259 | int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { | ||
1260 | /* Cleanmarker currently occupies a whole programming region */ | ||
1261 | c->cleanmarker_size = MTD_PROGREGION_SIZE(c->mtd); | ||
1262 | |||
1263 | /* Initialize write buffer */ | ||
1264 | init_rwsem(&c->wbuf_sem); | ||
1265 | c->wbuf_pagesize = MTD_PROGREGION_SIZE(c->mtd); | ||
1266 | c->wbuf_ofs = 0xFFFFFFFF; | ||
1267 | |||
1268 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | ||
1269 | if (!c->wbuf) | ||
1270 | return -ENOMEM; | ||
1271 | |||
1272 | return 0; | ||
1273 | } | ||
1274 | |||
1275 | void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) { | ||
1276 | kfree(c->wbuf); | ||
1277 | } | ||
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 69100615d9ae..1342f0158e9b 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: write.c,v 1.92 2005/04/13 13:22:35 dwmw2 Exp $ | 10 | * $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -54,35 +54,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint | |||
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
56 | 56 | ||
57 | #if CONFIG_JFFS2_FS_DEBUG > 0 | 57 | /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, |
58 | static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) | ||
59 | { | ||
60 | unsigned char buf[16]; | ||
61 | size_t retlen; | ||
62 | int ret, i; | ||
63 | |||
64 | ret = jffs2_flash_read(c, ofs, 16, &retlen, buf); | ||
65 | if (ret || (retlen != 16)) { | ||
66 | D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen)); | ||
67 | return; | ||
68 | } | ||
69 | ret = 0; | ||
70 | for (i=0; i<16; i++) { | ||
71 | if (buf[i] != 0xff) | ||
72 | ret = 1; | ||
73 | } | ||
74 | if (ret) { | ||
75 | printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there are data already there:\n", ofs); | ||
76 | printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
77 | ofs, | ||
78 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], | ||
79 | buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); | ||
80 | } | ||
81 | } | ||
82 | #endif | ||
83 | |||
84 | |||
85 | /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, | ||
86 | write it to the flash, link it into the existing inode/fragment list */ | 58 | write it to the flash, link it into the existing inode/fragment list */ |
87 | 59 | ||
88 | struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode) | 60 | struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode) |
@@ -106,7 +78,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
106 | vecs[1].iov_base = (unsigned char *)data; | 78 | vecs[1].iov_base = (unsigned char *)data; |
107 | vecs[1].iov_len = datalen; | 79 | vecs[1].iov_len = datalen; |
108 | 80 | ||
109 | D1(writecheck(c, flash_ofs)); | 81 | jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); |
110 | 82 | ||
111 | if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { | 83 | if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { |
112 | printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); | 84 | printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); |
@@ -114,7 +86,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
114 | raw = jffs2_alloc_raw_node_ref(); | 86 | raw = jffs2_alloc_raw_node_ref(); |
115 | if (!raw) | 87 | if (!raw) |
116 | return ERR_PTR(-ENOMEM); | 88 | return ERR_PTR(-ENOMEM); |
117 | 89 | ||
118 | fn = jffs2_alloc_full_dnode(); | 90 | fn = jffs2_alloc_full_dnode(); |
119 | if (!fn) { | 91 | if (!fn) { |
120 | jffs2_free_raw_node_ref(raw); | 92 | jffs2_free_raw_node_ref(raw); |
@@ -138,7 +110,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
138 | if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) { | 110 | if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) { |
139 | BUG_ON(!retried); | 111 | BUG_ON(!retried); |
140 | D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, " | 112 | D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, " |
141 | "highest version %d -> updating dnode\n", | 113 | "highest version %d -> updating dnode\n", |
142 | je32_to_cpu(ri->version), f->highest_version)); | 114 | je32_to_cpu(ri->version), f->highest_version)); |
143 | ri->version = cpu_to_je32(++f->highest_version); | 115 | ri->version = cpu_to_je32(++f->highest_version); |
144 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 116 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
@@ -148,7 +120,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
148 | (alloc_mode==ALLOC_GC)?0:f->inocache->ino); | 120 | (alloc_mode==ALLOC_GC)?0:f->inocache->ino); |
149 | 121 | ||
150 | if (ret || (retlen != sizeof(*ri) + datalen)) { | 122 | if (ret || (retlen != sizeof(*ri) + datalen)) { |
151 | printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", | 123 | printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", |
152 | sizeof(*ri)+datalen, flash_ofs, ret, retlen); | 124 | sizeof(*ri)+datalen, flash_ofs, ret, retlen); |
153 | 125 | ||
154 | /* Mark the space as dirtied */ | 126 | /* Mark the space as dirtied */ |
@@ -156,10 +128,10 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
156 | /* Doesn't belong to any inode */ | 128 | /* Doesn't belong to any inode */ |
157 | raw->next_in_ino = NULL; | 129 | raw->next_in_ino = NULL; |
158 | 130 | ||
159 | /* Don't change raw->size to match retlen. We may have | 131 | /* Don't change raw->size to match retlen. We may have |
160 | written the node header already, and only the data will | 132 | written the node header already, and only the data will |
161 | seem corrupted, in which case the scan would skip over | 133 | seem corrupted, in which case the scan would skip over |
162 | any node we write before the original intended end of | 134 | any node we write before the original intended end of |
163 | this node */ | 135 | this node */ |
164 | raw->flash_offset |= REF_OBSOLETE; | 136 | raw->flash_offset |= REF_OBSOLETE; |
165 | jffs2_add_physical_node_ref(c, raw); | 137 | jffs2_add_physical_node_ref(c, raw); |
@@ -176,26 +148,28 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
176 | retried = 1; | 148 | retried = 1; |
177 | 149 | ||
178 | D1(printk(KERN_DEBUG "Retrying failed write.\n")); | 150 | D1(printk(KERN_DEBUG "Retrying failed write.\n")); |
179 | 151 | ||
180 | ACCT_SANITY_CHECK(c,jeb); | 152 | jffs2_dbg_acct_sanity_check(c,jeb); |
181 | D1(ACCT_PARANOIA_CHECK(jeb)); | 153 | jffs2_dbg_acct_paranoia_check(c, jeb); |
182 | 154 | ||
183 | if (alloc_mode == ALLOC_GC) { | 155 | if (alloc_mode == ALLOC_GC) { |
184 | ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy); | 156 | ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, |
157 | &dummy, JFFS2_SUMMARY_INODE_SIZE); | ||
185 | } else { | 158 | } else { |
186 | /* Locking pain */ | 159 | /* Locking pain */ |
187 | up(&f->sem); | 160 | up(&f->sem); |
188 | jffs2_complete_reservation(c); | 161 | jffs2_complete_reservation(c); |
189 | 162 | ||
190 | ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode); | 163 | ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, |
164 | &dummy, alloc_mode, JFFS2_SUMMARY_INODE_SIZE); | ||
191 | down(&f->sem); | 165 | down(&f->sem); |
192 | } | 166 | } |
193 | 167 | ||
194 | if (!ret) { | 168 | if (!ret) { |
195 | D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); | 169 | D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); |
196 | 170 | ||
197 | ACCT_SANITY_CHECK(c,jeb); | 171 | jffs2_dbg_acct_sanity_check(c,jeb); |
198 | D1(ACCT_PARANOIA_CHECK(jeb)); | 172 | jffs2_dbg_acct_paranoia_check(c, jeb); |
199 | 173 | ||
200 | goto retry; | 174 | goto retry; |
201 | } | 175 | } |
@@ -207,9 +181,9 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
207 | return ERR_PTR(ret?ret:-EIO); | 181 | return ERR_PTR(ret?ret:-EIO); |
208 | } | 182 | } |
209 | /* Mark the space used */ | 183 | /* Mark the space used */ |
210 | /* If node covers at least a whole page, or if it starts at the | 184 | /* If node covers at least a whole page, or if it starts at the |
211 | beginning of a page and runs to the end of the file, or if | 185 | beginning of a page and runs to the end of the file, or if |
212 | it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. | 186 | it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. |
213 | */ | 187 | */ |
214 | if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || | 188 | if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || |
215 | ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && | 189 | ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && |
@@ -227,12 +201,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
227 | spin_unlock(&c->erase_completion_lock); | 201 | spin_unlock(&c->erase_completion_lock); |
228 | 202 | ||
229 | 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", | 203 | 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", |
230 | flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), | 204 | flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), |
231 | je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), | 205 | je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), |
232 | je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); | 206 | je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); |
233 | 207 | ||
234 | if (retried) { | 208 | if (retried) { |
235 | ACCT_SANITY_CHECK(c,NULL); | 209 | jffs2_dbg_acct_sanity_check(c,NULL); |
236 | } | 210 | } |
237 | 211 | ||
238 | return fn; | 212 | return fn; |
@@ -247,10 +221,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
247 | int retried = 0; | 221 | int retried = 0; |
248 | int ret; | 222 | int ret; |
249 | 223 | ||
250 | D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", | 224 | D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", |
251 | je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), | 225 | je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), |
252 | je32_to_cpu(rd->name_crc))); | 226 | je32_to_cpu(rd->name_crc))); |
253 | D1(writecheck(c, flash_ofs)); | ||
254 | 227 | ||
255 | D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { | 228 | D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { |
256 | printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); | 229 | printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); |
@@ -262,7 +235,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
262 | vecs[0].iov_len = sizeof(*rd); | 235 | vecs[0].iov_len = sizeof(*rd); |
263 | vecs[1].iov_base = (unsigned char *)name; | 236 | vecs[1].iov_base = (unsigned char *)name; |
264 | vecs[1].iov_len = namelen; | 237 | vecs[1].iov_len = namelen; |
265 | 238 | ||
239 | jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); | ||
240 | |||
266 | raw = jffs2_alloc_raw_node_ref(); | 241 | raw = jffs2_alloc_raw_node_ref(); |
267 | 242 | ||
268 | if (!raw) | 243 | if (!raw) |
@@ -301,7 +276,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
301 | ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, | 276 | ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, |
302 | (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); | 277 | (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); |
303 | if (ret || (retlen != sizeof(*rd) + namelen)) { | 278 | if (ret || (retlen != sizeof(*rd) + namelen)) { |
304 | printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", | 279 | printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", |
305 | sizeof(*rd)+namelen, flash_ofs, ret, retlen); | 280 | sizeof(*rd)+namelen, flash_ofs, ret, retlen); |
306 | /* Mark the space as dirtied */ | 281 | /* Mark the space as dirtied */ |
307 | if (retlen) { | 282 | if (retlen) { |
@@ -322,24 +297,26 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
322 | 297 | ||
323 | D1(printk(KERN_DEBUG "Retrying failed write.\n")); | 298 | D1(printk(KERN_DEBUG "Retrying failed write.\n")); |
324 | 299 | ||
325 | ACCT_SANITY_CHECK(c,jeb); | 300 | jffs2_dbg_acct_sanity_check(c,jeb); |
326 | D1(ACCT_PARANOIA_CHECK(jeb)); | 301 | jffs2_dbg_acct_paranoia_check(c, jeb); |
327 | 302 | ||
328 | if (alloc_mode == ALLOC_GC) { | 303 | if (alloc_mode == ALLOC_GC) { |
329 | ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy); | 304 | ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, |
305 | &dummy, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | ||
330 | } else { | 306 | } else { |
331 | /* Locking pain */ | 307 | /* Locking pain */ |
332 | up(&f->sem); | 308 | up(&f->sem); |
333 | jffs2_complete_reservation(c); | 309 | jffs2_complete_reservation(c); |
334 | 310 | ||
335 | ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode); | 311 | ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, |
312 | &dummy, alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | ||
336 | down(&f->sem); | 313 | down(&f->sem); |
337 | } | 314 | } |
338 | 315 | ||
339 | if (!ret) { | 316 | if (!ret) { |
340 | D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); | 317 | D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); |
341 | ACCT_SANITY_CHECK(c,jeb); | 318 | jffs2_dbg_acct_sanity_check(c,jeb); |
342 | D1(ACCT_PARANOIA_CHECK(jeb)); | 319 | jffs2_dbg_acct_paranoia_check(c, jeb); |
343 | goto retry; | 320 | goto retry; |
344 | } | 321 | } |
345 | D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); | 322 | D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); |
@@ -359,7 +336,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
359 | spin_unlock(&c->erase_completion_lock); | 336 | spin_unlock(&c->erase_completion_lock); |
360 | 337 | ||
361 | if (retried) { | 338 | if (retried) { |
362 | ACCT_SANITY_CHECK(c,NULL); | 339 | jffs2_dbg_acct_sanity_check(c,NULL); |
363 | } | 340 | } |
364 | 341 | ||
365 | return fd; | 342 | return fd; |
@@ -369,7 +346,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
369 | we don't have to go digging in struct inode or its equivalent. It should set: | 346 | we don't have to go digging in struct inode or its equivalent. It should set: |
370 | mode, uid, gid, (starting)isize, atime, ctime, mtime */ | 347 | mode, uid, gid, (starting)isize, atime, ctime, mtime */ |
371 | int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 348 | int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
372 | struct jffs2_raw_inode *ri, unsigned char *buf, | 349 | struct jffs2_raw_inode *ri, unsigned char *buf, |
373 | uint32_t offset, uint32_t writelen, uint32_t *retlen) | 350 | uint32_t offset, uint32_t writelen, uint32_t *retlen) |
374 | { | 351 | { |
375 | int ret = 0; | 352 | int ret = 0; |
@@ -377,7 +354,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
377 | 354 | ||
378 | D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n", | 355 | D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n", |
379 | f->inocache->ino, offset, writelen)); | 356 | f->inocache->ino, offset, writelen)); |
380 | 357 | ||
381 | while(writelen) { | 358 | while(writelen) { |
382 | struct jffs2_full_dnode *fn; | 359 | struct jffs2_full_dnode *fn; |
383 | unsigned char *comprbuf = NULL; | 360 | unsigned char *comprbuf = NULL; |
@@ -389,7 +366,8 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
389 | retry: | 366 | retry: |
390 | D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset)); | 367 | D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset)); |
391 | 368 | ||
392 | ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); | 369 | ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, |
370 | &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); | ||
393 | if (ret) { | 371 | if (ret) { |
394 | D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); | 372 | D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); |
395 | break; | 373 | break; |
@@ -473,10 +451,11 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
473 | uint32_t alloclen, phys_ofs; | 451 | uint32_t alloclen, phys_ofs; |
474 | int ret; | 452 | int ret; |
475 | 453 | ||
476 | /* Try to reserve enough space for both node and dirent. | 454 | /* Try to reserve enough space for both node and dirent. |
477 | * Just the node will do for now, though | 455 | * Just the node will do for now, though |
478 | */ | 456 | */ |
479 | ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); | 457 | ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL, |
458 | JFFS2_SUMMARY_INODE_SIZE); | ||
480 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); | 459 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); |
481 | if (ret) { | 460 | if (ret) { |
482 | up(&f->sem); | 461 | up(&f->sem); |
@@ -498,15 +477,16 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
498 | jffs2_complete_reservation(c); | 477 | jffs2_complete_reservation(c); |
499 | return PTR_ERR(fn); | 478 | return PTR_ERR(fn); |
500 | } | 479 | } |
501 | /* No data here. Only a metadata node, which will be | 480 | /* No data here. Only a metadata node, which will be |
502 | obsoleted by the first data write | 481 | obsoleted by the first data write |
503 | */ | 482 | */ |
504 | f->metadata = fn; | 483 | f->metadata = fn; |
505 | 484 | ||
506 | up(&f->sem); | 485 | up(&f->sem); |
507 | jffs2_complete_reservation(c); | 486 | jffs2_complete_reservation(c); |
508 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); | 487 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, |
509 | 488 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | |
489 | |||
510 | if (ret) { | 490 | if (ret) { |
511 | /* Eep. */ | 491 | /* Eep. */ |
512 | D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); | 492 | D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); |
@@ -539,9 +519,9 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
539 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); | 519 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); |
540 | 520 | ||
541 | jffs2_free_raw_dirent(rd); | 521 | jffs2_free_raw_dirent(rd); |
542 | 522 | ||
543 | if (IS_ERR(fd)) { | 523 | if (IS_ERR(fd)) { |
544 | /* dirent failed to write. Delete the inode normally | 524 | /* dirent failed to write. Delete the inode normally |
545 | as if it were the final unlink() */ | 525 | as if it were the final unlink() */ |
546 | jffs2_complete_reservation(c); | 526 | jffs2_complete_reservation(c); |
547 | up(&dir_f->sem); | 527 | up(&dir_f->sem); |
@@ -560,14 +540,15 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
560 | 540 | ||
561 | 541 | ||
562 | int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | 542 | int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, |
563 | const char *name, int namelen, struct jffs2_inode_info *dead_f) | 543 | const char *name, int namelen, struct jffs2_inode_info *dead_f, |
544 | uint32_t time) | ||
564 | { | 545 | { |
565 | struct jffs2_raw_dirent *rd; | 546 | struct jffs2_raw_dirent *rd; |
566 | struct jffs2_full_dirent *fd; | 547 | struct jffs2_full_dirent *fd; |
567 | uint32_t alloclen, phys_ofs; | 548 | uint32_t alloclen, phys_ofs; |
568 | int ret; | 549 | int ret; |
569 | 550 | ||
570 | if (1 /* alternative branch needs testing */ || | 551 | if (1 /* alternative branch needs testing */ || |
571 | !jffs2_can_mark_obsolete(c)) { | 552 | !jffs2_can_mark_obsolete(c)) { |
572 | /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */ | 553 | /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */ |
573 | 554 | ||
@@ -575,7 +556,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
575 | if (!rd) | 556 | if (!rd) |
576 | return -ENOMEM; | 557 | return -ENOMEM; |
577 | 558 | ||
578 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION); | 559 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, |
560 | ALLOC_DELETION, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | ||
579 | if (ret) { | 561 | if (ret) { |
580 | jffs2_free_raw_dirent(rd); | 562 | jffs2_free_raw_dirent(rd); |
581 | return ret; | 563 | return ret; |
@@ -588,18 +570,18 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
588 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 570 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
589 | rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); | 571 | rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); |
590 | rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); | 572 | rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); |
591 | 573 | ||
592 | rd->pino = cpu_to_je32(dir_f->inocache->ino); | 574 | rd->pino = cpu_to_je32(dir_f->inocache->ino); |
593 | rd->version = cpu_to_je32(++dir_f->highest_version); | 575 | rd->version = cpu_to_je32(++dir_f->highest_version); |
594 | rd->ino = cpu_to_je32(0); | 576 | rd->ino = cpu_to_je32(0); |
595 | rd->mctime = cpu_to_je32(get_seconds()); | 577 | rd->mctime = cpu_to_je32(time); |
596 | rd->nsize = namelen; | 578 | rd->nsize = namelen; |
597 | rd->type = DT_UNKNOWN; | 579 | rd->type = DT_UNKNOWN; |
598 | rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); | 580 | rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); |
599 | rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); | 581 | rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); |
600 | 582 | ||
601 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION); | 583 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION); |
602 | 584 | ||
603 | jffs2_free_raw_dirent(rd); | 585 | jffs2_free_raw_dirent(rd); |
604 | 586 | ||
605 | if (IS_ERR(fd)) { | 587 | if (IS_ERR(fd)) { |
@@ -618,7 +600,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
618 | down(&dir_f->sem); | 600 | down(&dir_f->sem); |
619 | 601 | ||
620 | while ((*prev) && (*prev)->nhash <= nhash) { | 602 | while ((*prev) && (*prev)->nhash <= nhash) { |
621 | if ((*prev)->nhash == nhash && | 603 | if ((*prev)->nhash == nhash && |
622 | !memcmp((*prev)->name, name, namelen) && | 604 | !memcmp((*prev)->name, name, namelen) && |
623 | !(*prev)->name[namelen]) { | 605 | !(*prev)->name[namelen]) { |
624 | struct jffs2_full_dirent *this = *prev; | 606 | struct jffs2_full_dirent *this = *prev; |
@@ -639,7 +621,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
639 | /* dead_f is NULL if this was a rename not a real unlink */ | 621 | /* dead_f is NULL if this was a rename not a real unlink */ |
640 | /* Also catch the !f->inocache case, where there was a dirent | 622 | /* Also catch the !f->inocache case, where there was a dirent |
641 | pointing to an inode which didn't exist. */ | 623 | pointing to an inode which didn't exist. */ |
642 | if (dead_f && dead_f->inocache) { | 624 | if (dead_f && dead_f->inocache) { |
643 | 625 | ||
644 | down(&dead_f->sem); | 626 | down(&dead_f->sem); |
645 | 627 | ||
@@ -647,9 +629,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
647 | while (dead_f->dents) { | 629 | while (dead_f->dents) { |
648 | /* There can be only deleted ones */ | 630 | /* There can be only deleted ones */ |
649 | fd = dead_f->dents; | 631 | fd = dead_f->dents; |
650 | 632 | ||
651 | dead_f->dents = fd->next; | 633 | dead_f->dents = fd->next; |
652 | 634 | ||
653 | if (fd->ino) { | 635 | if (fd->ino) { |
654 | printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", | 636 | printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", |
655 | dead_f->inocache->ino, fd->name, fd->ino); | 637 | dead_f->inocache->ino, fd->name, fd->ino); |
@@ -673,7 +655,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
673 | } | 655 | } |
674 | 656 | ||
675 | 657 | ||
676 | int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen) | 658 | int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen, uint32_t time) |
677 | { | 659 | { |
678 | struct jffs2_raw_dirent *rd; | 660 | struct jffs2_raw_dirent *rd; |
679 | struct jffs2_full_dirent *fd; | 661 | struct jffs2_full_dirent *fd; |
@@ -684,12 +666,13 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
684 | if (!rd) | 666 | if (!rd) |
685 | return -ENOMEM; | 667 | return -ENOMEM; |
686 | 668 | ||
687 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); | 669 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, |
670 | ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | ||
688 | if (ret) { | 671 | if (ret) { |
689 | jffs2_free_raw_dirent(rd); | 672 | jffs2_free_raw_dirent(rd); |
690 | return ret; | 673 | return ret; |
691 | } | 674 | } |
692 | 675 | ||
693 | down(&dir_f->sem); | 676 | down(&dir_f->sem); |
694 | 677 | ||
695 | /* Build a deletion node */ | 678 | /* Build a deletion node */ |
@@ -701,7 +684,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
701 | rd->pino = cpu_to_je32(dir_f->inocache->ino); | 684 | rd->pino = cpu_to_je32(dir_f->inocache->ino); |
702 | rd->version = cpu_to_je32(++dir_f->highest_version); | 685 | rd->version = cpu_to_je32(++dir_f->highest_version); |
703 | rd->ino = cpu_to_je32(ino); | 686 | rd->ino = cpu_to_je32(ino); |
704 | rd->mctime = cpu_to_je32(get_seconds()); | 687 | rd->mctime = cpu_to_je32(time); |
705 | rd->nsize = namelen; | 688 | rd->nsize = namelen; |
706 | 689 | ||
707 | rd->type = type; | 690 | rd->type = type; |
@@ -710,7 +693,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
710 | rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); | 693 | rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); |
711 | 694 | ||
712 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); | 695 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); |
713 | 696 | ||
714 | jffs2_free_raw_dirent(rd); | 697 | jffs2_free_raw_dirent(rd); |
715 | 698 | ||
716 | if (IS_ERR(fd)) { | 699 | if (IS_ERR(fd)) { |
diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c index f079f8388566..c638ae1008de 100644 --- a/fs/jffs2/writev.c +++ b/fs/jffs2/writev.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: writev.c,v 1.6 2004/11/16 20:36:12 dwmw2 Exp $ | 10 | * $Id: writev.c,v 1.8 2005/09/09 15:11:58 havasi Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -42,9 +42,40 @@ static inline int mtd_fake_writev(struct mtd_info *mtd, const struct kvec *vecs, | |||
42 | int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, | 42 | int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, |
43 | unsigned long count, loff_t to, size_t *retlen) | 43 | unsigned long count, loff_t to, size_t *retlen) |
44 | { | 44 | { |
45 | if (!jffs2_is_writebuffered(c)) { | ||
46 | if (jffs2_sum_active()) { | ||
47 | int res; | ||
48 | res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to); | ||
49 | if (res) { | ||
50 | return res; | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
45 | if (c->mtd->writev) | 55 | if (c->mtd->writev) |
46 | return c->mtd->writev(c->mtd, vecs, count, to, retlen); | 56 | return c->mtd->writev(c->mtd, vecs, count, to, retlen); |
47 | else | 57 | else { |
48 | return mtd_fake_writev(c->mtd, vecs, count, to, retlen); | 58 | return mtd_fake_writev(c->mtd, vecs, count, to, retlen); |
59 | } | ||
49 | } | 60 | } |
50 | 61 | ||
62 | int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, | ||
63 | size_t *retlen, const u_char *buf) | ||
64 | { | ||
65 | int ret; | ||
66 | ret = c->mtd->write(c->mtd, ofs, len, retlen, buf); | ||
67 | |||
68 | if (jffs2_sum_active()) { | ||
69 | struct kvec vecs[1]; | ||
70 | int res; | ||
71 | |||
72 | vecs[0].iov_base = (unsigned char *) buf; | ||
73 | vecs[0].iov_len = len; | ||
74 | |||
75 | res = jffs2_sum_add_kvec(c, vecs, 1, (uint32_t) ofs); | ||
76 | if (res) { | ||
77 | return res; | ||
78 | } | ||
79 | } | ||
80 | return ret; | ||
81 | } | ||
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h index 419fc953ac16..cf792bb3c726 100644 --- a/include/linux/jffs2.h +++ b/include/linux/jffs2.h | |||
@@ -5,10 +5,10 @@ | |||
5 | * | 5 | * |
6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in the | 8 | * For licensing information, see the file 'LICENCE' in the |
9 | * jffs2 directory. | 9 | * jffs2 directory. |
10 | * | 10 | * |
11 | * $Id: jffs2.h,v 1.34 2004/11/16 20:36:14 dwmw2 Exp $ | 11 | * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $ |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
@@ -28,6 +28,9 @@ | |||
28 | #define JFFS2_EMPTY_BITMASK 0xffff | 28 | #define JFFS2_EMPTY_BITMASK 0xffff |
29 | #define JFFS2_DIRTY_BITMASK 0x0000 | 29 | #define JFFS2_DIRTY_BITMASK 0x0000 |
30 | 30 | ||
31 | /* Summary node MAGIC marker */ | ||
32 | #define JFFS2_SUM_MAGIC 0x02851885 | ||
33 | |||
31 | /* We only allow a single char for length, and 0xFF is empty flash so | 34 | /* We only allow a single char for length, and 0xFF is empty flash so |
32 | we don't want it confused with a real length. Hence max 254. | 35 | we don't want it confused with a real length. Hence max 254. |
33 | */ | 36 | */ |
@@ -43,8 +46,6 @@ | |||
43 | #define JFFS2_COMPR_COPY 0x04 | 46 | #define JFFS2_COMPR_COPY 0x04 |
44 | #define JFFS2_COMPR_DYNRUBIN 0x05 | 47 | #define JFFS2_COMPR_DYNRUBIN 0x05 |
45 | #define JFFS2_COMPR_ZLIB 0x06 | 48 | #define JFFS2_COMPR_ZLIB 0x06 |
46 | #define JFFS2_COMPR_LZO 0x07 | ||
47 | #define JFFS2_COMPR_LZARI 0x08 | ||
48 | /* Compatibility flags. */ | 49 | /* Compatibility flags. */ |
49 | #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ | 50 | #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ |
50 | #define JFFS2_NODE_ACCURATE 0x2000 | 51 | #define JFFS2_NODE_ACCURATE 0x2000 |
@@ -62,15 +63,17 @@ | |||
62 | #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) | 63 | #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) |
63 | #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) | 64 | #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) |
64 | 65 | ||
66 | #define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) | ||
67 | |||
65 | // Maybe later... | 68 | // Maybe later... |
66 | //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) | 69 | //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) |
67 | //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) | 70 | //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) |
68 | 71 | ||
69 | 72 | ||
70 | #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at | 73 | #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at |
71 | mount time, don't wait for it to | 74 | mount time, don't wait for it to |
72 | happen later */ | 75 | happen later */ |
73 | #define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific | 76 | #define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific |
74 | compression type */ | 77 | compression type */ |
75 | 78 | ||
76 | 79 | ||
@@ -101,7 +104,7 @@ struct jffs2_unknown_node | |||
101 | struct jffs2_raw_dirent | 104 | struct jffs2_raw_dirent |
102 | { | 105 | { |
103 | jint16_t magic; | 106 | jint16_t magic; |
104 | jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ | 107 | jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */ |
105 | jint32_t totlen; | 108 | jint32_t totlen; |
106 | jint32_t hdr_crc; | 109 | jint32_t hdr_crc; |
107 | jint32_t pino; | 110 | jint32_t pino; |
@@ -117,7 +120,7 @@ struct jffs2_raw_dirent | |||
117 | } __attribute__((packed)); | 120 | } __attribute__((packed)); |
118 | 121 | ||
119 | /* The JFFS2 raw inode structure: Used for storage on physical media. */ | 122 | /* The JFFS2 raw inode structure: Used for storage on physical media. */ |
120 | /* The uid, gid, atime, mtime and ctime members could be longer, but | 123 | /* The uid, gid, atime, mtime and ctime members could be longer, but |
121 | are left like this for space efficiency. If and when people decide | 124 | are left like this for space efficiency. If and when people decide |
122 | they really need them extended, it's simple enough to add support for | 125 | they really need them extended, it's simple enough to add support for |
123 | a new type of raw node. | 126 | a new type of raw node. |
@@ -125,7 +128,7 @@ struct jffs2_raw_dirent | |||
125 | struct jffs2_raw_inode | 128 | struct jffs2_raw_inode |
126 | { | 129 | { |
127 | jint16_t magic; /* A constant magic number. */ | 130 | jint16_t magic; /* A constant magic number. */ |
128 | jint16_t nodetype; /* == JFFS_NODETYPE_INODE */ | 131 | jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */ |
129 | jint32_t totlen; /* Total length of this node (inc data, etc.) */ | 132 | jint32_t totlen; /* Total length of this node (inc data, etc.) */ |
130 | jint32_t hdr_crc; | 133 | jint32_t hdr_crc; |
131 | jint32_t ino; /* Inode number. */ | 134 | jint32_t ino; /* Inode number. */ |
@@ -148,9 +151,25 @@ struct jffs2_raw_inode | |||
148 | uint8_t data[0]; | 151 | uint8_t data[0]; |
149 | } __attribute__((packed)); | 152 | } __attribute__((packed)); |
150 | 153 | ||
151 | union jffs2_node_union { | 154 | struct jffs2_raw_summary |
155 | { | ||
156 | jint16_t magic; | ||
157 | jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */ | ||
158 | jint32_t totlen; | ||
159 | jint32_t hdr_crc; | ||
160 | jint32_t sum_num; /* number of sum entries*/ | ||
161 | jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */ | ||
162 | jint32_t padded; /* sum of the size of padding nodes */ | ||
163 | jint32_t sum_crc; /* summary information crc */ | ||
164 | jint32_t node_crc; /* node crc */ | ||
165 | jint32_t sum[0]; /* inode summary info */ | ||
166 | } __attribute__((packed)); | ||
167 | |||
168 | union jffs2_node_union | ||
169 | { | ||
152 | struct jffs2_raw_inode i; | 170 | struct jffs2_raw_inode i; |
153 | struct jffs2_raw_dirent d; | 171 | struct jffs2_raw_dirent d; |
172 | struct jffs2_raw_summary s; | ||
154 | struct jffs2_unknown_node u; | 173 | struct jffs2_unknown_node u; |
155 | }; | 174 | }; |
156 | 175 | ||
diff --git a/include/linux/jffs2_fs_i.h b/include/linux/jffs2_fs_i.h index 6dbb1cce6646..ef85ab56302b 100644 --- a/include/linux/jffs2_fs_i.h +++ b/include/linux/jffs2_fs_i.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: jffs2_fs_i.h,v 1.17 2004/11/11 23:51:27 dwmw2 Exp $ */ | 1 | /* $Id: jffs2_fs_i.h,v 1.19 2005/11/07 11:14:52 gleixner Exp $ */ |
2 | 2 | ||
3 | #ifndef _JFFS2_FS_I | 3 | #ifndef _JFFS2_FS_I |
4 | #define _JFFS2_FS_I | 4 | #define _JFFS2_FS_I |
@@ -25,13 +25,16 @@ struct jffs2_inode_info { | |||
25 | /* There may be one datanode which isn't referenced by any of the | 25 | /* There may be one datanode which isn't referenced by any of the |
26 | above fragments, if it contains a metadata update but no actual | 26 | above fragments, if it contains a metadata update but no actual |
27 | data - or if this is a directory inode */ | 27 | data - or if this is a directory inode */ |
28 | /* This also holds the _only_ dnode for symlinks/device nodes, | 28 | /* This also holds the _only_ dnode for symlinks/device nodes, |
29 | etc. */ | 29 | etc. */ |
30 | struct jffs2_full_dnode *metadata; | 30 | struct jffs2_full_dnode *metadata; |
31 | 31 | ||
32 | /* Directory entries */ | 32 | /* Directory entries */ |
33 | struct jffs2_full_dirent *dents; | 33 | struct jffs2_full_dirent *dents; |
34 | 34 | ||
35 | /* The target path if this is the inode of a symlink */ | ||
36 | unsigned char *target; | ||
37 | |||
35 | /* Some stuff we just have to keep in-core at all times, for each inode. */ | 38 | /* Some stuff we just have to keep in-core at all times, for each inode. */ |
36 | struct jffs2_inode_cache *inocache; | 39 | struct jffs2_inode_cache *inocache; |
37 | 40 | ||
diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h index 1e21546622de..4bcfb5570221 100644 --- a/include/linux/jffs2_fs_sb.h +++ b/include/linux/jffs2_fs_sb.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: jffs2_fs_sb.h,v 1.52 2005/05/19 16:12:17 gleixner Exp $ */ | 1 | /* $Id: jffs2_fs_sb.h,v 1.54 2005/09/21 13:37:34 dedekind Exp $ */ |
2 | 2 | ||
3 | #ifndef _JFFS2_FS_SB | 3 | #ifndef _JFFS2_FS_SB |
4 | #define _JFFS2_FS_SB | 4 | #define _JFFS2_FS_SB |
@@ -20,7 +20,7 @@ | |||
20 | struct jffs2_inodirty; | 20 | struct jffs2_inodirty; |
21 | 21 | ||
22 | /* A struct for the overall file system control. Pointers to | 22 | /* A struct for the overall file system control. Pointers to |
23 | jffs2_sb_info structs are named `c' in the source code. | 23 | jffs2_sb_info structs are named `c' in the source code. |
24 | Nee jffs_control | 24 | Nee jffs_control |
25 | */ | 25 | */ |
26 | struct jffs2_sb_info { | 26 | struct jffs2_sb_info { |
@@ -35,7 +35,7 @@ struct jffs2_sb_info { | |||
35 | struct completion gc_thread_start; /* GC thread start completion */ | 35 | struct completion gc_thread_start; /* GC thread start completion */ |
36 | struct completion gc_thread_exit; /* GC thread exit completion port */ | 36 | struct completion gc_thread_exit; /* GC thread exit completion port */ |
37 | 37 | ||
38 | struct semaphore alloc_sem; /* Used to protect all the following | 38 | struct semaphore alloc_sem; /* Used to protect all the following |
39 | fields, and also to protect against | 39 | fields, and also to protect against |
40 | out-of-order writing of nodes. And GC. */ | 40 | out-of-order writing of nodes. And GC. */ |
41 | uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER | 41 | uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER |
@@ -64,7 +64,7 @@ struct jffs2_sb_info { | |||
64 | uint32_t nospc_dirty_size; | 64 | uint32_t nospc_dirty_size; |
65 | 65 | ||
66 | uint32_t nr_blocks; | 66 | uint32_t nr_blocks; |
67 | struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks | 67 | struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks |
68 | * from the offset (blocks[ofs / sector_size]) */ | 68 | * from the offset (blocks[ofs / sector_size]) */ |
69 | struct jffs2_eraseblock *nextblock; /* The block we're currently filling */ | 69 | struct jffs2_eraseblock *nextblock; /* The block we're currently filling */ |
70 | 70 | ||
@@ -82,25 +82,26 @@ struct jffs2_sb_info { | |||
82 | struct list_head bad_list; /* Bad blocks. */ | 82 | struct list_head bad_list; /* Bad blocks. */ |
83 | struct list_head bad_used_list; /* Bad blocks with valid data in. */ | 83 | struct list_head bad_used_list; /* Bad blocks with valid data in. */ |
84 | 84 | ||
85 | spinlock_t erase_completion_lock; /* Protect free_list and erasing_list | 85 | spinlock_t erase_completion_lock; /* Protect free_list and erasing_list |
86 | against erase completion handler */ | 86 | against erase completion handler */ |
87 | wait_queue_head_t erase_wait; /* For waiting for erases to complete */ | 87 | wait_queue_head_t erase_wait; /* For waiting for erases to complete */ |
88 | 88 | ||
89 | wait_queue_head_t inocache_wq; | 89 | wait_queue_head_t inocache_wq; |
90 | struct jffs2_inode_cache **inocache_list; | 90 | struct jffs2_inode_cache **inocache_list; |
91 | spinlock_t inocache_lock; | 91 | spinlock_t inocache_lock; |
92 | 92 | ||
93 | /* Sem to allow jffs2_garbage_collect_deletion_dirent to | 93 | /* Sem to allow jffs2_garbage_collect_deletion_dirent to |
94 | drop the erase_completion_lock while it's holding a pointer | 94 | drop the erase_completion_lock while it's holding a pointer |
95 | to an obsoleted node. I don't like this. Alternatives welcomed. */ | 95 | to an obsoleted node. I don't like this. Alternatives welcomed. */ |
96 | struct semaphore erase_free_sem; | 96 | struct semaphore erase_free_sem; |
97 | 97 | ||
98 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ | ||
99 | |||
98 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | 100 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
99 | /* Write-behind buffer for NAND flash */ | 101 | /* Write-behind buffer for NAND flash */ |
100 | unsigned char *wbuf; | 102 | unsigned char *wbuf; |
101 | uint32_t wbuf_ofs; | 103 | uint32_t wbuf_ofs; |
102 | uint32_t wbuf_len; | 104 | uint32_t wbuf_len; |
103 | uint32_t wbuf_pagesize; | ||
104 | struct jffs2_inodirty *wbuf_inodes; | 105 | struct jffs2_inodirty *wbuf_inodes; |
105 | 106 | ||
106 | struct rw_semaphore wbuf_sem; /* Protects the write buffer */ | 107 | struct rw_semaphore wbuf_sem; /* Protects the write buffer */ |
@@ -112,6 +113,8 @@ struct jffs2_sb_info { | |||
112 | uint32_t fsdata_len; | 113 | uint32_t fsdata_len; |
113 | #endif | 114 | #endif |
114 | 115 | ||
116 | struct jffs2_summary *summary; /* Summary information */ | ||
117 | |||
115 | /* OS-private pointer for getting back to master superblock info */ | 118 | /* OS-private pointer for getting back to master superblock info */ |
116 | void *os_priv; | 119 | void *os_priv; |
117 | }; | 120 | }; |
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h new file mode 100644 index 000000000000..7a7fbe87fef0 --- /dev/null +++ b/include/linux/mtd/bbm.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * linux/include/linux/mtd/bbm.h | ||
3 | * | ||
4 | * NAND family Bad Block Management (BBM) header file | ||
5 | * - Bad Block Table (BBT) implementation | ||
6 | * | ||
7 | * Copyright (c) 2005 Samsung Electronics | ||
8 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
9 | * | ||
10 | * Copyright (c) 2000-2005 | ||
11 | * Thomas Gleixner <tglx@linuxtronix.de> | ||
12 | * | ||
13 | */ | ||
14 | #ifndef __LINUX_MTD_BBM_H | ||
15 | #define __LINUX_MTD_BBM_H | ||
16 | |||
17 | /* The maximum number of NAND chips in an array */ | ||
18 | #define NAND_MAX_CHIPS 8 | ||
19 | |||
20 | /** | ||
21 | * struct nand_bbt_descr - bad block table descriptor | ||
22 | * @param options options for this descriptor | ||
23 | * @param pages the page(s) where we find the bbt, used with | ||
24 | * option BBT_ABSPAGE when bbt is searched, | ||
25 | * then we store the found bbts pages here. | ||
26 | * Its an array and supports up to 8 chips now | ||
27 | * @param offs offset of the pattern in the oob area of the page | ||
28 | * @param veroffs offset of the bbt version counter in the oob are of the page | ||
29 | * @param version version read from the bbt page during scan | ||
30 | * @param len length of the pattern, if 0 no pattern check is performed | ||
31 | * @param maxblocks maximum number of blocks to search for a bbt. This number of | ||
32 | * blocks is reserved at the end of the device | ||
33 | * where the tables are written. | ||
34 | * @param reserved_block_code if non-0, this pattern denotes a reserved | ||
35 | * (rather than bad) block in the stored bbt | ||
36 | * @param pattern pattern to identify bad block table or factory marked | ||
37 | * good / bad blocks, can be NULL, if len = 0 | ||
38 | * | ||
39 | * Descriptor for the bad block table marker and the descriptor for the | ||
40 | * pattern which identifies good and bad blocks. The assumption is made | ||
41 | * that the pattern and the version count are always located in the oob area | ||
42 | * of the first block. | ||
43 | */ | ||
44 | struct nand_bbt_descr { | ||
45 | int options; | ||
46 | int pages[NAND_MAX_CHIPS]; | ||
47 | int offs; | ||
48 | int veroffs; | ||
49 | uint8_t version[NAND_MAX_CHIPS]; | ||
50 | int len; | ||
51 | int maxblocks; | ||
52 | int reserved_block_code; | ||
53 | uint8_t *pattern; | ||
54 | }; | ||
55 | |||
56 | /* Options for the bad block table descriptors */ | ||
57 | |||
58 | /* The number of bits used per block in the bbt on the device */ | ||
59 | #define NAND_BBT_NRBITS_MSK 0x0000000F | ||
60 | #define NAND_BBT_1BIT 0x00000001 | ||
61 | #define NAND_BBT_2BIT 0x00000002 | ||
62 | #define NAND_BBT_4BIT 0x00000004 | ||
63 | #define NAND_BBT_8BIT 0x00000008 | ||
64 | /* The bad block table is in the last good block of the device */ | ||
65 | #define NAND_BBT_LASTBLOCK 0x00000010 | ||
66 | /* The bbt is at the given page, else we must scan for the bbt */ | ||
67 | #define NAND_BBT_ABSPAGE 0x00000020 | ||
68 | /* The bbt is at the given page, else we must scan for the bbt */ | ||
69 | #define NAND_BBT_SEARCH 0x00000040 | ||
70 | /* bbt is stored per chip on multichip devices */ | ||
71 | #define NAND_BBT_PERCHIP 0x00000080 | ||
72 | /* bbt has a version counter at offset veroffs */ | ||
73 | #define NAND_BBT_VERSION 0x00000100 | ||
74 | /* Create a bbt if none axists */ | ||
75 | #define NAND_BBT_CREATE 0x00000200 | ||
76 | /* Search good / bad pattern through all pages of a block */ | ||
77 | #define NAND_BBT_SCANALLPAGES 0x00000400 | ||
78 | /* Scan block empty during good / bad block scan */ | ||
79 | #define NAND_BBT_SCANEMPTY 0x00000800 | ||
80 | /* Write bbt if neccecary */ | ||
81 | #define NAND_BBT_WRITE 0x00001000 | ||
82 | /* Read and write back block contents when writing bbt */ | ||
83 | #define NAND_BBT_SAVECONTENT 0x00002000 | ||
84 | /* Search good / bad pattern on the first and the second page */ | ||
85 | #define NAND_BBT_SCAN2NDPAGE 0x00004000 | ||
86 | |||
87 | /* The maximum number of blocks to scan for a bbt */ | ||
88 | #define NAND_BBT_SCAN_MAXBLOCKS 4 | ||
89 | |||
90 | /* | ||
91 | * Constants for oob configuration | ||
92 | */ | ||
93 | #define ONENAND_BADBLOCK_POS 0 | ||
94 | |||
95 | /** | ||
96 | * struct bbt_info - [GENERIC] Bad Block Table data structure | ||
97 | * @param bbt_erase_shift [INTERN] number of address bits in a bbt entry | ||
98 | * @param badblockpos [INTERN] position of the bad block marker in the oob area | ||
99 | * @param bbt [INTERN] bad block table pointer | ||
100 | * @param badblock_pattern [REPLACEABLE] bad block scan pattern used for initial bad block scan | ||
101 | * @param priv [OPTIONAL] pointer to private bbm date | ||
102 | */ | ||
103 | struct bbm_info { | ||
104 | int bbt_erase_shift; | ||
105 | int badblockpos; | ||
106 | int options; | ||
107 | |||
108 | uint8_t *bbt; | ||
109 | |||
110 | int (*isbad_bbt)(struct mtd_info *mtd, loff_t ofs, int allowbbt); | ||
111 | |||
112 | /* TODO Add more NAND specific fileds */ | ||
113 | struct nand_bbt_descr *badblock_pattern; | ||
114 | |||
115 | void *priv; | ||
116 | }; | ||
117 | |||
118 | /* OneNAND BBT interface */ | ||
119 | extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd); | ||
120 | extern int onenand_default_bbt(struct mtd_info *mtd); | ||
121 | |||
122 | #endif /* __LINUX_MTD_BBM_H */ | ||
diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h index 4ebc2e5a16e2..f46afec6fbf8 100644 --- a/include/linux/mtd/blktrans.h +++ b/include/linux/mtd/blktrans.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: blktrans.h,v 1.5 2003/06/23 12:00:08 dwmw2 Exp $ | 2 | * $Id: blktrans.h,v 1.6 2005/11/07 11:14:54 gleixner Exp $ |
3 | * | 3 | * |
4 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> | 4 | * (C) 2003 David Woodhouse <dwmw2@infradead.org> |
5 | * | 5 | * |
@@ -67,6 +67,6 @@ extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr); | |||
67 | extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); | 67 | extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); |
68 | extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); | 68 | extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); |
69 | extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); | 69 | extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); |
70 | 70 | ||
71 | 71 | ||
72 | #endif /* __MTD_TRANS_H__ */ | 72 | #endif /* __MTD_TRANS_H__ */ |
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index e6b6a1c66bd5..39f1430bd6d5 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h | |||
@@ -1,7 +1,7 @@ | |||
1 | 1 | ||
2 | /* Common Flash Interface structures | 2 | /* Common Flash Interface structures |
3 | * See http://support.intel.com/design/flash/technote/index.htm | 3 | * See http://support.intel.com/design/flash/technote/index.htm |
4 | * $Id: cfi.h,v 1.54 2005/06/06 23:04:36 tpoynor Exp $ | 4 | * $Id: cfi.h,v 1.56 2005/11/07 11:14:54 gleixner Exp $ |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #ifndef __MTD_CFI_H__ | 7 | #ifndef __MTD_CFI_H__ |
@@ -82,8 +82,8 @@ static inline int cfi_interleave_supported(int i) | |||
82 | } | 82 | } |
83 | 83 | ||
84 | 84 | ||
85 | /* NB: these values must represents the number of bytes needed to meet the | 85 | /* NB: these values must represents the number of bytes needed to meet the |
86 | * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. | 86 | * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. |
87 | * These numbers are used in calculations. | 87 | * These numbers are used in calculations. |
88 | */ | 88 | */ |
89 | #define CFI_DEVICETYPE_X8 (8 / 8) | 89 | #define CFI_DEVICETYPE_X8 (8 / 8) |
@@ -173,6 +173,15 @@ struct cfi_intelext_regioninfo { | |||
173 | struct cfi_intelext_blockinfo BlockTypes[1]; | 173 | struct cfi_intelext_blockinfo BlockTypes[1]; |
174 | } __attribute__((packed)); | 174 | } __attribute__((packed)); |
175 | 175 | ||
176 | struct cfi_intelext_programming_regioninfo { | ||
177 | uint8_t ProgRegShift; | ||
178 | uint8_t Reserved1; | ||
179 | uint8_t ControlValid; | ||
180 | uint8_t Reserved2; | ||
181 | uint8_t ControlInvalid; | ||
182 | uint8_t Reserved3; | ||
183 | } __attribute__((packed)); | ||
184 | |||
176 | /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ | 185 | /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ |
177 | 186 | ||
178 | struct cfi_pri_amdstd { | 187 | struct cfi_pri_amdstd { |
@@ -250,7 +259,7 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int | |||
250 | /* | 259 | /* |
251 | * Transforms the CFI command for the given geometry (bus width & interleave). | 260 | * Transforms the CFI command for the given geometry (bus width & interleave). |
252 | * It looks too long to be inline, but in the common case it should almost all | 261 | * It looks too long to be inline, but in the common case it should almost all |
253 | * get optimised away. | 262 | * get optimised away. |
254 | */ | 263 | */ |
255 | static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi) | 264 | static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi) |
256 | { | 265 | { |
@@ -259,7 +268,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf | |||
259 | unsigned long onecmd; | 268 | unsigned long onecmd; |
260 | int i; | 269 | int i; |
261 | 270 | ||
262 | /* We do it this way to give the compiler a fighting chance | 271 | /* We do it this way to give the compiler a fighting chance |
263 | of optimising away all the crap for 'bankwidth' larger than | 272 | of optimising away all the crap for 'bankwidth' larger than |
264 | an unsigned long, in the common case where that support is | 273 | an unsigned long, in the common case where that support is |
265 | disabled */ | 274 | disabled */ |
@@ -270,7 +279,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf | |||
270 | wordwidth = map_bankwidth(map); | 279 | wordwidth = map_bankwidth(map); |
271 | words_per_bus = 1; | 280 | words_per_bus = 1; |
272 | } | 281 | } |
273 | 282 | ||
274 | chip_mode = map_bankwidth(map) / cfi_interleave(cfi); | 283 | chip_mode = map_bankwidth(map) / cfi_interleave(cfi); |
275 | chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); | 284 | chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); |
276 | 285 | ||
@@ -289,7 +298,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf | |||
289 | break; | 298 | break; |
290 | } | 299 | } |
291 | 300 | ||
292 | /* Now replicate it across the size of an unsigned long, or | 301 | /* Now replicate it across the size of an unsigned long, or |
293 | just to the bus width as appropriate */ | 302 | just to the bus width as appropriate */ |
294 | switch (chips_per_word) { | 303 | switch (chips_per_word) { |
295 | default: BUG(); | 304 | default: BUG(); |
@@ -305,7 +314,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf | |||
305 | ; | 314 | ; |
306 | } | 315 | } |
307 | 316 | ||
308 | /* And finally, for the multi-word case, replicate it | 317 | /* And finally, for the multi-word case, replicate it |
309 | in all words in the structure */ | 318 | in all words in the structure */ |
310 | for (i=0; i < words_per_bus; i++) { | 319 | for (i=0; i < words_per_bus; i++) { |
311 | val.x[i] = onecmd; | 320 | val.x[i] = onecmd; |
@@ -316,14 +325,14 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf | |||
316 | #define CMD(x) cfi_build_cmd((x), map, cfi) | 325 | #define CMD(x) cfi_build_cmd((x), map, cfi) |
317 | 326 | ||
318 | 327 | ||
319 | static inline unsigned char cfi_merge_status(map_word val, struct map_info *map, | 328 | static inline unsigned long cfi_merge_status(map_word val, struct map_info *map, |
320 | struct cfi_private *cfi) | 329 | struct cfi_private *cfi) |
321 | { | 330 | { |
322 | int wordwidth, words_per_bus, chip_mode, chips_per_word; | 331 | int wordwidth, words_per_bus, chip_mode, chips_per_word; |
323 | unsigned long onestat, res = 0; | 332 | unsigned long onestat, res = 0; |
324 | int i; | 333 | int i; |
325 | 334 | ||
326 | /* We do it this way to give the compiler a fighting chance | 335 | /* We do it this way to give the compiler a fighting chance |
327 | of optimising away all the crap for 'bankwidth' larger than | 336 | of optimising away all the crap for 'bankwidth' larger than |
328 | an unsigned long, in the common case where that support is | 337 | an unsigned long, in the common case where that support is |
329 | disabled */ | 338 | disabled */ |
@@ -334,7 +343,7 @@ static inline unsigned char cfi_merge_status(map_word val, struct map_info *map, | |||
334 | wordwidth = map_bankwidth(map); | 343 | wordwidth = map_bankwidth(map); |
335 | words_per_bus = 1; | 344 | words_per_bus = 1; |
336 | } | 345 | } |
337 | 346 | ||
338 | chip_mode = map_bankwidth(map) / cfi_interleave(cfi); | 347 | chip_mode = map_bankwidth(map) / cfi_interleave(cfi); |
339 | chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); | 348 | chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); |
340 | 349 | ||
diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h index 953e64fb8ac5..386a52cf8b1b 100644 --- a/include/linux/mtd/doc2000.h +++ b/include/linux/mtd/doc2000.h | |||
@@ -1,12 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * Linux driver for Disk-On-Chip devices | 2 | * Linux driver for Disk-On-Chip devices |
3 | * | 3 | * |
4 | * Copyright (C) 1999 Machine Vision Holdings, Inc. | 4 | * Copyright (C) 1999 Machine Vision Holdings, Inc. |
5 | * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org> | 5 | * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org> |
6 | * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com> | 6 | * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com> |
7 | * Copyright (C) 2002-2003 SnapGear Inc | 7 | * Copyright (C) 2002-2003 SnapGear Inc |
8 | * | 8 | * |
9 | * $Id: doc2000.h,v 1.24 2005/01/05 12:40:38 dwmw2 Exp $ | 9 | * $Id: doc2000.h,v 1.25 2005/11/07 11:14:54 gleixner Exp $ |
10 | * | 10 | * |
11 | * Released under GPL | 11 | * Released under GPL |
12 | */ | 12 | */ |
@@ -75,10 +75,10 @@ | |||
75 | #define DoC_Mplus_CtrlConfirm 0x1076 | 75 | #define DoC_Mplus_CtrlConfirm 0x1076 |
76 | #define DoC_Mplus_Power 0x1fff | 76 | #define DoC_Mplus_Power 0x1fff |
77 | 77 | ||
78 | /* How to access the device? | 78 | /* How to access the device? |
79 | * On ARM, it'll be mmap'd directly with 32-bit wide accesses. | 79 | * On ARM, it'll be mmap'd directly with 32-bit wide accesses. |
80 | * On PPC, it's mmap'd and 16-bit wide. | 80 | * On PPC, it's mmap'd and 16-bit wide. |
81 | * Others use readb/writeb | 81 | * Others use readb/writeb |
82 | */ | 82 | */ |
83 | #if defined(__arm__) | 83 | #if defined(__arm__) |
84 | #define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) | 84 | #define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) |
@@ -172,7 +172,7 @@ struct DiskOnChip { | |||
172 | unsigned long totlen; | 172 | unsigned long totlen; |
173 | unsigned char ChipID; /* Type of DiskOnChip */ | 173 | unsigned char ChipID; /* Type of DiskOnChip */ |
174 | int ioreg; | 174 | int ioreg; |
175 | 175 | ||
176 | unsigned long mfr; /* Flash IDs - only one type of flash per device */ | 176 | unsigned long mfr; /* Flash IDs - only one type of flash per device */ |
177 | unsigned long id; | 177 | unsigned long id; |
178 | int chipshift; | 178 | int chipshift; |
@@ -180,10 +180,10 @@ struct DiskOnChip { | |||
180 | char pageadrlen; | 180 | char pageadrlen; |
181 | char interleave; /* Internal interleaving - Millennium Plus style */ | 181 | char interleave; /* Internal interleaving - Millennium Plus style */ |
182 | unsigned long erasesize; | 182 | unsigned long erasesize; |
183 | 183 | ||
184 | int curfloor; | 184 | int curfloor; |
185 | int curchip; | 185 | int curchip; |
186 | 186 | ||
187 | int numchips; | 187 | int numchips; |
188 | struct Nand *chips; | 188 | struct Nand *chips; |
189 | struct mtd_info *nextdoc; | 189 | struct mtd_info *nextdoc; |
diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h index 675776fa3e27..a293a3b78e05 100644 --- a/include/linux/mtd/flashchip.h +++ b/include/linux/mtd/flashchip.h | |||
@@ -1,12 +1,12 @@ | |||
1 | 1 | ||
2 | /* | 2 | /* |
3 | * struct flchip definition | 3 | * struct flchip definition |
4 | * | 4 | * |
5 | * Contains information about the location and state of a given flash device | 5 | * Contains information about the location and state of a given flash device |
6 | * | 6 | * |
7 | * (C) 2000 Red Hat. GPLd. | 7 | * (C) 2000 Red Hat. GPLd. |
8 | * | 8 | * |
9 | * $Id: flashchip.h,v 1.17 2005/03/14 18:27:15 bjd Exp $ | 9 | * $Id: flashchip.h,v 1.18 2005/11/07 11:14:54 gleixner Exp $ |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
@@ -15,11 +15,11 @@ | |||
15 | 15 | ||
16 | /* For spinlocks. sched.h includes spinlock.h from whichever directory it | 16 | /* For spinlocks. sched.h includes spinlock.h from whichever directory it |
17 | * happens to be in - so we don't have to care whether we're on 2.2, which | 17 | * happens to be in - so we don't have to care whether we're on 2.2, which |
18 | * has asm/spinlock.h, or 2.4, which has linux/spinlock.h | 18 | * has asm/spinlock.h, or 2.4, which has linux/spinlock.h |
19 | */ | 19 | */ |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | 21 | ||
22 | typedef enum { | 22 | typedef enum { |
23 | FL_READY, | 23 | FL_READY, |
24 | FL_STATUS, | 24 | FL_STATUS, |
25 | FL_CFI_QUERY, | 25 | FL_CFI_QUERY, |
@@ -45,7 +45,7 @@ typedef enum { | |||
45 | 45 | ||
46 | 46 | ||
47 | 47 | ||
48 | /* NOTE: confusingly, this can be used to refer to more than one chip at a time, | 48 | /* NOTE: confusingly, this can be used to refer to more than one chip at a time, |
49 | if they're interleaved. This can even refer to individual partitions on | 49 | if they're interleaved. This can even refer to individual partitions on |
50 | the same physical chip when present. */ | 50 | the same physical chip when present. */ |
51 | 51 | ||
diff --git a/include/linux/mtd/ftl.h b/include/linux/mtd/ftl.h index 3678459b4535..d99609113307 100644 --- a/include/linux/mtd/ftl.h +++ b/include/linux/mtd/ftl.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: ftl.h,v 1.6 2003/01/24 13:20:04 dwmw2 Exp $ | 2 | * $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $ |
3 | * | 3 | * |
4 | * Derived from (and probably identical to): | 4 | * Derived from (and probably identical to): |
5 | * ftl.h 1.7 1999/10/25 20:23:17 | 5 | * ftl.h 1.7 1999/10/25 20:23:17 |
6 | * | 6 | * |
@@ -12,7 +12,7 @@ | |||
12 | * Software distributed under the License is distributed on an "AS IS" | 12 | * Software distributed under the License is distributed on an "AS IS" |
13 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | 13 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
14 | * the License for the specific language governing rights and | 14 | * the License for the specific language governing rights and |
15 | * limitations under the License. | 15 | * limitations under the License. |
16 | * | 16 | * |
17 | * The initial developer of the original code is David A. Hinds | 17 | * The initial developer of the original code is David A. Hinds |
18 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | 18 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds |
diff --git a/include/linux/mtd/gen_probe.h b/include/linux/mtd/gen_probe.h index 3d7bdec14f97..256e7342ed1e 100644 --- a/include/linux/mtd/gen_probe.h +++ b/include/linux/mtd/gen_probe.h | |||
@@ -1,14 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * (C) 2001, 2001 Red Hat, Inc. | 2 | * (C) 2001, 2001 Red Hat, Inc. |
3 | * GPL'd | 3 | * GPL'd |
4 | * $Id: gen_probe.h,v 1.3 2004/10/20 22:10:33 dwmw2 Exp $ | 4 | * $Id: gen_probe.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $ |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #ifndef __LINUX_MTD_GEN_PROBE_H__ | 7 | #ifndef __LINUX_MTD_GEN_PROBE_H__ |
8 | #define __LINUX_MTD_GEN_PROBE_H__ | 8 | #define __LINUX_MTD_GEN_PROBE_H__ |
9 | 9 | ||
10 | #include <linux/mtd/flashchip.h> | 10 | #include <linux/mtd/flashchip.h> |
11 | #include <linux/mtd/map.h> | 11 | #include <linux/mtd/map.h> |
12 | #include <linux/mtd/cfi.h> | 12 | #include <linux/mtd/cfi.h> |
13 | #include <linux/bitops.h> | 13 | #include <linux/bitops.h> |
14 | 14 | ||
diff --git a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h index 2ba0f700ddbc..9006feb218b9 100644 --- a/include/linux/mtd/jedec.h +++ b/include/linux/mtd/jedec.h | |||
@@ -1,13 +1,13 @@ | |||
1 | 1 | ||
2 | /* JEDEC Flash Interface. | 2 | /* JEDEC Flash Interface. |
3 | * This is an older type of interface for self programming flash. It is | 3 | * This is an older type of interface for self programming flash. It is |
4 | * commonly use in older AMD chips and is obsolete compared with CFI. | 4 | * commonly use in older AMD chips and is obsolete compared with CFI. |
5 | * It is called JEDEC because the JEDEC association distributes the ID codes | 5 | * It is called JEDEC because the JEDEC association distributes the ID codes |
6 | * for the chips. | 6 | * for the chips. |
7 | * | 7 | * |
8 | * See the AMD flash databook for information on how to operate the interface. | 8 | * See the AMD flash databook for information on how to operate the interface. |
9 | * | 9 | * |
10 | * $Id: jedec.h,v 1.3 2003/05/21 11:51:01 dwmw2 Exp $ | 10 | * $Id: jedec.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $ |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef __LINUX_MTD_JEDEC_H__ | 13 | #ifndef __LINUX_MTD_JEDEC_H__ |
@@ -33,16 +33,16 @@ struct jedec_flash_chip | |||
33 | __u16 jedec; | 33 | __u16 jedec; |
34 | unsigned long size; | 34 | unsigned long size; |
35 | unsigned long sectorsize; | 35 | unsigned long sectorsize; |
36 | 36 | ||
37 | // *(__u8*)(base + (adder << addrshift)) = data << datashift | 37 | // *(__u8*)(base + (adder << addrshift)) = data << datashift |
38 | // Address size = size << addrshift | 38 | // Address size = size << addrshift |
39 | unsigned long base; // Byte 0 of the flash, will be unaligned | 39 | unsigned long base; // Byte 0 of the flash, will be unaligned |
40 | unsigned int datashift; // Useful for 32bit/16bit accesses | 40 | unsigned int datashift; // Useful for 32bit/16bit accesses |
41 | unsigned int addrshift; | 41 | unsigned int addrshift; |
42 | unsigned long offset; // linerized start. base==offset for unbanked, uninterleaved flash | 42 | unsigned long offset; // linerized start. base==offset for unbanked, uninterleaved flash |
43 | 43 | ||
44 | __u32 capabilities; | 44 | __u32 capabilities; |
45 | 45 | ||
46 | // These markers are filled in by the flash_chip_scan function | 46 | // These markers are filled in by the flash_chip_scan function |
47 | unsigned long start; | 47 | unsigned long start; |
48 | unsigned long length; | 48 | unsigned long length; |
@@ -51,16 +51,16 @@ struct jedec_flash_chip | |||
51 | struct jedec_private | 51 | struct jedec_private |
52 | { | 52 | { |
53 | unsigned long size; // Total size of all the devices | 53 | unsigned long size; // Total size of all the devices |
54 | 54 | ||
55 | /* Bank handling. If sum(bank_fill) == size then this is linear flash. | 55 | /* Bank handling. If sum(bank_fill) == size then this is linear flash. |
56 | Otherwise the mapping has holes in it. bank_fill may be used to | 56 | Otherwise the mapping has holes in it. bank_fill may be used to |
57 | find the holes, but in the common symetric case | 57 | find the holes, but in the common symetric case |
58 | bank_fill[0] == bank_fill[*], thus addresses may be computed | 58 | bank_fill[0] == bank_fill[*], thus addresses may be computed |
59 | mathmatically. bank_fill must be powers of two */ | 59 | mathmatically. bank_fill must be powers of two */ |
60 | unsigned is_banked; | 60 | unsigned is_banked; |
61 | unsigned long bank_fill[MAX_JEDEC_CHIPS]; | 61 | unsigned long bank_fill[MAX_JEDEC_CHIPS]; |
62 | 62 | ||
63 | struct jedec_flash_chip chips[MAX_JEDEC_CHIPS]; | 63 | struct jedec_flash_chip chips[MAX_JEDEC_CHIPS]; |
64 | }; | 64 | }; |
65 | 65 | ||
66 | #endif | 66 | #endif |
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index fc28841f3409..fedfbc8a287f 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h | |||
@@ -1,6 +1,6 @@ | |||
1 | 1 | ||
2 | /* Overhauled routines for dealing with different mmap regions of flash */ | 2 | /* Overhauled routines for dealing with different mmap regions of flash */ |
3 | /* $Id: map.h,v 1.52 2005/05/25 10:29:41 gleixner Exp $ */ | 3 | /* $Id: map.h,v 1.54 2005/11/07 11:14:54 gleixner Exp $ */ |
4 | 4 | ||
5 | #ifndef __LINUX_MTD_MAP_H__ | 5 | #ifndef __LINUX_MTD_MAP_H__ |
6 | #define __LINUX_MTD_MAP_H__ | 6 | #define __LINUX_MTD_MAP_H__ |
@@ -170,14 +170,14 @@ typedef union { | |||
170 | to a chip probe routine -- either JEDEC or CFI probe or both -- via | 170 | to a chip probe routine -- either JEDEC or CFI probe or both -- via |
171 | do_map_probe(). If a chip is recognised, the probe code will invoke the | 171 | do_map_probe(). If a chip is recognised, the probe code will invoke the |
172 | appropriate chip driver (if present) and return a struct mtd_info. | 172 | appropriate chip driver (if present) and return a struct mtd_info. |
173 | At which point, you fill in the mtd->module with your own module | 173 | At which point, you fill in the mtd->module with your own module |
174 | address, and register it with the MTD core code. Or you could partition | 174 | address, and register it with the MTD core code. Or you could partition |
175 | it and register the partitions instead, or keep it for your own private | 175 | it and register the partitions instead, or keep it for your own private |
176 | use; whatever. | 176 | use; whatever. |
177 | 177 | ||
178 | The mtd->priv field will point to the struct map_info, and any further | 178 | The mtd->priv field will point to the struct map_info, and any further |
179 | private data required by the chip driver is linked from the | 179 | private data required by the chip driver is linked from the |
180 | mtd->priv->fldrv_priv field. This allows the map driver to get at | 180 | mtd->priv->fldrv_priv field. This allows the map driver to get at |
181 | the destructor function map->fldrv_destroy() when it's tired | 181 | the destructor function map->fldrv_destroy() when it's tired |
182 | of living. | 182 | of living. |
183 | */ | 183 | */ |
@@ -214,7 +214,7 @@ struct map_info { | |||
214 | If there is no cache to care about this can be set to NULL. */ | 214 | If there is no cache to care about this can be set to NULL. */ |
215 | void (*inval_cache)(struct map_info *, unsigned long, ssize_t); | 215 | void (*inval_cache)(struct map_info *, unsigned long, ssize_t); |
216 | 216 | ||
217 | /* set_vpp() must handle being reentered -- enable, enable, disable | 217 | /* set_vpp() must handle being reentered -- enable, enable, disable |
218 | must leave it enabled. */ | 218 | must leave it enabled. */ |
219 | void (*set_vpp)(struct map_info *, int); | 219 | void (*set_vpp)(struct map_info *, int); |
220 | 220 | ||
@@ -353,7 +353,7 @@ static inline map_word map_word_ff(struct map_info *map) | |||
353 | { | 353 | { |
354 | map_word r; | 354 | map_word r; |
355 | int i; | 355 | int i; |
356 | 356 | ||
357 | if (map_bankwidth(map) < MAP_FF_LIMIT) { | 357 | if (map_bankwidth(map) < MAP_FF_LIMIT) { |
358 | int bw = 8 * map_bankwidth(map); | 358 | int bw = 8 * map_bankwidth(map); |
359 | r.x[0] = (1 << bw) - 1; | 359 | r.x[0] = (1 << bw) - 1; |
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index c50c3f3927d9..e95d0463a3e5 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mtd.h,v 1.59 2005/04/11 10:19:02 gleixner Exp $ | 2 | * $Id: mtd.h,v 1.61 2005/11/07 11:14:54 gleixner Exp $ |
3 | * | 3 | * |
4 | * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al. | 4 | * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al. |
5 | * | 5 | * |
@@ -72,7 +72,17 @@ struct mtd_info { | |||
72 | u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) | 72 | u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) |
73 | u_int32_t ecctype; | 73 | u_int32_t ecctype; |
74 | u_int32_t eccsize; | 74 | u_int32_t eccsize; |
75 | 75 | ||
76 | /* | ||
77 | * Reuse some of the above unused fields in the case of NOR flash | ||
78 | * with configurable programming regions to avoid modifying the | ||
79 | * user visible structure layout/size. Only valid when the | ||
80 | * MTD_PROGRAM_REGIONS flag is set. | ||
81 | * (Maybe we should have an union for those?) | ||
82 | */ | ||
83 | #define MTD_PROGREGION_SIZE(mtd) (mtd)->oobblock | ||
84 | #define MTD_PROGREGION_CTRLMODE_VALID(mtd) (mtd)->oobsize | ||
85 | #define MTD_PROGREGION_CTRLMODE_INVALID(mtd) (mtd)->ecctype | ||
76 | 86 | ||
77 | // Kernel-only stuff starts here. | 87 | // Kernel-only stuff starts here. |
78 | char *name; | 88 | char *name; |
@@ -80,13 +90,13 @@ struct mtd_info { | |||
80 | 90 | ||
81 | // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) | 91 | // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) |
82 | struct nand_oobinfo oobinfo; | 92 | struct nand_oobinfo oobinfo; |
83 | u_int32_t oobavail; // Number of bytes in OOB area available for fs | 93 | u_int32_t oobavail; // Number of bytes in OOB area available for fs |
84 | 94 | ||
85 | /* Data for variable erase regions. If numeraseregions is zero, | 95 | /* Data for variable erase regions. If numeraseregions is zero, |
86 | * it means that the whole device has erasesize as given above. | 96 | * it means that the whole device has erasesize as given above. |
87 | */ | 97 | */ |
88 | int numeraseregions; | 98 | int numeraseregions; |
89 | struct mtd_erase_region_info *eraseregions; | 99 | struct mtd_erase_region_info *eraseregions; |
90 | 100 | ||
91 | /* This really shouldn't be here. It can go away in 2.5 */ | 101 | /* This really shouldn't be here. It can go away in 2.5 */ |
92 | u_int32_t bank_size; | 102 | u_int32_t bank_size; |
@@ -109,10 +119,10 @@ struct mtd_info { | |||
109 | int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); | 119 | int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); |
110 | int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); | 120 | int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); |
111 | 121 | ||
112 | /* | 122 | /* |
113 | * Methods to access the protection register area, present in some | 123 | * Methods to access the protection register area, present in some |
114 | * flash devices. The user data is one time programmable but the | 124 | * flash devices. The user data is one time programmable but the |
115 | * factory data is read only. | 125 | * factory data is read only. |
116 | */ | 126 | */ |
117 | int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); | 127 | int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); |
118 | int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); | 128 | int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); |
@@ -123,14 +133,14 @@ struct mtd_info { | |||
123 | 133 | ||
124 | /* kvec-based read/write methods. We need these especially for NAND flash, | 134 | /* kvec-based read/write methods. We need these especially for NAND flash, |
125 | with its limited number of write cycles per erase. | 135 | with its limited number of write cycles per erase. |
126 | NB: The 'count' parameter is the number of _vectors_, each of | 136 | NB: The 'count' parameter is the number of _vectors_, each of |
127 | which contains an (ofs, len) tuple. | 137 | which contains an (ofs, len) tuple. |
128 | */ | 138 | */ |
129 | int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen); | 139 | int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen); |
130 | int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, | 140 | int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, |
131 | size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); | 141 | size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); |
132 | int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); | 142 | int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); |
133 | int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, | 143 | int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, |
134 | size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); | 144 | size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); |
135 | 145 | ||
136 | /* Sync */ | 146 | /* Sync */ |
@@ -194,7 +204,7 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, | |||
194 | #define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args) | 204 | #define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args) |
195 | #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) | 205 | #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) |
196 | #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) | 206 | #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) |
197 | #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) | 207 | #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) |
198 | 208 | ||
199 | 209 | ||
200 | #ifdef CONFIG_MTD_PARTITIONS | 210 | #ifdef CONFIG_MTD_PARTITIONS |
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 9b5b76217584..da5e67b3fc70 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * Steven J. Hill <sjhill@realitydiluted.com> | 5 | * Steven J. Hill <sjhill@realitydiluted.com> |
6 | * Thomas Gleixner <tglx@linutronix.de> | 6 | * Thomas Gleixner <tglx@linutronix.de> |
7 | * | 7 | * |
8 | * $Id: nand.h,v 1.73 2005/05/31 19:39:17 gleixner Exp $ | 8 | * $Id: nand.h,v 1.74 2005/09/15 13:58:50 vwool Exp $ |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
@@ -24,7 +24,7 @@ | |||
24 | * bat later if I did something naughty. | 24 | * bat later if I did something naughty. |
25 | * 10-11-2000 SJH Added private NAND flash structure for driver | 25 | * 10-11-2000 SJH Added private NAND flash structure for driver |
26 | * 10-24-2000 SJH Added prototype for 'nand_scan' function | 26 | * 10-24-2000 SJH Added prototype for 'nand_scan' function |
27 | * 10-29-2001 TG changed nand_chip structure to support | 27 | * 10-29-2001 TG changed nand_chip structure to support |
28 | * hardwarespecific function for accessing control lines | 28 | * hardwarespecific function for accessing control lines |
29 | * 02-21-2002 TG added support for different read/write adress and | 29 | * 02-21-2002 TG added support for different read/write adress and |
30 | * ready/busy line access function | 30 | * ready/busy line access function |
@@ -36,21 +36,21 @@ | |||
36 | * CONFIG_MTD_NAND_ECC_JFFS2 is not set | 36 | * CONFIG_MTD_NAND_ECC_JFFS2 is not set |
37 | * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC | 37 | * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC |
38 | * | 38 | * |
39 | * 08-29-2002 tglx nand_chip structure: data_poi for selecting | 39 | * 08-29-2002 tglx nand_chip structure: data_poi for selecting |
40 | * internal / fs-driver buffer | 40 | * internal / fs-driver buffer |
41 | * support for 6byte/512byte hardware ECC | 41 | * support for 6byte/512byte hardware ECC |
42 | * read_ecc, write_ecc extended for different oob-layout | 42 | * read_ecc, write_ecc extended for different oob-layout |
43 | * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB, | 43 | * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB, |
44 | * NAND_YAFFS_OOB | 44 | * NAND_YAFFS_OOB |
45 | * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL | 45 | * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL |
46 | * Split manufacturer and device ID structures | 46 | * Split manufacturer and device ID structures |
47 | * | 47 | * |
48 | * 02-08-2004 tglx added option field to nand structure for chip anomalities | 48 | * 02-08-2004 tglx added option field to nand structure for chip anomalities |
49 | * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id | 49 | * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id |
50 | * update of nand_chip structure description | 50 | * update of nand_chip structure description |
51 | * 01-17-2005 dmarlin added extended commands for AG-AND device and added option | 51 | * 01-17-2005 dmarlin added extended commands for AG-AND device and added option |
52 | * for BBT_AUTO_REFRESH. | 52 | * for BBT_AUTO_REFRESH. |
53 | * 01-20-2005 dmarlin added optional pointer to hardware specific callback for | 53 | * 01-20-2005 dmarlin added optional pointer to hardware specific callback for |
54 | * extra error status checks. | 54 | * extra error status checks. |
55 | */ | 55 | */ |
56 | #ifndef __LINUX_MTD_NAND_H | 56 | #ifndef __LINUX_MTD_NAND_H |
@@ -120,8 +120,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ | |||
120 | #define NAND_CMD_CACHEDPROG 0x15 | 120 | #define NAND_CMD_CACHEDPROG 0x15 |
121 | 121 | ||
122 | /* Extended commands for AG-AND device */ | 122 | /* Extended commands for AG-AND device */ |
123 | /* | 123 | /* |
124 | * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but | 124 | * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but |
125 | * there is no way to distinguish that from NAND_CMD_READ0 | 125 | * there is no way to distinguish that from NAND_CMD_READ0 |
126 | * until the remaining sequence of commands has been completed | 126 | * until the remaining sequence of commands has been completed |
127 | * so add a high order bit and mask it off in the command. | 127 | * so add a high order bit and mask it off in the command. |
@@ -145,7 +145,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ | |||
145 | #define NAND_STATUS_READY 0x40 | 145 | #define NAND_STATUS_READY 0x40 |
146 | #define NAND_STATUS_WP 0x80 | 146 | #define NAND_STATUS_WP 0x80 |
147 | 147 | ||
148 | /* | 148 | /* |
149 | * Constants for ECC_MODES | 149 | * Constants for ECC_MODES |
150 | */ | 150 | */ |
151 | 151 | ||
@@ -191,12 +191,12 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ | |||
191 | #define NAND_CACHEPRG 0x00000008 | 191 | #define NAND_CACHEPRG 0x00000008 |
192 | /* Chip has copy back function */ | 192 | /* Chip has copy back function */ |
193 | #define NAND_COPYBACK 0x00000010 | 193 | #define NAND_COPYBACK 0x00000010 |
194 | /* AND Chip which has 4 banks and a confusing page / block | 194 | /* AND Chip which has 4 banks and a confusing page / block |
195 | * assignment. See Renesas datasheet for further information */ | 195 | * assignment. See Renesas datasheet for further information */ |
196 | #define NAND_IS_AND 0x00000020 | 196 | #define NAND_IS_AND 0x00000020 |
197 | /* Chip has a array of 4 pages which can be read without | 197 | /* Chip has a array of 4 pages which can be read without |
198 | * additional ready /busy waits */ | 198 | * additional ready /busy waits */ |
199 | #define NAND_4PAGE_ARRAY 0x00000040 | 199 | #define NAND_4PAGE_ARRAY 0x00000040 |
200 | /* Chip requires that BBT is periodically rewritten to prevent | 200 | /* Chip requires that BBT is periodically rewritten to prevent |
201 | * bits from adjacent blocks from 'leaking' in altering data. | 201 | * bits from adjacent blocks from 'leaking' in altering data. |
202 | * This happens with the Renesas AG-AND chips, possibly others. */ | 202 | * This happens with the Renesas AG-AND chips, possibly others. */ |
@@ -219,8 +219,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ | |||
219 | /* Use a flash based bad block table. This option is passed to the | 219 | /* Use a flash based bad block table. This option is passed to the |
220 | * default bad block table function. */ | 220 | * default bad block table function. */ |
221 | #define NAND_USE_FLASH_BBT 0x00010000 | 221 | #define NAND_USE_FLASH_BBT 0x00010000 |
222 | /* The hw ecc generator provides a syndrome instead a ecc value on read | 222 | /* The hw ecc generator provides a syndrome instead a ecc value on read |
223 | * This can only work if we have the ecc bytes directly behind the | 223 | * This can only work if we have the ecc bytes directly behind the |
224 | * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ | 224 | * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ |
225 | #define NAND_HWECC_SYNDROME 0x00020000 | 225 | #define NAND_HWECC_SYNDROME 0x00020000 |
226 | /* This option skips the bbt scan during initialization. */ | 226 | /* This option skips the bbt scan during initialization. */ |
@@ -244,6 +244,7 @@ typedef enum { | |||
244 | FL_ERASING, | 244 | FL_ERASING, |
245 | FL_SYNCING, | 245 | FL_SYNCING, |
246 | FL_CACHEDPRG, | 246 | FL_CACHEDPRG, |
247 | FL_PM_SUSPENDED, | ||
247 | } nand_state_t; | 248 | } nand_state_t; |
248 | 249 | ||
249 | /* Keep gcc happy */ | 250 | /* Keep gcc happy */ |
@@ -251,7 +252,7 @@ struct nand_chip; | |||
251 | 252 | ||
252 | /** | 253 | /** |
253 | * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices | 254 | * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices |
254 | * @lock: protection lock | 255 | * @lock: protection lock |
255 | * @active: the mtd device which holds the controller currently | 256 | * @active: the mtd device which holds the controller currently |
256 | * @wq: wait queue to sleep on if a NAND operation is in progress | 257 | * @wq: wait queue to sleep on if a NAND operation is in progress |
257 | * used instead of the per chip wait queue when a hw controller is available | 258 | * used instead of the per chip wait queue when a hw controller is available |
@@ -264,8 +265,8 @@ struct nand_hw_control { | |||
264 | 265 | ||
265 | /** | 266 | /** |
266 | * struct nand_chip - NAND Private Flash Chip Data | 267 | * struct nand_chip - NAND Private Flash Chip Data |
267 | * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device | 268 | * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device |
268 | * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device | 269 | * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device |
269 | * @read_byte: [REPLACEABLE] read one byte from the chip | 270 | * @read_byte: [REPLACEABLE] read one byte from the chip |
270 | * @write_byte: [REPLACEABLE] write one byte to the chip | 271 | * @write_byte: [REPLACEABLE] write one byte to the chip |
271 | * @read_word: [REPLACEABLE] read one word from the chip | 272 | * @read_word: [REPLACEABLE] read one word from the chip |
@@ -288,7 +289,7 @@ struct nand_hw_control { | |||
288 | * be provided if a hardware ECC is available | 289 | * be provided if a hardware ECC is available |
289 | * @erase_cmd: [INTERN] erase command write function, selectable due to AND support | 290 | * @erase_cmd: [INTERN] erase command write function, selectable due to AND support |
290 | * @scan_bbt: [REPLACEABLE] function to scan bad block table | 291 | * @scan_bbt: [REPLACEABLE] function to scan bad block table |
291 | * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines | 292 | * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines |
292 | * @eccsize: [INTERN] databytes used per ecc-calculation | 293 | * @eccsize: [INTERN] databytes used per ecc-calculation |
293 | * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step | 294 | * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step |
294 | * @eccsteps: [INTERN] number of ecc calculation steps per page | 295 | * @eccsteps: [INTERN] number of ecc calculation steps per page |
@@ -300,7 +301,7 @@ struct nand_hw_control { | |||
300 | * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock | 301 | * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock |
301 | * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry | 302 | * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry |
302 | * @chip_shift: [INTERN] number of address bits in one chip | 303 | * @chip_shift: [INTERN] number of address bits in one chip |
303 | * @data_buf: [INTERN] internal buffer for one page + oob | 304 | * @data_buf: [INTERN] internal buffer for one page + oob |
304 | * @oob_buf: [INTERN] oob buffer for one eraseblock | 305 | * @oob_buf: [INTERN] oob buffer for one eraseblock |
305 | * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized | 306 | * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized |
306 | * @data_poi: [INTERN] pointer to a data buffer | 307 | * @data_poi: [INTERN] pointer to a data buffer |
@@ -315,22 +316,22 @@ struct nand_hw_control { | |||
315 | * @bbt: [INTERN] bad block table pointer | 316 | * @bbt: [INTERN] bad block table pointer |
316 | * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup | 317 | * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup |
317 | * @bbt_md: [REPLACEABLE] bad block table mirror descriptor | 318 | * @bbt_md: [REPLACEABLE] bad block table mirror descriptor |
318 | * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan | 319 | * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan |
319 | * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices | 320 | * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices |
320 | * @priv: [OPTIONAL] pointer to private chip date | 321 | * @priv: [OPTIONAL] pointer to private chip date |
321 | * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks | 322 | * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks |
322 | * (determine if errors are correctable) | 323 | * (determine if errors are correctable) |
323 | */ | 324 | */ |
324 | 325 | ||
325 | struct nand_chip { | 326 | struct nand_chip { |
326 | void __iomem *IO_ADDR_R; | 327 | void __iomem *IO_ADDR_R; |
327 | void __iomem *IO_ADDR_W; | 328 | void __iomem *IO_ADDR_W; |
328 | 329 | ||
329 | u_char (*read_byte)(struct mtd_info *mtd); | 330 | u_char (*read_byte)(struct mtd_info *mtd); |
330 | void (*write_byte)(struct mtd_info *mtd, u_char byte); | 331 | void (*write_byte)(struct mtd_info *mtd, u_char byte); |
331 | u16 (*read_word)(struct mtd_info *mtd); | 332 | u16 (*read_word)(struct mtd_info *mtd); |
332 | void (*write_word)(struct mtd_info *mtd, u16 word); | 333 | void (*write_word)(struct mtd_info *mtd, u16 word); |
333 | 334 | ||
334 | void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); | 335 | void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); |
335 | void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); | 336 | void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); |
336 | int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); | 337 | int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); |
@@ -395,7 +396,7 @@ struct nand_chip { | |||
395 | * @name: Identify the device type | 396 | * @name: Identify the device type |
396 | * @id: device ID code | 397 | * @id: device ID code |
397 | * @pagesize: Pagesize in bytes. Either 256 or 512 or 0 | 398 | * @pagesize: Pagesize in bytes. Either 256 or 512 or 0 |
398 | * If the pagesize is 0, then the real pagesize | 399 | * If the pagesize is 0, then the real pagesize |
399 | * and the eraseize are determined from the | 400 | * and the eraseize are determined from the |
400 | * extended id bytes in the chip | 401 | * extended id bytes in the chip |
401 | * @erasesize: Size of an erase block in the flash device. | 402 | * @erasesize: Size of an erase block in the flash device. |
@@ -424,7 +425,7 @@ struct nand_manufacturers { | |||
424 | extern struct nand_flash_dev nand_flash_ids[]; | 425 | extern struct nand_flash_dev nand_flash_ids[]; |
425 | extern struct nand_manufacturers nand_manuf_ids[]; | 426 | extern struct nand_manufacturers nand_manuf_ids[]; |
426 | 427 | ||
427 | /** | 428 | /** |
428 | * struct nand_bbt_descr - bad block table descriptor | 429 | * struct nand_bbt_descr - bad block table descriptor |
429 | * @options: options for this descriptor | 430 | * @options: options for this descriptor |
430 | * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE | 431 | * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE |
@@ -435,14 +436,14 @@ extern struct nand_manufacturers nand_manuf_ids[]; | |||
435 | * @version: version read from the bbt page during scan | 436 | * @version: version read from the bbt page during scan |
436 | * @len: length of the pattern, if 0 no pattern check is performed | 437 | * @len: length of the pattern, if 0 no pattern check is performed |
437 | * @maxblocks: maximum number of blocks to search for a bbt. This number of | 438 | * @maxblocks: maximum number of blocks to search for a bbt. This number of |
438 | * blocks is reserved at the end of the device where the tables are | 439 | * blocks is reserved at the end of the device where the tables are |
439 | * written. | 440 | * written. |
440 | * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than | 441 | * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than |
441 | * bad) block in the stored bbt | 442 | * bad) block in the stored bbt |
442 | * @pattern: pattern to identify bad block table or factory marked good / | 443 | * @pattern: pattern to identify bad block table or factory marked good / |
443 | * bad blocks, can be NULL, if len = 0 | 444 | * bad blocks, can be NULL, if len = 0 |
444 | * | 445 | * |
445 | * Descriptor for the bad block table marker and the descriptor for the | 446 | * Descriptor for the bad block table marker and the descriptor for the |
446 | * pattern which identifies good and bad blocks. The assumption is made | 447 | * pattern which identifies good and bad blocks. The assumption is made |
447 | * that the pattern and the version count are always located in the oob area | 448 | * that the pattern and the version count are always located in the oob area |
448 | * of the first block. | 449 | * of the first block. |
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h new file mode 100644 index 000000000000..f1fd4215686a --- /dev/null +++ b/include/linux/mtd/onenand.h | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * linux/include/linux/mtd/onenand.h | ||
3 | * | ||
4 | * Copyright (C) 2005 Samsung Electronics | ||
5 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
6 | * | ||
7 | * 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 | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __LINUX_MTD_ONENAND_H | ||
13 | #define __LINUX_MTD_ONENAND_H | ||
14 | |||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/mtd/onenand_regs.h> | ||
17 | #include <linux/mtd/bbm.h> | ||
18 | |||
19 | #define MAX_BUFFERRAM 2 | ||
20 | #define MAX_ONENAND_PAGESIZE (2048 + 64) | ||
21 | |||
22 | /* Scan and identify a OneNAND device */ | ||
23 | extern int onenand_scan(struct mtd_info *mtd, int max_chips); | ||
24 | /* Free resources held by the OneNAND device */ | ||
25 | extern void onenand_release(struct mtd_info *mtd); | ||
26 | |||
27 | /** | ||
28 | * onenand_state_t - chip states | ||
29 | * Enumeration for OneNAND flash chip state | ||
30 | */ | ||
31 | typedef enum { | ||
32 | FL_READY, | ||
33 | FL_READING, | ||
34 | FL_WRITING, | ||
35 | FL_ERASING, | ||
36 | FL_SYNCING, | ||
37 | FL_UNLOCKING, | ||
38 | FL_LOCKING, | ||
39 | FL_PM_SUSPENDED, | ||
40 | } onenand_state_t; | ||
41 | |||
42 | /** | ||
43 | * struct onenand_bufferram - OneNAND BufferRAM Data | ||
44 | * @param block block address in BufferRAM | ||
45 | * @param page page address in BufferRAM | ||
46 | * @param valid valid flag | ||
47 | */ | ||
48 | struct onenand_bufferram { | ||
49 | int block; | ||
50 | int page; | ||
51 | int valid; | ||
52 | }; | ||
53 | |||
54 | /** | ||
55 | * struct onenand_chip - OneNAND Private Flash Chip Data | ||
56 | * @param base [BOARDSPECIFIC] address to access OneNAND | ||
57 | * @param chipsize [INTERN] the size of one chip for multichip arrays | ||
58 | * @param device_id [INTERN] device ID | ||
59 | * @param verstion_id [INTERN] version ID | ||
60 | * @param options [BOARDSPECIFIC] various chip options. They can partly be set to inform onenand_scan about | ||
61 | * @param erase_shift [INTERN] number of address bits in a block | ||
62 | * @param page_shift [INTERN] number of address bits in a page | ||
63 | * @param ppb_shift [INTERN] number of address bits in a pages per block | ||
64 | * @param page_mask [INTERN] a page per block mask | ||
65 | * @param bufferam_index [INTERN] BufferRAM index | ||
66 | * @param bufferam [INTERN] BufferRAM info | ||
67 | * @param readw [REPLACEABLE] hardware specific function for read short | ||
68 | * @param writew [REPLACEABLE] hardware specific function for write short | ||
69 | * @param command [REPLACEABLE] hardware specific function for writing commands to the chip | ||
70 | * @param wait [REPLACEABLE] hardware specific function for wait on ready | ||
71 | * @param read_bufferram [REPLACEABLE] hardware specific function for BufferRAM Area | ||
72 | * @param write_bufferram [REPLACEABLE] hardware specific function for BufferRAM Area | ||
73 | * @param read_word [REPLACEABLE] hardware specific function for read register of OneNAND | ||
74 | * @param write_word [REPLACEABLE] hardware specific function for write register of OneNAND | ||
75 | * @param scan_bbt [REPLACEALBE] hardware specific function for scaning Bad block Table | ||
76 | * @param chip_lock [INTERN] spinlock used to protect access to this structure and the chip | ||
77 | * @param wq [INTERN] wait queue to sleep on if a OneNAND operation is in progress | ||
78 | * @param state [INTERN] the current state of the OneNAND device | ||
79 | * @param autooob [REPLACEABLE] the default (auto)placement scheme | ||
80 | * @param bbm [REPLACEABLE] pointer to Bad Block Management | ||
81 | * @param priv [OPTIONAL] pointer to private chip date | ||
82 | */ | ||
83 | struct onenand_chip { | ||
84 | void __iomem *base; | ||
85 | unsigned int chipsize; | ||
86 | unsigned int device_id; | ||
87 | unsigned int density_mask; | ||
88 | unsigned int options; | ||
89 | |||
90 | unsigned int erase_shift; | ||
91 | unsigned int page_shift; | ||
92 | unsigned int ppb_shift; /* Pages per block shift */ | ||
93 | unsigned int page_mask; | ||
94 | |||
95 | unsigned int bufferram_index; | ||
96 | struct onenand_bufferram bufferram[MAX_BUFFERRAM]; | ||
97 | |||
98 | int (*command)(struct mtd_info *mtd, int cmd, loff_t address, size_t len); | ||
99 | int (*wait)(struct mtd_info *mtd, int state); | ||
100 | int (*read_bufferram)(struct mtd_info *mtd, int area, | ||
101 | unsigned char *buffer, int offset, size_t count); | ||
102 | int (*write_bufferram)(struct mtd_info *mtd, int area, | ||
103 | const unsigned char *buffer, int offset, size_t count); | ||
104 | unsigned short (*read_word)(void __iomem *addr); | ||
105 | void (*write_word)(unsigned short value, void __iomem *addr); | ||
106 | void (*mmcontrol)(struct mtd_info *mtd, int sync_read); | ||
107 | int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); | ||
108 | int (*scan_bbt)(struct mtd_info *mtd); | ||
109 | |||
110 | spinlock_t chip_lock; | ||
111 | wait_queue_head_t wq; | ||
112 | onenand_state_t state; | ||
113 | |||
114 | struct nand_oobinfo *autooob; | ||
115 | |||
116 | void *bbm; | ||
117 | |||
118 | void *priv; | ||
119 | }; | ||
120 | |||
121 | /* | ||
122 | * Helper macros | ||
123 | */ | ||
124 | #define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) | ||
125 | #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) | ||
126 | #define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) | ||
127 | |||
128 | #define ONENAND_GET_SYS_CFG1(this) \ | ||
129 | (this->read_word(this->base + ONENAND_REG_SYS_CFG1)) | ||
130 | #define ONENAND_SET_SYS_CFG1(v, this) \ | ||
131 | (this->write_word(v, this->base + ONENAND_REG_SYS_CFG1)) | ||
132 | |||
133 | /* | ||
134 | * Options bits | ||
135 | */ | ||
136 | #define ONENAND_CONT_LOCK (0x0001) | ||
137 | |||
138 | |||
139 | /* | ||
140 | * OneNAND Flash Manufacturer ID Codes | ||
141 | */ | ||
142 | #define ONENAND_MFR_SAMSUNG 0xec | ||
143 | #define ONENAND_MFR_UNKNOWN 0x00 | ||
144 | |||
145 | /** | ||
146 | * struct nand_manufacturers - NAND Flash Manufacturer ID Structure | ||
147 | * @param name: Manufacturer name | ||
148 | * @param id: manufacturer ID code of device. | ||
149 | */ | ||
150 | struct onenand_manufacturers { | ||
151 | int id; | ||
152 | char *name; | ||
153 | }; | ||
154 | |||
155 | #endif /* __LINUX_MTD_ONENAND_H */ | ||
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h new file mode 100644 index 000000000000..d7832ef8ed63 --- /dev/null +++ b/include/linux/mtd/onenand_regs.h | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * linux/include/linux/mtd/onenand_regs.h | ||
3 | * | ||
4 | * OneNAND Register header file | ||
5 | * | ||
6 | * Copyright (C) 2005 Samsung Electronics | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __ONENAND_REG_H | ||
14 | #define __ONENAND_REG_H | ||
15 | |||
16 | /* Memory Address Map Translation (Word order) */ | ||
17 | #define ONENAND_MEMORY_MAP(x) ((x) << 1) | ||
18 | |||
19 | /* | ||
20 | * External BufferRAM area | ||
21 | */ | ||
22 | #define ONENAND_BOOTRAM ONENAND_MEMORY_MAP(0x0000) | ||
23 | #define ONENAND_DATARAM ONENAND_MEMORY_MAP(0x0200) | ||
24 | #define ONENAND_SPARERAM ONENAND_MEMORY_MAP(0x8010) | ||
25 | |||
26 | /* | ||
27 | * OneNAND Registers | ||
28 | */ | ||
29 | #define ONENAND_REG_MANUFACTURER_ID ONENAND_MEMORY_MAP(0xF000) | ||
30 | #define ONENAND_REG_DEVICE_ID ONENAND_MEMORY_MAP(0xF001) | ||
31 | #define ONENAND_REG_VERSION_ID ONENAND_MEMORY_MAP(0xF002) | ||
32 | #define ONENAND_REG_DATA_BUFFER_SIZE ONENAND_MEMORY_MAP(0xF003) | ||
33 | #define ONENAND_REG_BOOT_BUFFER_SIZE ONENAND_MEMORY_MAP(0xF004) | ||
34 | #define ONENAND_REG_NUM_BUFFERS ONENAND_MEMORY_MAP(0xF005) | ||
35 | #define ONENAND_REG_TECHNOLOGY ONENAND_MEMORY_MAP(0xF006) | ||
36 | |||
37 | #define ONENAND_REG_START_ADDRESS1 ONENAND_MEMORY_MAP(0xF100) | ||
38 | #define ONENAND_REG_START_ADDRESS2 ONENAND_MEMORY_MAP(0xF101) | ||
39 | #define ONENAND_REG_START_ADDRESS3 ONENAND_MEMORY_MAP(0xF102) | ||
40 | #define ONENAND_REG_START_ADDRESS4 ONENAND_MEMORY_MAP(0xF103) | ||
41 | #define ONENAND_REG_START_ADDRESS5 ONENAND_MEMORY_MAP(0xF104) | ||
42 | #define ONENAND_REG_START_ADDRESS6 ONENAND_MEMORY_MAP(0xF105) | ||
43 | #define ONENAND_REG_START_ADDRESS7 ONENAND_MEMORY_MAP(0xF106) | ||
44 | #define ONENAND_REG_START_ADDRESS8 ONENAND_MEMORY_MAP(0xF107) | ||
45 | |||
46 | #define ONENAND_REG_START_BUFFER ONENAND_MEMORY_MAP(0xF200) | ||
47 | #define ONENAND_REG_COMMAND ONENAND_MEMORY_MAP(0xF220) | ||
48 | #define ONENAND_REG_SYS_CFG1 ONENAND_MEMORY_MAP(0xF221) | ||
49 | #define ONENAND_REG_SYS_CFG2 ONENAND_MEMORY_MAP(0xF222) | ||
50 | #define ONENAND_REG_CTRL_STATUS ONENAND_MEMORY_MAP(0xF240) | ||
51 | #define ONENAND_REG_INTERRUPT ONENAND_MEMORY_MAP(0xF241) | ||
52 | #define ONENAND_REG_START_BLOCK_ADDRESS ONENAND_MEMORY_MAP(0xF24C) | ||
53 | #define ONENAND_REG_END_BLOCK_ADDRESS ONENAND_MEMORY_MAP(0xF24D) | ||
54 | #define ONENAND_REG_WP_STATUS ONENAND_MEMORY_MAP(0xF24E) | ||
55 | |||
56 | #define ONENAND_REG_ECC_STATUS ONENAND_MEMORY_MAP(0xFF00) | ||
57 | #define ONENAND_REG_ECC_M0 ONENAND_MEMORY_MAP(0xFF01) | ||
58 | #define ONENAND_REG_ECC_S0 ONENAND_MEMORY_MAP(0xFF02) | ||
59 | #define ONENAND_REG_ECC_M1 ONENAND_MEMORY_MAP(0xFF03) | ||
60 | #define ONENAND_REG_ECC_S1 ONENAND_MEMORY_MAP(0xFF04) | ||
61 | #define ONENAND_REG_ECC_M2 ONENAND_MEMORY_MAP(0xFF05) | ||
62 | #define ONENAND_REG_ECC_S2 ONENAND_MEMORY_MAP(0xFF06) | ||
63 | #define ONENAND_REG_ECC_M3 ONENAND_MEMORY_MAP(0xFF07) | ||
64 | #define ONENAND_REG_ECC_S3 ONENAND_MEMORY_MAP(0xFF08) | ||
65 | |||
66 | /* | ||
67 | * Device ID Register F001h (R) | ||
68 | */ | ||
69 | #define ONENAND_DEVICE_DENSITY_SHIFT (4) | ||
70 | #define ONENAND_DEVICE_IS_DDP (1 << 3) | ||
71 | #define ONENAND_DEVICE_IS_DEMUX (1 << 2) | ||
72 | #define ONENAND_DEVICE_VCC_MASK (0x3) | ||
73 | |||
74 | #define ONENAND_DEVICE_DENSITY_512Mb (0x002) | ||
75 | |||
76 | /* | ||
77 | * Version ID Register F002h (R) | ||
78 | */ | ||
79 | #define ONENAND_VERSION_PROCESS_SHIFT (8) | ||
80 | |||
81 | /* | ||
82 | * Start Address 1 F100h (R/W) | ||
83 | */ | ||
84 | #define ONENAND_DDP_SHIFT (15) | ||
85 | |||
86 | /* | ||
87 | * Start Address 8 F107h (R/W) | ||
88 | */ | ||
89 | #define ONENAND_FPA_MASK (0x3f) | ||
90 | #define ONENAND_FPA_SHIFT (2) | ||
91 | #define ONENAND_FSA_MASK (0x03) | ||
92 | |||
93 | /* | ||
94 | * Start Buffer Register F200h (R/W) | ||
95 | */ | ||
96 | #define ONENAND_BSA_MASK (0x03) | ||
97 | #define ONENAND_BSA_SHIFT (8) | ||
98 | #define ONENAND_BSA_BOOTRAM (0 << 2) | ||
99 | #define ONENAND_BSA_DATARAM0 (2 << 2) | ||
100 | #define ONENAND_BSA_DATARAM1 (3 << 2) | ||
101 | #define ONENAND_BSC_MASK (0x03) | ||
102 | |||
103 | /* | ||
104 | * Command Register F220h (R/W) | ||
105 | */ | ||
106 | #define ONENAND_CMD_READ (0x00) | ||
107 | #define ONENAND_CMD_READOOB (0x13) | ||
108 | #define ONENAND_CMD_PROG (0x80) | ||
109 | #define ONENAND_CMD_PROGOOB (0x1A) | ||
110 | #define ONENAND_CMD_UNLOCK (0x23) | ||
111 | #define ONENAND_CMD_LOCK (0x2A) | ||
112 | #define ONENAND_CMD_LOCK_TIGHT (0x2C) | ||
113 | #define ONENAND_CMD_ERASE (0x94) | ||
114 | #define ONENAND_CMD_RESET (0xF0) | ||
115 | #define ONENAND_CMD_READID (0x90) | ||
116 | |||
117 | /* NOTE: Those are not *REAL* commands */ | ||
118 | #define ONENAND_CMD_BUFFERRAM (0x1978) | ||
119 | |||
120 | /* | ||
121 | * System Configuration 1 Register F221h (R, R/W) | ||
122 | */ | ||
123 | #define ONENAND_SYS_CFG1_SYNC_READ (1 << 15) | ||
124 | #define ONENAND_SYS_CFG1_BRL_7 (7 << 12) | ||
125 | #define ONENAND_SYS_CFG1_BRL_6 (6 << 12) | ||
126 | #define ONENAND_SYS_CFG1_BRL_5 (5 << 12) | ||
127 | #define ONENAND_SYS_CFG1_BRL_4 (4 << 12) | ||
128 | #define ONENAND_SYS_CFG1_BRL_3 (3 << 12) | ||
129 | #define ONENAND_SYS_CFG1_BRL_10 (2 << 12) | ||
130 | #define ONENAND_SYS_CFG1_BRL_9 (1 << 12) | ||
131 | #define ONENAND_SYS_CFG1_BRL_8 (0 << 12) | ||
132 | #define ONENAND_SYS_CFG1_BRL_SHIFT (12) | ||
133 | #define ONENAND_SYS_CFG1_BL_32 (4 << 9) | ||
134 | #define ONENAND_SYS_CFG1_BL_16 (3 << 9) | ||
135 | #define ONENAND_SYS_CFG1_BL_8 (2 << 9) | ||
136 | #define ONENAND_SYS_CFG1_BL_4 (1 << 9) | ||
137 | #define ONENAND_SYS_CFG1_BL_CONT (0 << 9) | ||
138 | #define ONENAND_SYS_CFG1_BL_SHIFT (9) | ||
139 | #define ONENAND_SYS_CFG1_NO_ECC (1 << 8) | ||
140 | #define ONENAND_SYS_CFG1_RDY (1 << 7) | ||
141 | #define ONENAND_SYS_CFG1_INT (1 << 6) | ||
142 | #define ONENAND_SYS_CFG1_IOBE (1 << 5) | ||
143 | #define ONENAND_SYS_CFG1_RDY_CONF (1 << 4) | ||
144 | |||
145 | /* | ||
146 | * Controller Status Register F240h (R) | ||
147 | */ | ||
148 | #define ONENAND_CTRL_ONGO (1 << 15) | ||
149 | #define ONENAND_CTRL_LOCK (1 << 14) | ||
150 | #define ONENAND_CTRL_LOAD (1 << 13) | ||
151 | #define ONENAND_CTRL_PROGRAM (1 << 12) | ||
152 | #define ONENAND_CTRL_ERASE (1 << 11) | ||
153 | #define ONENAND_CTRL_ERROR (1 << 10) | ||
154 | #define ONENAND_CTRL_RSTB (1 << 7) | ||
155 | |||
156 | /* | ||
157 | * Interrupt Status Register F241h (R) | ||
158 | */ | ||
159 | #define ONENAND_INT_MASTER (1 << 15) | ||
160 | #define ONENAND_INT_READ (1 << 7) | ||
161 | #define ONENAND_INT_WRITE (1 << 6) | ||
162 | #define ONENAND_INT_ERASE (1 << 5) | ||
163 | #define ONENAND_INT_RESET (1 << 4) | ||
164 | #define ONENAND_INT_CLEAR (0 << 0) | ||
165 | |||
166 | /* | ||
167 | * NAND Flash Write Protection Status Register F24Eh (R) | ||
168 | */ | ||
169 | #define ONENAND_WP_US (1 << 2) | ||
170 | #define ONENAND_WP_LS (1 << 1) | ||
171 | #define ONENAND_WP_LTS (1 << 0) | ||
172 | |||
173 | /* | ||
174 | * ECC Status Reigser FF00h (R) | ||
175 | */ | ||
176 | #define ONENAND_ECC_1BIT (1 << 0) | ||
177 | #define ONENAND_ECC_2BIT (1 << 1) | ||
178 | #define ONENAND_ECC_2BIT_ALL (0xAAAA) | ||
179 | |||
180 | #endif /* __ONENAND_REG_H */ | ||
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 50b2edfc8f11..b03f512d51b9 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * This code is GPL | 6 | * This code is GPL |
7 | * | 7 | * |
8 | * $Id: partitions.h,v 1.16 2004/11/16 18:34:40 dwmw2 Exp $ | 8 | * $Id: partitions.h,v 1.17 2005/11/07 11:14:55 gleixner Exp $ |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifndef MTD_PARTITIONS_H | 11 | #ifndef MTD_PARTITIONS_H |
@@ -16,25 +16,25 @@ | |||
16 | 16 | ||
17 | /* | 17 | /* |
18 | * Partition definition structure: | 18 | * Partition definition structure: |
19 | * | 19 | * |
20 | * An array of struct partition is passed along with a MTD object to | 20 | * An array of struct partition is passed along with a MTD object to |
21 | * add_mtd_partitions() to create them. | 21 | * add_mtd_partitions() to create them. |
22 | * | 22 | * |
23 | * For each partition, these fields are available: | 23 | * For each partition, these fields are available: |
24 | * name: string that will be used to label the partition's MTD device. | 24 | * name: string that will be used to label the partition's MTD device. |
25 | * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition | 25 | * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition |
26 | * will extend to the end of the master MTD device. | 26 | * will extend to the end of the master MTD device. |
27 | * offset: absolute starting position within the master MTD device; if | 27 | * offset: absolute starting position within the master MTD device; if |
28 | * defined as MTDPART_OFS_APPEND, the partition will start where the | 28 | * defined as MTDPART_OFS_APPEND, the partition will start where the |
29 | * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. | 29 | * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. |
30 | * mask_flags: contains flags that have to be masked (removed) from the | 30 | * mask_flags: contains flags that have to be masked (removed) from the |
31 | * master MTD flag set for the corresponding MTD partition. | 31 | * master MTD flag set for the corresponding MTD partition. |
32 | * For example, to force a read-only partition, simply adding | 32 | * For example, to force a read-only partition, simply adding |
33 | * MTD_WRITEABLE to the mask_flags will do the trick. | 33 | * MTD_WRITEABLE to the mask_flags will do the trick. |
34 | * | 34 | * |
35 | * Note: writeable partitions require their size and offset be | 35 | * Note: writeable partitions require their size and offset be |
36 | * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). | 36 | * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). |
37 | */ | 37 | */ |
38 | 38 | ||
39 | struct mtd_partition { | 39 | struct mtd_partition { |
40 | char *name; /* identifier string */ | 40 | char *name; /* identifier string */ |
@@ -66,7 +66,7 @@ struct mtd_part_parser { | |||
66 | 66 | ||
67 | extern int register_mtd_parser(struct mtd_part_parser *parser); | 67 | extern int register_mtd_parser(struct mtd_part_parser *parser); |
68 | extern int deregister_mtd_parser(struct mtd_part_parser *parser); | 68 | extern int deregister_mtd_parser(struct mtd_part_parser *parser); |
69 | extern int parse_mtd_partitions(struct mtd_info *master, const char **types, | 69 | extern int parse_mtd_partitions(struct mtd_info *master, const char **types, |
70 | struct mtd_partition **pparts, unsigned long origin); | 70 | struct mtd_partition **pparts, unsigned long origin); |
71 | 71 | ||
72 | #define put_partition_parser(p) do { module_put((p)->owner); } while(0) | 72 | #define put_partition_parser(p) do { module_put((p)->owner); } while(0) |
diff --git a/include/linux/mtd/physmap.h b/include/linux/mtd/physmap.h index 05aa4970677f..c7b8bcdef013 100644 --- a/include/linux/mtd/physmap.h +++ b/include/linux/mtd/physmap.h | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * For boards with physically mapped flash and using | 2 | * For boards with physically mapped flash and using |
3 | * drivers/mtd/maps/physmap.c mapping driver. | 3 | * drivers/mtd/maps/physmap.c mapping driver. |
4 | * | 4 | * |
5 | * $Id: physmap.h,v 1.3 2004/07/21 00:16:15 jwboyer Exp $ | 5 | * $Id: physmap.h,v 1.4 2005/11/07 11:14:55 gleixner Exp $ |
6 | * | 6 | * |
7 | * Copyright (C) 2003 MontaVista Software Inc. | 7 | * Copyright (C) 2003 MontaVista Software Inc. |
8 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | 8 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net |
@@ -18,7 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/config.h> | 19 | #include <linux/config.h> |
20 | 20 | ||
21 | #if defined(CONFIG_MTD_PHYSMAP) | 21 | #if defined(CONFIG_MTD_PHYSMAP) |
22 | 22 | ||
23 | #include <linux/mtd/mtd.h> | 23 | #include <linux/mtd/mtd.h> |
24 | #include <linux/mtd/map.h> | 24 | #include <linux/mtd/map.h> |
@@ -44,12 +44,12 @@ static inline void physmap_configure(unsigned long addr, unsigned long size, int | |||
44 | #if defined(CONFIG_MTD_PARTITIONS) | 44 | #if defined(CONFIG_MTD_PARTITIONS) |
45 | 45 | ||
46 | /* | 46 | /* |
47 | * Machines that wish to do flash partition may want to call this function in | 47 | * Machines that wish to do flash partition may want to call this function in |
48 | * their setup routine. | 48 | * their setup routine. |
49 | * | 49 | * |
50 | * physmap_set_partitions(mypartitions, num_parts); | 50 | * physmap_set_partitions(mypartitions, num_parts); |
51 | * | 51 | * |
52 | * Note that one can always override this hard-coded partition with | 52 | * Note that one can always override this hard-coded partition with |
53 | * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS). | 53 | * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS). |
54 | */ | 54 | */ |
55 | void physmap_set_partitions(struct mtd_partition *parts, int num_parts); | 55 | void physmap_set_partitions(struct mtd_partition *parts, int num_parts); |
diff --git a/include/linux/mtd/pmc551.h b/include/linux/mtd/pmc551.h index 113e3087f68a..a7f6d20ad407 100644 --- a/include/linux/mtd/pmc551.h +++ b/include/linux/mtd/pmc551.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $ | 2 | * $Id: pmc551.h,v 1.6 2005/11/07 11:14:55 gleixner Exp $ |
3 | * | 3 | * |
4 | * PMC551 PCI Mezzanine Ram Device | 4 | * PMC551 PCI Mezzanine Ram Device |
5 | * | 5 | * |
@@ -7,7 +7,7 @@ | |||
7 | * Mark Ferrell | 7 | * Mark Ferrell |
8 | * Copyright 1999,2000 Nortel Networks | 8 | * Copyright 1999,2000 Nortel Networks |
9 | * | 9 | * |
10 | * License: | 10 | * License: |
11 | * As part of this driver was derrived from the slram.c driver it falls | 11 | * As part of this driver was derrived from the slram.c driver it falls |
12 | * under the same license, which is GNU General Public License v2 | 12 | * under the same license, which is GNU General Public License v2 |
13 | */ | 13 | */ |
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | #include <linux/mtd/mtd.h> | 18 | #include <linux/mtd/mtd.h> |
19 | 19 | ||
20 | #define PMC551_VERSION "$Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $\n"\ | 20 | #define PMC551_VERSION "$Id: pmc551.h,v 1.6 2005/11/07 11:14:55 gleixner Exp $\n"\ |
21 | "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n" | 21 | "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n" |
22 | 22 | ||
23 | /* | 23 | /* |
@@ -30,7 +30,7 @@ struct mypriv { | |||
30 | u32 curr_map0; | 30 | u32 curr_map0; |
31 | u32 asize; | 31 | u32 asize; |
32 | struct mtd_info *nextpmc551; | 32 | struct mtd_info *nextpmc551; |
33 | }; | 33 | }; |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * Function Prototypes | 36 | * Function Prototypes |
@@ -39,7 +39,7 @@ static int pmc551_erase(struct mtd_info *, struct erase_info *); | |||
39 | static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t); | 39 | static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t); |
40 | static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); | 40 | static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); |
41 | static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 41 | static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
42 | static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 42 | static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
43 | 43 | ||
44 | 44 | ||
45 | /* | 45 | /* |
@@ -50,7 +50,7 @@ static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_cha | |||
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | #ifndef PCI_DEVICE_ID_V3_SEMI_V370PDC | 52 | #ifndef PCI_DEVICE_ID_V3_SEMI_V370PDC |
53 | #define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200 | 53 | #define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200 |
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | 56 | ||
diff --git a/include/linux/mtd/xip.h b/include/linux/mtd/xip.h index 7b7deef6b180..220d50bb71cd 100644 --- a/include/linux/mtd/xip.h +++ b/include/linux/mtd/xip.h | |||
@@ -12,7 +12,7 @@ | |||
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | * | 14 | * |
15 | * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $ | 15 | * $Id: xip.h,v 1.5 2005/11/07 11:14:55 gleixner Exp $ |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifndef __LINUX_MTD_XIP_H__ | 18 | #ifndef __LINUX_MTD_XIP_H__ |
@@ -23,19 +23,19 @@ | |||
23 | #ifdef CONFIG_MTD_XIP | 23 | #ifdef CONFIG_MTD_XIP |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Function that are modifying the flash state away from array mode must | ||
27 | * obviously not be running from flash. The __xipram is therefore marking | ||
28 | * those functions so they get relocated to ram. | ||
29 | */ | ||
30 | #define __xipram __attribute__ ((__section__ (".data"))) | ||
31 | |||
32 | /* | ||
33 | * We really don't want gcc to guess anything. | 26 | * We really don't want gcc to guess anything. |
34 | * We absolutely _need_ proper inlining. | 27 | * We absolutely _need_ proper inlining. |
35 | */ | 28 | */ |
36 | #include <linux/compiler.h> | 29 | #include <linux/compiler.h> |
37 | 30 | ||
38 | /* | 31 | /* |
32 | * Function that are modifying the flash state away from array mode must | ||
33 | * obviously not be running from flash. The __xipram is therefore marking | ||
34 | * those functions so they get relocated to ram. | ||
35 | */ | ||
36 | #define __xipram noinline __attribute__ ((__section__ (".data"))) | ||
37 | |||
38 | /* | ||
39 | * Each architecture has to provide the following macros. They must access | 39 | * Each architecture has to provide the following macros. They must access |
40 | * the hardware directly and not rely on any other (XIP) functions since they | 40 | * the hardware directly and not rely on any other (XIP) functions since they |
41 | * won't be available when used (flash not in array mode). | 41 | * won't be available when used (flash not in array mode). |
@@ -60,9 +60,9 @@ | |||
60 | * overflowing. | 60 | * overflowing. |
61 | * | 61 | * |
62 | * xip_iprefetch() | 62 | * xip_iprefetch() |
63 | * | 63 | * |
64 | * Macro to fill instruction prefetch | 64 | * Macro to fill instruction prefetch |
65 | * e.g. a series of nops: asm volatile (".rep 8; nop; .endr"); | 65 | * e.g. a series of nops: asm volatile (".rep 8; nop; .endr"); |
66 | */ | 66 | */ |
67 | 67 | ||
68 | #include <asm/mtd-xip.h> | 68 | #include <asm/mtd-xip.h> |
diff --git a/include/linux/rslib.h b/include/linux/rslib.h index 980c8f74d8dc..ace25acfdc97 100644 --- a/include/linux/rslib.h +++ b/include/linux/rslib.h | |||
@@ -1,15 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * include/linux/rslib.h | 2 | * include/linux/rslib.h |
3 | * | 3 | * |
4 | * Overview: | 4 | * Overview: |
5 | * Generic Reed Solomon encoder / decoder library | 5 | * Generic Reed Solomon encoder / decoder library |
6 | * | 6 | * |
7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
8 | * | 8 | * |
9 | * RS code lifted from reed solomon library written by Phil Karn | 9 | * RS code lifted from reed solomon library written by Phil Karn |
10 | * Copyright 2002 Phil Karn, KA9Q | 10 | * Copyright 2002 Phil Karn, KA9Q |
11 | * | 11 | * |
12 | * $Id: rslib.h,v 1.3 2004/10/05 22:08:22 gleixner Exp $ | 12 | * $Id: rslib.h,v 1.4 2005/11/07 11:14:52 gleixner Exp $ |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License version 2 as | 15 | * it under the terms of the GNU General Public License version 2 as |
@@ -21,20 +21,20 @@ | |||
21 | 21 | ||
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * struct rs_control - rs control structure | 25 | * struct rs_control - rs control structure |
26 | * | 26 | * |
27 | * @mm: Bits per symbol | 27 | * @mm: Bits per symbol |
28 | * @nn: Symbols per block (= (1<<mm)-1) | 28 | * @nn: Symbols per block (= (1<<mm)-1) |
29 | * @alpha_to: log lookup table | 29 | * @alpha_to: log lookup table |
30 | * @index_of: Antilog lookup table | 30 | * @index_of: Antilog lookup table |
31 | * @genpoly: Generator polynomial | 31 | * @genpoly: Generator polynomial |
32 | * @nroots: Number of generator roots = number of parity symbols | 32 | * @nroots: Number of generator roots = number of parity symbols |
33 | * @fcr: First consecutive root, index form | 33 | * @fcr: First consecutive root, index form |
34 | * @prim: Primitive element, index form | 34 | * @prim: Primitive element, index form |
35 | * @iprim: prim-th root of 1, index form | 35 | * @iprim: prim-th root of 1, index form |
36 | * @gfpoly: The primitive generator polynominal | 36 | * @gfpoly: The primitive generator polynominal |
37 | * @users: Users of this structure | 37 | * @users: Users of this structure |
38 | * @list: List entry for the rs control list | 38 | * @list: List entry for the rs control list |
39 | */ | 39 | */ |
40 | struct rs_control { | 40 | struct rs_control { |
@@ -58,7 +58,7 @@ int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, | |||
58 | uint16_t invmsk); | 58 | uint16_t invmsk); |
59 | #endif | 59 | #endif |
60 | #ifdef CONFIG_REED_SOLOMON_DEC8 | 60 | #ifdef CONFIG_REED_SOLOMON_DEC8 |
61 | int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len, | 61 | int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len, |
62 | uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, | 62 | uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, |
63 | uint16_t *corr); | 63 | uint16_t *corr); |
64 | #endif | 64 | #endif |
@@ -75,7 +75,7 @@ int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len, | |||
75 | #endif | 75 | #endif |
76 | 76 | ||
77 | /* Create or get a matching rs control structure */ | 77 | /* Create or get a matching rs control structure */ |
78 | struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, | 78 | struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, |
79 | int nroots); | 79 | int nroots); |
80 | 80 | ||
81 | /* Release a rs control structure */ | 81 | /* Release a rs control structure */ |
@@ -87,9 +87,9 @@ void free_rs(struct rs_control *rs); | |||
87 | * @x: the value to reduce | 87 | * @x: the value to reduce |
88 | * | 88 | * |
89 | * where | 89 | * where |
90 | * rs->mm = number of bits per symbol | 90 | * rs->mm = number of bits per symbol |
91 | * rs->nn = (2^rs->mm) - 1 | 91 | * rs->nn = (2^rs->mm) - 1 |
92 | * | 92 | * |
93 | * Simple arithmetic modulo would return a wrong result for values | 93 | * Simple arithmetic modulo would return a wrong result for values |
94 | * >= 3 * rs->nn | 94 | * >= 3 * rs->nn |
95 | */ | 95 | */ |
diff --git a/include/mtd/inftl-user.h b/include/mtd/inftl-user.h index bda4f2c8f728..9b1e2526b45e 100644 --- a/include/mtd/inftl-user.h +++ b/include/mtd/inftl-user.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: inftl-user.h,v 1.1 2004/05/05 15:17:00 dwmw2 Exp $ | 2 | * $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $ |
3 | * | 3 | * |
4 | * Parts of INFTL headers shared with userspace | 4 | * Parts of INFTL headers shared with userspace |
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 428d9122940b..b5994ea56a5a 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: mtd-abi.h,v 1.11 2005/05/19 16:08:58 gleixner Exp $ | 2 | * $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $ |
3 | * | 3 | * |
4 | * Portions of MTD ABI definition which are shared by kernel and user space | 4 | * Portions of MTD ABI definition which are shared by kernel and user space |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #ifndef __MTD_ABI_H__ | 7 | #ifndef __MTD_ABI_H__ |
@@ -42,6 +42,7 @@ struct mtd_oob_buf { | |||
42 | #define MTD_OOB 64 // Out-of-band data (NAND flash) | 42 | #define MTD_OOB 64 // Out-of-band data (NAND flash) |
43 | #define MTD_ECC 128 // Device capable of automatic ECC | 43 | #define MTD_ECC 128 // Device capable of automatic ECC |
44 | #define MTD_NO_VIRTBLOCKS 256 // Virtual blocks not allowed | 44 | #define MTD_NO_VIRTBLOCKS 256 // Virtual blocks not allowed |
45 | #define MTD_PROGRAM_REGIONS 512 // Configurable Programming Regions | ||
45 | 46 | ||
46 | // Some common devices / combinations of capabilities | 47 | // Some common devices / combinations of capabilities |
47 | #define MTD_CAP_ROM 0 | 48 | #define MTD_CAP_ROM 0 |
@@ -80,7 +81,7 @@ struct mtd_info_user { | |||
80 | }; | 81 | }; |
81 | 82 | ||
82 | struct region_info_user { | 83 | struct region_info_user { |
83 | uint32_t offset; /* At which this region starts, | 84 | uint32_t offset; /* At which this region starts, |
84 | * from the beginning of the MTD */ | 85 | * from the beginning of the MTD */ |
85 | uint32_t erasesize; /* For this region */ | 86 | uint32_t erasesize; /* For this region */ |
86 | uint32_t numblocks; /* Number of blocks in this region */ | 87 | uint32_t numblocks; /* Number of blocks in this region */ |
diff --git a/include/mtd/nftl-user.h b/include/mtd/nftl-user.h index 924ec0459e9c..b2bca18e7311 100644 --- a/include/mtd/nftl-user.h +++ b/include/mtd/nftl-user.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: nftl-user.h,v 1.1 2004/05/05 14:44:57 dwmw2 Exp $ | 2 | * $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $ |
3 | * | 3 | * |
4 | * Parts of NFTL headers shared with userspace | 4 | * Parts of NFTL headers shared with userspace |
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
diff --git a/lib/reed_solomon/Makefile b/lib/reed_solomon/Makefile index 747a2de29346..c3d7136827ed 100644 --- a/lib/reed_solomon/Makefile +++ b/lib/reed_solomon/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | # | 1 | # |
2 | # This is a modified version of reed solomon lib, | 2 | # This is a modified version of reed solomon lib, |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o | 5 | obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o |
diff --git a/lib/reed_solomon/decode_rs.c b/lib/reed_solomon/decode_rs.c index d401decd6289..a58df56f09b6 100644 --- a/lib/reed_solomon/decode_rs.c +++ b/lib/reed_solomon/decode_rs.c | |||
@@ -1,22 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * lib/reed_solomon/decode_rs.c | 2 | * lib/reed_solomon/decode_rs.c |
3 | * | 3 | * |
4 | * Overview: | 4 | * Overview: |
5 | * Generic Reed Solomon encoder / decoder library | 5 | * Generic Reed Solomon encoder / decoder library |
6 | * | 6 | * |
7 | * Copyright 2002, Phil Karn, KA9Q | 7 | * Copyright 2002, Phil Karn, KA9Q |
8 | * May be used under the terms of the GNU General Public License (GPL) | 8 | * May be used under the terms of the GNU General Public License (GPL) |
9 | * | 9 | * |
10 | * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de) | 10 | * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de) |
11 | * | 11 | * |
12 | * $Id: decode_rs.c,v 1.6 2004/10/22 15:41:47 gleixner Exp $ | 12 | * $Id: decode_rs.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $ |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | /* Generic data width independent code which is included by the | 16 | /* Generic data width independent code which is included by the |
17 | * wrappers. | 17 | * wrappers. |
18 | */ | 18 | */ |
19 | { | 19 | { |
20 | int deg_lambda, el, deg_omega; | 20 | int deg_lambda, el, deg_omega; |
21 | int i, j, r, k, pad; | 21 | int i, j, r, k, pad; |
22 | int nn = rs->nn; | 22 | int nn = rs->nn; |
@@ -41,9 +41,9 @@ | |||
41 | pad = nn - nroots - len; | 41 | pad = nn - nroots - len; |
42 | if (pad < 0 || pad >= nn) | 42 | if (pad < 0 || pad >= nn) |
43 | return -ERANGE; | 43 | return -ERANGE; |
44 | 44 | ||
45 | /* Does the caller provide the syndrome ? */ | 45 | /* Does the caller provide the syndrome ? */ |
46 | if (s != NULL) | 46 | if (s != NULL) |
47 | goto decode; | 47 | goto decode; |
48 | 48 | ||
49 | /* form the syndromes; i.e., evaluate data(x) at roots of | 49 | /* form the syndromes; i.e., evaluate data(x) at roots of |
@@ -54,11 +54,11 @@ | |||
54 | for (j = 1; j < len; j++) { | 54 | for (j = 1; j < len; j++) { |
55 | for (i = 0; i < nroots; i++) { | 55 | for (i = 0; i < nroots; i++) { |
56 | if (syn[i] == 0) { | 56 | if (syn[i] == 0) { |
57 | syn[i] = (((uint16_t) data[j]) ^ | 57 | syn[i] = (((uint16_t) data[j]) ^ |
58 | invmsk) & msk; | 58 | invmsk) & msk; |
59 | } else { | 59 | } else { |
60 | syn[i] = ((((uint16_t) data[j]) ^ | 60 | syn[i] = ((((uint16_t) data[j]) ^ |
61 | invmsk) & msk) ^ | 61 | invmsk) & msk) ^ |
62 | alpha_to[rs_modnn(rs, index_of[syn[i]] + | 62 | alpha_to[rs_modnn(rs, index_of[syn[i]] + |
63 | (fcr + i) * prim)]; | 63 | (fcr + i) * prim)]; |
64 | } | 64 | } |
@@ -70,7 +70,7 @@ | |||
70 | if (syn[i] == 0) { | 70 | if (syn[i] == 0) { |
71 | syn[i] = ((uint16_t) par[j]) & msk; | 71 | syn[i] = ((uint16_t) par[j]) & msk; |
72 | } else { | 72 | } else { |
73 | syn[i] = (((uint16_t) par[j]) & msk) ^ | 73 | syn[i] = (((uint16_t) par[j]) & msk) ^ |
74 | alpha_to[rs_modnn(rs, index_of[syn[i]] + | 74 | alpha_to[rs_modnn(rs, index_of[syn[i]] + |
75 | (fcr+i)*prim)]; | 75 | (fcr+i)*prim)]; |
76 | } | 76 | } |
@@ -99,14 +99,14 @@ | |||
99 | 99 | ||
100 | if (no_eras > 0) { | 100 | if (no_eras > 0) { |
101 | /* Init lambda to be the erasure locator polynomial */ | 101 | /* Init lambda to be the erasure locator polynomial */ |
102 | lambda[1] = alpha_to[rs_modnn(rs, | 102 | lambda[1] = alpha_to[rs_modnn(rs, |
103 | prim * (nn - 1 - eras_pos[0]))]; | 103 | prim * (nn - 1 - eras_pos[0]))]; |
104 | for (i = 1; i < no_eras; i++) { | 104 | for (i = 1; i < no_eras; i++) { |
105 | u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i])); | 105 | u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i])); |
106 | for (j = i + 1; j > 0; j--) { | 106 | for (j = i + 1; j > 0; j--) { |
107 | tmp = index_of[lambda[j - 1]]; | 107 | tmp = index_of[lambda[j - 1]]; |
108 | if (tmp != nn) { | 108 | if (tmp != nn) { |
109 | lambda[j] ^= | 109 | lambda[j] ^= |
110 | alpha_to[rs_modnn(rs, u + tmp)]; | 110 | alpha_to[rs_modnn(rs, u + tmp)]; |
111 | } | 111 | } |
112 | } | 112 | } |
@@ -127,8 +127,8 @@ | |||
127 | discr_r = 0; | 127 | discr_r = 0; |
128 | for (i = 0; i < r; i++) { | 128 | for (i = 0; i < r; i++) { |
129 | if ((lambda[i] != 0) && (s[r - i - 1] != nn)) { | 129 | if ((lambda[i] != 0) && (s[r - i - 1] != nn)) { |
130 | discr_r ^= | 130 | discr_r ^= |
131 | alpha_to[rs_modnn(rs, | 131 | alpha_to[rs_modnn(rs, |
132 | index_of[lambda[i]] + | 132 | index_of[lambda[i]] + |
133 | s[r - i - 1])]; | 133 | s[r - i - 1])]; |
134 | } | 134 | } |
@@ -143,7 +143,7 @@ | |||
143 | t[0] = lambda[0]; | 143 | t[0] = lambda[0]; |
144 | for (i = 0; i < nroots; i++) { | 144 | for (i = 0; i < nroots; i++) { |
145 | if (b[i] != nn) { | 145 | if (b[i] != nn) { |
146 | t[i + 1] = lambda[i + 1] ^ | 146 | t[i + 1] = lambda[i + 1] ^ |
147 | alpha_to[rs_modnn(rs, discr_r + | 147 | alpha_to[rs_modnn(rs, discr_r + |
148 | b[i])]; | 148 | b[i])]; |
149 | } else | 149 | } else |
@@ -229,7 +229,7 @@ | |||
229 | num1 = 0; | 229 | num1 = 0; |
230 | for (i = deg_omega; i >= 0; i--) { | 230 | for (i = deg_omega; i >= 0; i--) { |
231 | if (omega[i] != nn) | 231 | if (omega[i] != nn) |
232 | num1 ^= alpha_to[rs_modnn(rs, omega[i] + | 232 | num1 ^= alpha_to[rs_modnn(rs, omega[i] + |
233 | i * root[j])]; | 233 | i * root[j])]; |
234 | } | 234 | } |
235 | num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)]; | 235 | num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)]; |
@@ -239,13 +239,13 @@ | |||
239 | * lambda_pr of lambda[i] */ | 239 | * lambda_pr of lambda[i] */ |
240 | for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) { | 240 | for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) { |
241 | if (lambda[i + 1] != nn) { | 241 | if (lambda[i + 1] != nn) { |
242 | den ^= alpha_to[rs_modnn(rs, lambda[i + 1] + | 242 | den ^= alpha_to[rs_modnn(rs, lambda[i + 1] + |
243 | i * root[j])]; | 243 | i * root[j])]; |
244 | } | 244 | } |
245 | } | 245 | } |
246 | /* Apply error to data */ | 246 | /* Apply error to data */ |
247 | if (num1 != 0 && loc[j] >= pad) { | 247 | if (num1 != 0 && loc[j] >= pad) { |
248 | uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + | 248 | uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + |
249 | index_of[num2] + | 249 | index_of[num2] + |
250 | nn - index_of[den])]; | 250 | nn - index_of[den])]; |
251 | /* Store the error correction pattern, if a | 251 | /* Store the error correction pattern, if a |
diff --git a/lib/reed_solomon/encode_rs.c b/lib/reed_solomon/encode_rs.c index 237bf65ae886..0b5b1a6728ec 100644 --- a/lib/reed_solomon/encode_rs.c +++ b/lib/reed_solomon/encode_rs.c | |||
@@ -1,19 +1,19 @@ | |||
1 | /* | 1 | /* |
2 | * lib/reed_solomon/encode_rs.c | 2 | * lib/reed_solomon/encode_rs.c |
3 | * | 3 | * |
4 | * Overview: | 4 | * Overview: |
5 | * Generic Reed Solomon encoder / decoder library | 5 | * Generic Reed Solomon encoder / decoder library |
6 | * | 6 | * |
7 | * Copyright 2002, Phil Karn, KA9Q | 7 | * Copyright 2002, Phil Karn, KA9Q |
8 | * May be used under the terms of the GNU General Public License (GPL) | 8 | * May be used under the terms of the GNU General Public License (GPL) |
9 | * | 9 | * |
10 | * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de) | 10 | * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de) |
11 | * | 11 | * |
12 | * $Id: encode_rs.c,v 1.4 2004/10/22 15:41:47 gleixner Exp $ | 12 | * $Id: encode_rs.c,v 1.5 2005/11/07 11:14:59 gleixner Exp $ |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | /* Generic data width independent code which is included by the | 16 | /* Generic data width independent code which is included by the |
17 | * wrappers. | 17 | * wrappers. |
18 | * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par) | 18 | * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par) |
19 | */ | 19 | */ |
@@ -35,16 +35,16 @@ | |||
35 | for (i = 0; i < len; i++) { | 35 | for (i = 0; i < len; i++) { |
36 | fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]]; | 36 | fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]]; |
37 | /* feedback term is non-zero */ | 37 | /* feedback term is non-zero */ |
38 | if (fb != nn) { | 38 | if (fb != nn) { |
39 | for (j = 1; j < nroots; j++) { | 39 | for (j = 1; j < nroots; j++) { |
40 | par[j] ^= alpha_to[rs_modnn(rs, fb + | 40 | par[j] ^= alpha_to[rs_modnn(rs, fb + |
41 | genpoly[nroots - j])]; | 41 | genpoly[nroots - j])]; |
42 | } | 42 | } |
43 | } | 43 | } |
44 | /* Shift */ | 44 | /* Shift */ |
45 | memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1)); | 45 | memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1)); |
46 | if (fb != nn) { | 46 | if (fb != nn) { |
47 | par[nroots - 1] = alpha_to[rs_modnn(rs, | 47 | par[nroots - 1] = alpha_to[rs_modnn(rs, |
48 | fb + genpoly[0])]; | 48 | fb + genpoly[0])]; |
49 | } else { | 49 | } else { |
50 | par[nroots - 1] = 0; | 50 | par[nroots - 1] = 0; |
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c index 6604e3b1940c..f5fef948a415 100644 --- a/lib/reed_solomon/reed_solomon.c +++ b/lib/reed_solomon/reed_solomon.c | |||
@@ -1,22 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * lib/reed_solomon/rslib.c | 2 | * lib/reed_solomon/rslib.c |
3 | * | 3 | * |
4 | * Overview: | 4 | * Overview: |
5 | * Generic Reed Solomon encoder / decoder library | 5 | * Generic Reed Solomon encoder / decoder library |
6 | * | 6 | * |
7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
8 | * | 8 | * |
9 | * Reed Solomon code lifted from reed solomon library written by Phil Karn | 9 | * Reed Solomon code lifted from reed solomon library written by Phil Karn |
10 | * Copyright 2002 Phil Karn, KA9Q | 10 | * Copyright 2002 Phil Karn, KA9Q |
11 | * | 11 | * |
12 | * $Id: rslib.c,v 1.5 2004/10/22 15:41:47 gleixner Exp $ | 12 | * $Id: rslib.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $ |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License version 2 as | 15 | * it under the terms of the GNU General Public License version 2 as |
16 | * published by the Free Software Foundation. | 16 | * published by the Free Software Foundation. |
17 | * | 17 | * |
18 | * Description: | 18 | * Description: |
19 | * | 19 | * |
20 | * The generic Reed Solomon library provides runtime configurable | 20 | * The generic Reed Solomon library provides runtime configurable |
21 | * encoding / decoding of RS codes. | 21 | * encoding / decoding of RS codes. |
22 | * Each user must call init_rs to get a pointer to a rs_control | 22 | * Each user must call init_rs to get a pointer to a rs_control |
@@ -25,11 +25,11 @@ | |||
25 | * If a structure is generated then the polynomial arrays for | 25 | * If a structure is generated then the polynomial arrays for |
26 | * fast encoding / decoding are built. This can take some time so | 26 | * fast encoding / decoding are built. This can take some time so |
27 | * make sure not to call this function from a time critical path. | 27 | * make sure not to call this function from a time critical path. |
28 | * Usually a module / driver should initialize the necessary | 28 | * Usually a module / driver should initialize the necessary |
29 | * rs_control structure on module / driver init and release it | 29 | * rs_control structure on module / driver init and release it |
30 | * on exit. | 30 | * on exit. |
31 | * The encoding puts the calculated syndrome into a given syndrome | 31 | * The encoding puts the calculated syndrome into a given syndrome |
32 | * buffer. | 32 | * buffer. |
33 | * The decoding is a two step process. The first step calculates | 33 | * The decoding is a two step process. The first step calculates |
34 | * the syndrome over the received (data + syndrome) and calls the | 34 | * the syndrome over the received (data + syndrome) and calls the |
35 | * second stage, which does the decoding / error correction itself. | 35 | * second stage, which does the decoding / error correction itself. |
@@ -51,7 +51,7 @@ static LIST_HEAD (rslist); | |||
51 | /* Protection for the list */ | 51 | /* Protection for the list */ |
52 | static DECLARE_MUTEX(rslistlock); | 52 | static DECLARE_MUTEX(rslistlock); |
53 | 53 | ||
54 | /** | 54 | /** |
55 | * rs_init - Initialize a Reed-Solomon codec | 55 | * rs_init - Initialize a Reed-Solomon codec |
56 | * | 56 | * |
57 | * @symsize: symbol size, bits (1-8) | 57 | * @symsize: symbol size, bits (1-8) |
@@ -63,7 +63,7 @@ static DECLARE_MUTEX(rslistlock); | |||
63 | * Allocate a control structure and the polynom arrays for faster | 63 | * Allocate a control structure and the polynom arrays for faster |
64 | * en/decoding. Fill the arrays according to the given parameters | 64 | * en/decoding. Fill the arrays according to the given parameters |
65 | */ | 65 | */ |
66 | static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, | 66 | static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, |
67 | int prim, int nroots) | 67 | int prim, int nroots) |
68 | { | 68 | { |
69 | struct rs_control *rs; | 69 | struct rs_control *rs; |
@@ -124,15 +124,15 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, | |||
124 | /* Multiply rs->genpoly[] by @**(root + x) */ | 124 | /* Multiply rs->genpoly[] by @**(root + x) */ |
125 | for (j = i; j > 0; j--) { | 125 | for (j = i; j > 0; j--) { |
126 | if (rs->genpoly[j] != 0) { | 126 | if (rs->genpoly[j] != 0) { |
127 | rs->genpoly[j] = rs->genpoly[j -1] ^ | 127 | rs->genpoly[j] = rs->genpoly[j -1] ^ |
128 | rs->alpha_to[rs_modnn(rs, | 128 | rs->alpha_to[rs_modnn(rs, |
129 | rs->index_of[rs->genpoly[j]] + root)]; | 129 | rs->index_of[rs->genpoly[j]] + root)]; |
130 | } else | 130 | } else |
131 | rs->genpoly[j] = rs->genpoly[j - 1]; | 131 | rs->genpoly[j] = rs->genpoly[j - 1]; |
132 | } | 132 | } |
133 | /* rs->genpoly[0] can never be zero */ | 133 | /* rs->genpoly[0] can never be zero */ |
134 | rs->genpoly[0] = | 134 | rs->genpoly[0] = |
135 | rs->alpha_to[rs_modnn(rs, | 135 | rs->alpha_to[rs_modnn(rs, |
136 | rs->index_of[rs->genpoly[0]] + root)]; | 136 | rs->index_of[rs->genpoly[0]] + root)]; |
137 | } | 137 | } |
138 | /* convert rs->genpoly[] to index form for quicker encoding */ | 138 | /* convert rs->genpoly[] to index form for quicker encoding */ |
@@ -153,7 +153,7 @@ errrs: | |||
153 | } | 153 | } |
154 | 154 | ||
155 | 155 | ||
156 | /** | 156 | /** |
157 | * free_rs - Free the rs control structure, if its not longer used | 157 | * free_rs - Free the rs control structure, if its not longer used |
158 | * | 158 | * |
159 | * @rs: the control structure which is not longer used by the | 159 | * @rs: the control structure which is not longer used by the |
@@ -173,19 +173,19 @@ void free_rs(struct rs_control *rs) | |||
173 | up(&rslistlock); | 173 | up(&rslistlock); |
174 | } | 174 | } |
175 | 175 | ||
176 | /** | 176 | /** |
177 | * init_rs - Find a matching or allocate a new rs control structure | 177 | * init_rs - Find a matching or allocate a new rs control structure |
178 | * | 178 | * |
179 | * @symsize: the symbol size (number of bits) | 179 | * @symsize: the symbol size (number of bits) |
180 | * @gfpoly: the extended Galois field generator polynomial coefficients, | 180 | * @gfpoly: the extended Galois field generator polynomial coefficients, |
181 | * with the 0th coefficient in the low order bit. The polynomial | 181 | * with the 0th coefficient in the low order bit. The polynomial |
182 | * must be primitive; | 182 | * must be primitive; |
183 | * @fcr: the first consecutive root of the rs code generator polynomial | 183 | * @fcr: the first consecutive root of the rs code generator polynomial |
184 | * in index form | 184 | * in index form |
185 | * @prim: primitive element to generate polynomial roots | 185 | * @prim: primitive element to generate polynomial roots |
186 | * @nroots: RS code generator polynomial degree (number of roots) | 186 | * @nroots: RS code generator polynomial degree (number of roots) |
187 | */ | 187 | */ |
188 | struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, | 188 | struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, |
189 | int nroots) | 189 | int nroots) |
190 | { | 190 | { |
191 | struct list_head *tmp; | 191 | struct list_head *tmp; |
@@ -198,9 +198,9 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, | |||
198 | return NULL; | 198 | return NULL; |
199 | if (prim <= 0 || prim >= (1<<symsize)) | 199 | if (prim <= 0 || prim >= (1<<symsize)) |
200 | return NULL; | 200 | return NULL; |
201 | if (nroots < 0 || nroots >= (1<<symsize) || nroots > 8) | 201 | if (nroots < 0 || nroots >= (1<<symsize)) |
202 | return NULL; | 202 | return NULL; |
203 | 203 | ||
204 | down(&rslistlock); | 204 | down(&rslistlock); |
205 | 205 | ||
206 | /* Walk through the list and look for a matching entry */ | 206 | /* Walk through the list and look for a matching entry */ |
@@ -211,9 +211,9 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, | |||
211 | if (gfpoly != rs->gfpoly) | 211 | if (gfpoly != rs->gfpoly) |
212 | continue; | 212 | continue; |
213 | if (fcr != rs->fcr) | 213 | if (fcr != rs->fcr) |
214 | continue; | 214 | continue; |
215 | if (prim != rs->prim) | 215 | if (prim != rs->prim) |
216 | continue; | 216 | continue; |
217 | if (nroots != rs->nroots) | 217 | if (nroots != rs->nroots) |
218 | continue; | 218 | continue; |
219 | /* We have a matching one already */ | 219 | /* We have a matching one already */ |
@@ -227,18 +227,18 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, | |||
227 | rs->users = 1; | 227 | rs->users = 1; |
228 | list_add(&rs->list, &rslist); | 228 | list_add(&rs->list, &rslist); |
229 | } | 229 | } |
230 | out: | 230 | out: |
231 | up(&rslistlock); | 231 | up(&rslistlock); |
232 | return rs; | 232 | return rs; |
233 | } | 233 | } |
234 | 234 | ||
235 | #ifdef CONFIG_REED_SOLOMON_ENC8 | 235 | #ifdef CONFIG_REED_SOLOMON_ENC8 |
236 | /** | 236 | /** |
237 | * encode_rs8 - Calculate the parity for data values (8bit data width) | 237 | * encode_rs8 - Calculate the parity for data values (8bit data width) |
238 | * | 238 | * |
239 | * @rs: the rs control structure | 239 | * @rs: the rs control structure |
240 | * @data: data field of a given type | 240 | * @data: data field of a given type |
241 | * @len: data length | 241 | * @len: data length |
242 | * @par: parity data, must be initialized by caller (usually all 0) | 242 | * @par: parity data, must be initialized by caller (usually all 0) |
243 | * @invmsk: invert data mask (will be xored on data) | 243 | * @invmsk: invert data mask (will be xored on data) |
244 | * | 244 | * |
@@ -246,7 +246,7 @@ out: | |||
246 | * symbol size > 8. The calling code must take care of encoding of the | 246 | * symbol size > 8. The calling code must take care of encoding of the |
247 | * syndrome result for storage itself. | 247 | * syndrome result for storage itself. |
248 | */ | 248 | */ |
249 | int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, | 249 | int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, |
250 | uint16_t invmsk) | 250 | uint16_t invmsk) |
251 | { | 251 | { |
252 | #include "encode_rs.c" | 252 | #include "encode_rs.c" |
@@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(encode_rs8); | |||
255 | #endif | 255 | #endif |
256 | 256 | ||
257 | #ifdef CONFIG_REED_SOLOMON_DEC8 | 257 | #ifdef CONFIG_REED_SOLOMON_DEC8 |
258 | /** | 258 | /** |
259 | * decode_rs8 - Decode codeword (8bit data width) | 259 | * decode_rs8 - Decode codeword (8bit data width) |
260 | * | 260 | * |
261 | * @rs: the rs control structure | 261 | * @rs: the rs control structure |
@@ -273,7 +273,7 @@ EXPORT_SYMBOL_GPL(encode_rs8); | |||
273 | * syndrome result and the received parity before calling this code. | 273 | * syndrome result and the received parity before calling this code. |
274 | */ | 274 | */ |
275 | int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len, | 275 | int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len, |
276 | uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, | 276 | uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, |
277 | uint16_t *corr) | 277 | uint16_t *corr) |
278 | { | 278 | { |
279 | #include "decode_rs.c" | 279 | #include "decode_rs.c" |
@@ -287,13 +287,13 @@ EXPORT_SYMBOL_GPL(decode_rs8); | |||
287 | * | 287 | * |
288 | * @rs: the rs control structure | 288 | * @rs: the rs control structure |
289 | * @data: data field of a given type | 289 | * @data: data field of a given type |
290 | * @len: data length | 290 | * @len: data length |
291 | * @par: parity data, must be initialized by caller (usually all 0) | 291 | * @par: parity data, must be initialized by caller (usually all 0) |
292 | * @invmsk: invert data mask (will be xored on data, not on parity!) | 292 | * @invmsk: invert data mask (will be xored on data, not on parity!) |
293 | * | 293 | * |
294 | * Each field in the data array contains up to symbol size bits of valid data. | 294 | * Each field in the data array contains up to symbol size bits of valid data. |
295 | */ | 295 | */ |
296 | int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par, | 296 | int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par, |
297 | uint16_t invmsk) | 297 | uint16_t invmsk) |
298 | { | 298 | { |
299 | #include "encode_rs.c" | 299 | #include "encode_rs.c" |
@@ -302,7 +302,7 @@ EXPORT_SYMBOL_GPL(encode_rs16); | |||
302 | #endif | 302 | #endif |
303 | 303 | ||
304 | #ifdef CONFIG_REED_SOLOMON_DEC16 | 304 | #ifdef CONFIG_REED_SOLOMON_DEC16 |
305 | /** | 305 | /** |
306 | * decode_rs16 - Decode codeword (16bit data width) | 306 | * decode_rs16 - Decode codeword (16bit data width) |
307 | * | 307 | * |
308 | * @rs: the rs control structure | 308 | * @rs: the rs control structure |
@@ -312,13 +312,13 @@ EXPORT_SYMBOL_GPL(encode_rs16); | |||
312 | * @s: syndrome data field (if NULL, syndrome is calculated) | 312 | * @s: syndrome data field (if NULL, syndrome is calculated) |
313 | * @no_eras: number of erasures | 313 | * @no_eras: number of erasures |
314 | * @eras_pos: position of erasures, can be NULL | 314 | * @eras_pos: position of erasures, can be NULL |
315 | * @invmsk: invert data mask (will be xored on data, not on parity!) | 315 | * @invmsk: invert data mask (will be xored on data, not on parity!) |
316 | * @corr: buffer to store correction bitmask on eras_pos | 316 | * @corr: buffer to store correction bitmask on eras_pos |
317 | * | 317 | * |
318 | * Each field in the data array contains up to symbol size bits of valid data. | 318 | * Each field in the data array contains up to symbol size bits of valid data. |
319 | */ | 319 | */ |
320 | int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len, | 320 | int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len, |
321 | uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, | 321 | uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, |
322 | uint16_t *corr) | 322 | uint16_t *corr) |
323 | { | 323 | { |
324 | #include "decode_rs.c" | 324 | #include "decode_rs.c" |